1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
package editor
import "github.com/charmbracelet/lipgloss"
// SetGrammar sets whether grammar checking is enabled for the session. Diagnostics
// keep arriving from the app regardless; this only gates their rendering.
func (e *Editor) SetGrammar(on bool) { e.grammarOn = on; e.invalidate() }
// ToggleGrammar flips grammar checking and returns the new state.
func (e *Editor) ToggleGrammar() bool { e.grammarOn = !e.grammarOn; e.invalidate(); return e.grammarOn }
// GrammarEnabled reports the user's session toggle for grammar checking.
func (e *Editor) GrammarEnabled() bool { return e.grammarOn }
// SetGrammarDiags replaces the grammar-underline ranges, keyed by logical line
// (each range is a [start,end) rune column pair). Callers pass whatever Harper
// last reported for the current buffer; an empty map clears all grammar
// underlines. The visual model is invalidated so the change shows on next render.
func (e *Editor) SetGrammarDiags(byLine map[int][][2]int) {
e.grammarDiags = byLine
e.invalidate()
}
// grammarActive reports whether grammar underlines should render: enabled and the
// buffer is prose (grammar, like spellcheck, skips code files).
func (e *Editor) grammarActive() bool {
return e.grammarOn && e.codeFile == "" && len(e.grammarDiags) > 0
}
// grammarPass overlays a green undercurl on each grammar range, layered after
// spellPass so a word already flagged red (misspelled) keeps its red underline โ
// spelling outranks grammar on the same text.
func (e *Editor) grammarPass(all [][]Span) [][]Span {
for li := range all {
ranges := e.grammarDiags[li]
if len(ranges) == 0 {
continue
}
spans := all[li]
for _, r := range ranges {
spans = overlayUndercurl(spans, r[0], r[1], e.theme.Grammar)
}
all[li] = spans
}
return all
}
// overlayUndercurl marks the rune range [a,b) of spans with a curly underline in
// color, splitting spans at the range boundaries (like overlaySelection). Only
// prose spans not already Wavy are marked, so grammar green never repaints a
// misspelling's red nor underlines markup punctuation.
func overlayUndercurl(spans []Span, a, b int, color lipgloss.Color) []Span {
total := 0
for _, sp := range spans {
total += len([]rune(sp.Text))
}
if a < 0 {
a = 0
}
if b > total {
b = total
}
if a >= b {
return spans
}
out := sliceSpans(spans, 0, a)
mid := sliceSpans(spans, a, b)
for i := range mid {
if mid[i].Prose && !mid[i].Wavy {
mid[i].Wavy = true
mid[i].UnderColor = color
}
}
out = append(out, mid...)
return append(out, sliceSpans(spans, b, total)...)
}
|