turbo-editors/turbo-corepublic Fork 0
v1.0.1
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

markdown_inline.go · 110 lines · 2.7 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 16h ago1package syntax
2
3// The inline half of the Markdown scanner: what can appear inside a line of
4// prose, once the line's own shape has been decided by markdown.go.
5
6// scanMarkdownInline colours what can appear inside a line of prose.
7func scanMarkdownInline(s *LineScanner) {
8 for !s.AtEnd() {
9 switch {
10 case s.Peek(0) == '`':
11 takeCodeSpan(s)
12 case s.Peek(0) == '!' && s.Peek(1) == '[':
13 takeLink(s, 1)
14 case s.Peek(0) == '[':
15 takeLink(s, 0)
16 case isEmphasisMarker(s.Peek(0)):
17 takeEmphasis(s)
18 default:
19 s.pos++
20 }
21 }
22}
23
24// isEmphasisMarker reports whether a rune can begin bold or italic text.
25func isEmphasisMarker(r rune) bool { return r == '*' || r == '_' }
26
27// takeCodeSpan colours `code`, or the lone backtick when nothing closes it.
28func takeCodeSpan(s *LineScanner) {
29 start := s.pos
30 for at := s.pos + 1; at < len(s.line); at++ {
31 if s.line[at] == '`' {
32 s.pos = at + 1
33 s.Emit(start, s.pos, ClassString)
34 return
35 }
36 }
37 s.pos++
38}
39
40// takeEmphasis colours *italic*, **bold** and their underscore spellings.
41//
42// The run of markers at the start has to be matched by the same run at the
43// end, so that **bold** is one span rather than an empty italic followed by
44// stray text.
45func takeEmphasis(s *LineScanner) {
46 marker := s.Peek(0)
47 run := 0
48 for s.Peek(run) == marker {
49 run++
50 }
51
52 if end := findRun(s.line, s.pos+run, marker, run); end > 0 {
53 start := s.pos
54 s.pos = end + run
55 s.Emit(start, s.pos, ClassEmphasis)
56 return
57 }
58 s.pos += run
59}
60
61// findRun returns where a run of exactly n markers starts at or after from, or
62// -1 when the line holds none.
63func findRun(line []rune, from int, marker rune, n int) int {
64 for at := from; at+n <= len(line); at++ {
65 if line[at] != marker {
66 continue
67 }
68 count := 0
69 for at+count < len(line) && line[at+count] == marker {
70 count++
71 }
72 if count == n {
73 return at
74 }
75 at += count - 1
76 }
77 return -1
78}
79
80// takeLink colours [text](target) and its image form ![alt](src).
81//
82// Both halves are one span: a link is one thing to the eye, and splitting the
83// text from the target would put two colours on something read as a unit.
84func takeLink(s *LineScanner, offset int) {
85 closeBracket := indexFrom(s.line, s.pos+offset+1, ']')
86 if closeBracket < 0 || closeBracket+1 >= len(s.line) || s.line[closeBracket+1] != '(' {
87 s.pos += offset + 1
88 return
89 }
90
91 closeParen := indexFrom(s.line, closeBracket+2, ')')
92 if closeParen < 0 {
93 s.pos += offset + 1
94 return
95 }
96
97 start := s.pos
98 s.pos = closeParen + 1
99 s.Emit(start, s.pos, ClassLink)
100}
101
102// indexFrom returns where a rune first appears at or after an offset, or -1.
103func indexFrom(line []rune, from int, want rune) int {
104 for at := max(from, 0); at < len(line); at++ {
105 if line[at] == want {
106 return at
107 }
108 }
109 return -1
110}