diff options
| author | Paul Buetow <paul@buetow.org> | 2025-08-17 00:06:00 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-08-17 00:06:00 +0300 |
| commit | dc383b4faef881f3bb22816f42c53a79236a4152 (patch) | |
| tree | 7c6a48487fc1d51fed72ea5d15618d133132cdaa /internal/lsp/context.go | |
| parent | 6a1d48036105e92193aef11a15a77a569eeb1562 (diff) | |
lsp/config: make completion trigger characters configurable
- Add trigger_characters to JSON config and ServerOptions
- Store on server and advertise in initialize
- Update README and example config
- Preserve previous defaults when unset
Diffstat (limited to 'internal/lsp/context.go')
| -rw-r--r-- | internal/lsp/context.go | 116 |
1 files changed, 58 insertions, 58 deletions
diff --git a/internal/lsp/context.go b/internal/lsp/context.go index 8f345df..e746058 100644 --- a/internal/lsp/context.go +++ b/internal/lsp/context.go @@ -1,8 +1,8 @@ package lsp import ( - "strings" - "hexai/internal/logging" + "hexai/internal/logging" + "strings" ) // buildAdditionalContext builds extra context messages based on the configured mode. @@ -12,71 +12,71 @@ import ( // - file-on-new-func: include full file only when defining a new function // - always-full: always include the full file func (s *Server) buildAdditionalContext(newFunc bool, uri string, pos Position) (string, bool) { - mode := s.contextMode - switch mode { - case "minimal": - return "", false - case "window": - return s.windowContext(uri, pos), true - case "file-on-new-func": - if newFunc { - return s.fullFileContext(uri), true - } - return "", false - case "always-full": - return s.fullFileContext(uri), true - default: - // fallback to minimal if unknown - return "", false - } + mode := s.contextMode + switch mode { + case "minimal": + return "", false + case "window": + return s.windowContext(uri, pos), true + case "file-on-new-func": + if newFunc { + return s.fullFileContext(uri), true + } + return "", false + case "always-full": + return s.fullFileContext(uri), true + default: + // fallback to minimal if unknown + return "", false + } } func (s *Server) windowContext(uri string, pos Position) string { - d := s.getDocument(uri) - if d == nil || len(d.lines) == 0 { - logging.Logf("lsp ", "context: window requested but document not open; skipping uri=%s", uri) - return "" - } - n := len(d.lines) - half := s.windowLines / 2 - start := pos.Line - half - if start < 0 { - start = 0 - } - end := pos.Line + half + 1 - if end > n { - end = n - } - text := strings.Join(d.lines[start:end], "\n") - return truncateToApproxTokens(text, s.maxContextTokens) + d := s.getDocument(uri) + if d == nil || len(d.lines) == 0 { + logging.Logf("lsp ", "context: window requested but document not open; skipping uri=%s", uri) + return "" + } + n := len(d.lines) + half := s.windowLines / 2 + start := pos.Line - half + if start < 0 { + start = 0 + } + end := pos.Line + half + 1 + if end > n { + end = n + } + text := strings.Join(d.lines[start:end], "\n") + return truncateToApproxTokens(text, s.maxContextTokens) } func (s *Server) fullFileContext(uri string) string { - d := s.getDocument(uri) - if d == nil { - logging.Logf("lsp ", "context: full-file requested but document not open; skipping uri=%s", uri) - return "" - } - return truncateToApproxTokens(d.text, s.maxContextTokens) + d := s.getDocument(uri) + if d == nil { + logging.Logf("lsp ", "context: full-file requested but document not open; skipping uri=%s", uri) + return "" + } + return truncateToApproxTokens(d.text, s.maxContextTokens) } // truncateToApproxTokens naively truncates the input to fit approx N tokens. // Uses 4 chars/token heuristic for speed and determinism. func truncateToApproxTokens(text string, maxTokens int) string { - if maxTokens <= 0 { - return "" - } - maxChars := maxTokens * 4 - if len(text) <= maxChars { - return text - } - // try to cut on a line boundary near maxChars - cut := maxChars - if cut > len(text) { - cut = len(text) - } - if i := strings.LastIndex(text[:cut], "\n"); i > 0 { - cut = i - } - return text[:cut] + if maxTokens <= 0 { + return "" + } + maxChars := maxTokens * 4 + if len(text) <= maxChars { + return text + } + // try to cut on a line boundary near maxChars + cut := maxChars + if cut > len(text) { + cut = len(text) + } + if i := strings.LastIndex(text[:cut], "\n"); i > 0 { + cut = i + } + return text[:cut] } |
