summaryrefslogtreecommitdiff
path: root/internal/lsp/handlers_completion.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-06 10:25:36 +0300
committerPaul Buetow <paul@buetow.org>2025-09-06 10:25:36 +0300
commit5be9532cfa630f4aacd8d879c3e4f5cc316da0fa (patch)
tree0a901680fccd1e2703ffdbd9284ccff932be1d67 /internal/lsp/handlers_completion.go
parent70f1d0e78c57dfa5beae779b3d392b6e6fa44c14 (diff)
feat(lsp): configurable inline/chat triggers; switch inline markers to >text>/>>text>; update docs and example config; tests updated to new triggers and raise LSP coverage to >=85%; chore: remove semicolon legacy; chore(mage): auto-refresh coverage daily if docs/coverage.out is older than 24h
Diffstat (limited to 'internal/lsp/handlers_completion.go')
-rw-r--r--internal/lsp/handlers_completion.go51
1 files changed, 28 insertions, 23 deletions
diff --git a/internal/lsp/handlers_completion.go b/internal/lsp/handlers_completion.go
index 576fc3d..036e591 100644
--- a/internal/lsp/handlers_completion.go
+++ b/internal/lsp/handlers_completion.go
@@ -93,10 +93,10 @@ func (s *Server) tryLLMCompletion(p CompletionParams, above, current, below, fun
logging.AnsiGreen, logging.PreviewForLog(cleaned), logging.AnsiBase)
return s.makeCompletionItems(cleaned, inParams, current, p, docStr), true
}
- if (isBareDoubleSemicolon(current) || isBareDoubleSemicolon(below)) && !manualInvoke {
- logging.Logf("lsp ", "%scompletion skip=empty-double-semicolon line=%d char=%d current=%q%s", logging.AnsiYellow, p.Position.Line, p.Position.Character, trimLen(current), logging.AnsiBase)
- return []CompletionItem{}, true
- }
+ if (isBareDoubleOpen(current) || isBareDoubleOpen(below)) {
+ logging.Logf("lsp ", "%scompletion skip=empty-double-semicolon line=%d char=%d current=%q%s", logging.AnsiYellow, p.Position.Line, p.Position.Character, trimLen(current), logging.AnsiBase)
+ return []CompletionItem{}, true
+ }
if !inParams && !s.prefixHeuristicAllows(inlinePrompt, current, p, manualInvoke) {
logging.Logf("lsp ", "%scompletion skip=short-prefix line=%d char=%d current=%q%s", logging.AnsiYellow, p.Position.Line, p.Position.Character, trimLen(current), logging.AnsiBase)
@@ -163,14 +163,19 @@ func parseManualInvoke(ctx any) bool {
// shouldSuppressForChatTriggerEOL returns true when a chat trigger like ">" follows ?, !, :, or ; at EOL.
func (s *Server) shouldSuppressForChatTriggerEOL(current string, p CompletionParams) bool {
- if t := strings.TrimRight(current, " \t"); len(t) >= 2 && t[len(t)-1] == '>' {
- prev := t[len(t)-2]
- if prev == '?' || prev == '!' || prev == ':' || prev == ';' {
- logging.Logf("lsp ", "completion skip=chat-trigger-eol uri=%s line=%d", p.TextDocument.URI, p.Position.Line)
- return true
- }
- }
- return false
+ t := strings.TrimRight(current, " \t")
+ if s.chatSuffix == "" { return false }
+ if strings.HasSuffix(t, s.chatSuffix) {
+ if len(t) < len(s.chatSuffix)+1 { return false }
+ prev := string(t[len(t)-len(s.chatSuffix)-1])
+ for _, pf := range s.chatPrefixes {
+ if prev == pf {
+ logging.Logf("lsp ", "completion skip=chat-trigger-eol uri=%s line=%d", p.TextDocument.URI, p.Position.Line)
+ return true
+ }
+ }
+ }
+ return false
}
// prefixHeuristicAllows applies minimal prefix rules unless inlinePrompt or structural triggers apply.
@@ -244,12 +249,12 @@ func (s *Server) tryProviderNativeCompletion(current string, p CompletionParams,
if cleaned != "" {
cleaned = stripDuplicateGeneralPrefix(current[:p.Position.Character], cleaned)
}
- if cleaned != "" && hasDoubleSemicolonTrigger(current) {
- indent := leadingIndent(current)
- if indent != "" {
- cleaned = applyIndent(indent, cleaned)
- }
- }
+ if cleaned != "" && hasDoubleOpenTrigger(current) {
+ indent := leadingIndent(current)
+ if indent != "" {
+ cleaned = applyIndent(indent, cleaned)
+ }
+ }
if strings.TrimSpace(cleaned) != "" {
key := s.completionCacheKey(p, above, current, below, funcCtx, inParams, hasExtra, extraText)
s.completionCachePut(key, cleaned)
@@ -354,10 +359,10 @@ func (s *Server) postProcessCompletion(text string, leftOfCursor string, current
if cleaned != "" {
cleaned = stripDuplicateGeneralPrefix(leftOfCursor, cleaned)
}
- if cleaned != "" && hasDoubleSemicolonTrigger(currentLine) {
- if indent := leadingIndent(currentLine); indent != "" {
- cleaned = applyIndent(indent, cleaned)
- }
- }
+ if cleaned != "" && hasDoubleOpenTrigger(currentLine) {
+ if indent := leadingIndent(currentLine); indent != "" {
+ cleaned = applyIndent(indent, cleaned)
+ }
+ }
return cleaned
}