summaryrefslogtreecommitdiffstats
path: root/cnmfmt/cnmfmt.go
diff options
context:
space:
mode:
Diffstat (limited to 'cnmfmt/cnmfmt.go')
-rw-r--r--cnmfmt/cnmfmt.go136
1 files changed, 76 insertions, 60 deletions
diff --git a/cnmfmt/cnmfmt.go b/cnmfmt/cnmfmt.go
index fa2ec65..1e5b6ee 100644
--- a/cnmfmt/cnmfmt.go
+++ b/cnmfmt/cnmfmt.go
@@ -9,6 +9,10 @@ import (
"contnet.org/lib/cnm-go"
)
+const (
+ numFormats = 5 // emphasized, alternate, code, quote, link
+)
+
func init() {
cnm.RegisterTextContentParser("fmt", parseTextFmt)
}
@@ -37,7 +41,7 @@ func ParseParagraph(s string) Text {
}
switch r {
- case '*', '/', '_', '`', '@':
+ case '*', '_', '`', '"', '@':
handleTag(r, &last, &t, &format, &buf, &url)
case '\\':
@@ -138,13 +142,13 @@ func handleTag(r rune, last *rune, txt *Text, format *Format, buf *bytes.Buffer,
buf.Reset()
switch r {
case '*':
- format.Bold = !format.Bold
- case '/':
- format.Italic = !format.Italic
+ format.Emphasized = !format.Emphasized
case '_':
- format.Underline = !format.Underline
+ format.Alternate = !format.Alternate
case '`':
- format.Monospace = !format.Monospace
+ format.Code = !format.Code
+ case '"':
+ format.Quote = !format.Quote
case '@':
format.Link = ""
*url = !*url
@@ -152,7 +156,7 @@ func handleTag(r rune, last *rune, txt *Text, format *Format, buf *bytes.Buffer,
*last = -1
} else {
switch *last {
- case '*', '/', '_', '`', '@':
+ case '*', '_', '`', '"', '@':
buf.WriteRune(*last)
}
*last = r
@@ -161,7 +165,7 @@ func handleTag(r rune, last *rune, txt *Text, format *Format, buf *bytes.Buffer,
// WriteIndent writes the formatted text indented by n tabs.
func (t Text) WriteIndent(w io.Writer, n int) error {
- var state [5]byte // bold, italic, underline, monospace, link
+ var state [numFormats]byte
si := 0
format := Format{}
spans := EscapeSpans(t.Spans)
@@ -171,17 +175,17 @@ func (t Text) WriteIndent(w io.Writer, n int) error {
for _, f := range order {
switch f {
case '*':
- format.Bold = !format.Bold
+ format.Emphasized = !format.Emphasized
line = append(line, "**")
- case '/':
- format.Italic = !format.Italic
- line = append(line, "//")
case '_':
- format.Underline = !format.Underline
+ format.Alternate = !format.Alternate
line = append(line, "__")
case '`':
- format.Monospace = !format.Monospace
+ format.Code = !format.Code
line = append(line, "``")
+ case '"':
+ format.Quote = !format.Quote
+ line = append(line, "\"\"")
case '@':
if format.Link != "" {
line = append(line, "@@")
@@ -208,40 +212,41 @@ func tagOrder(state []byte, old, new Format) []byte {
ldiff = "1"
}
diff := Format{
- Bold: old.Bold != new.Bold,
- Italic: old.Italic != new.Italic,
- Underline: old.Underline != new.Underline,
- Monospace: old.Monospace != new.Monospace,
- Link: ldiff,
+ Emphasized: old.Emphasized != new.Emphasized,
+ Alternate: old.Alternate != new.Alternate,
+ Code: old.Code != new.Code,
+ Quote: old.Quote != new.Quote,
+ Link: ldiff,
}
- var order [5]byte
+ // close formats
+ var order [numFormats]byte
oi := 0
for i := len(state) - 1; i >= 0; i-- {
switch state[i] {
case '*':
- if diff.Bold {
+ if diff.Emphasized {
order[oi] = '*'
oi++
- diff.Bold = false
- }
- case '/':
- if diff.Italic {
- order[oi] = '/'
- oi++
- diff.Italic = false
+ diff.Emphasized = false
}
case '_':
- if diff.Underline {
+ if diff.Alternate {
order[oi] = '_'
oi++
- diff.Underline = false
+ diff.Alternate = false
}
case '`':
- if diff.Monospace {
+ if diff.Code {
order[oi] = '`'
oi++
- diff.Monospace = false
+ diff.Code = false
+ }
+ case '"':
+ if diff.Quote {
+ order[oi] = '"'
+ oi++
+ diff.Quote = false
}
case '@':
if diff.Link != "" {
@@ -252,22 +257,23 @@ func tagOrder(state []byte, old, new Format) []byte {
}
}
- if diff.Bold {
+ // open formats
+ if diff.Emphasized {
order[oi] = '*'
oi++
}
- if diff.Italic {
- order[oi] = '/'
- oi++
- }
- if diff.Underline {
+ if diff.Alternate {
order[oi] = '_'
oi++
}
- if diff.Monospace {
+ if diff.Code {
order[oi] = '`'
oi++
}
+ if diff.Quote {
+ order[oi] = '"'
+ oi++
+ }
if diff.Link != "" {
order[oi] = '@'
oi++
@@ -277,25 +283,29 @@ func tagOrder(state []byte, old, new Format) []byte {
}
func cleanupTags(state []byte, order []byte, format Format) int {
- var newState [10]byte
- copy(newState[:5], state)
- copy(newState[5:], order)
+ var newState [2 * numFormats]byte
+
+ // take care of both state and order
+ copy(newState[:numFormats], state)
+ copy(newState[numFormats:], order)
+
+ // remove formats that are off
for i := range newState {
switch newState[i] {
case '*':
- if !format.Bold {
- newState[i] = 0
- }
- case '/':
- if !format.Italic {
+ if !format.Emphasized {
newState[i] = 0
}
case '_':
- if !format.Underline {
+ if !format.Alternate {
newState[i] = 0
}
case '`':
- if !format.Monospace {
+ if !format.Code {
+ newState[i] = 0
+ }
+ case '"':
+ if !format.Quote {
newState[i] = 0
}
case '@':
@@ -304,6 +314,7 @@ func cleanupTags(state []byte, order []byte, format Format) int {
}
}
}
+
si := 0
for _, f := range newState {
if f > 0 {
@@ -311,6 +322,12 @@ func cleanupTags(state []byte, order []byte, format Format) int {
si++
}
}
+
+ // clean up unused state
+ for i := si; i < numFormats; i++ {
+ state[i] = 0
+ }
+
return si
}
@@ -325,17 +342,17 @@ type Span struct {
// Format represents a state of CNMfmt formatting.
type Format struct {
- // Bold text.
- Bold bool
+ // Emphasized text.
+ Emphasized bool
- // Italic text.
- Italic bool
+ // Text in an alternate voice.
+ Alternate bool
- // Underlined text.
- Underline bool
+ // Text is code.
+ Code bool
- // Monospaced text.
- Monospace bool
+ // Quoted text.
+ Quote bool
// Hyperlink URL (if non-empty).
Link string
@@ -385,9 +402,9 @@ func EscapeSpans(spans []Span) []Span {
var escapeReplacer = strings.NewReplacer(
`*`, `\*`,
- `/`, `\/`,
`_`, `\_`,
"`", "\\`",
+ `"`, `\"`,
`@`, `\@`,
)
@@ -402,11 +419,10 @@ func Unescape(s string) string {
}
var unescapeReplacer = strings.NewReplacer(
- `\\`, `\\`,
`\*`, `*`,
- `\/`, `/`,
`\_`, `_`,
"\\`", "`",
+ `\"`, `"`,
`\@`, `@`,
)