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)...) }