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
77
78
79
80
81
82
83
84
|
// Summary: Builds additional context snippets based on configured mode and truncates text by token heuristic.
// Not yet reviewed by a human
package lsp
import (
"hexai/internal/logging"
"strings"
)
// buildAdditionalContext builds extra context messages based on the configured mode.
// Modes:
// - minimal: no extra context
// - window: include a window of lines around the cursor
// - 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
}
}
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)
}
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)
}
// 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]
}
|