โ– humdrum codex / glint v1.1.2
license AGPL-3.0
2.5 KB raw
 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)...)
}