summaryrefslogtreecommitdiff
path: root/internal/lsp/server.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-06 10:56:27 +0300
committerPaul Buetow <paul@buetow.org>2025-09-06 10:56:27 +0300
commit320de746f7a2985b60c8564a0e65bdf231e840b7 (patch)
treee70bcf50813dba411afa2934e774383124bbc99e /internal/lsp/server.go
parent06247527d5170f329b454b42f59a3e4434ab1f4b (diff)
use gofumpt
Diffstat (limited to 'internal/lsp/server.go')
-rw-r--r--internal/lsp/server.go163
1 files changed, 94 insertions, 69 deletions
diff --git a/internal/lsp/server.go b/internal/lsp/server.go
index e040d08..fa4467b 100644
--- a/internal/lsp/server.go
+++ b/internal/lsp/server.go
@@ -2,15 +2,16 @@
package lsp
import (
- "bufio"
- "encoding/json"
- "codeberg.org/snonux/hexai/internal/llm"
- "codeberg.org/snonux/hexai/internal/logging"
- "io"
- "log"
- "strings"
- "sync"
- "time"
+ "bufio"
+ "encoding/json"
+ "io"
+ "log"
+ "strings"
+ "sync"
+ "time"
+
+ "codeberg.org/snonux/hexai/internal/llm"
+ "codeberg.org/snonux/hexai/internal/logging"
)
// Server implements a minimal LSP over stdio.
@@ -27,8 +28,8 @@ type Server struct {
maxTokens int
contextMode string
windowLines int
- maxContextTokens int
- triggerChars []string
+ maxContextTokens int
+ triggerChars []string
// If set, used as the LSP coding temperature for all LLM calls
codingTemperature *float64
// LLM request stats
@@ -40,46 +41,46 @@ type Server struct {
// Small LRU cache for recent code completion outputs (keyed by context)
compCache map[string]string
compCacheOrder []string // most-recent at end; cap ~10
- // Outgoing JSON-RPC id counter for server-initiated requests
- nextID int64
+ // Outgoing JSON-RPC id counter for server-initiated requests
+ nextID int64
// Minimum identifier chars required for manual invoke to bypass prefix checks
manualInvokeMinPrefix int
- // Debounce and throttle settings
- completionDebounce time.Duration
- throttleInterval time.Duration
- lastLLMCall time.Time
+ // Debounce and throttle settings
+ completionDebounce time.Duration
+ throttleInterval time.Duration
+ lastLLMCall time.Time
- // Dispatch table for JSON-RPC methods → handler functions
- handlers map[string]func(Request)
+ // Dispatch table for JSON-RPC methods → handler functions
+ handlers map[string]func(Request)
- // Configurable trigger characters
- inlineOpen string
- inlineClose string
- chatSuffix string
- chatPrefixes []string
+ // Configurable trigger characters
+ inlineOpen string
+ inlineClose string
+ chatSuffix string
+ chatPrefixes []string
}
// ServerOptions collects configuration for NewServer to avoid long parameter lists.
type ServerOptions struct {
- LogContext bool
- MaxTokens int
- ContextMode string
- WindowLines int
- MaxContextTokens int
+ LogContext bool
+ MaxTokens int
+ ContextMode string
+ WindowLines int
+ MaxContextTokens int
- Client llm.Client
- TriggerCharacters []string
- CodingTemperature *float64
- ManualInvokeMinPrefix int
- CompletionDebounceMs int
- CompletionThrottleMs int
+ Client llm.Client
+ TriggerCharacters []string
+ CodingTemperature *float64
+ ManualInvokeMinPrefix int
+ CompletionDebounceMs int
+ CompletionThrottleMs int
- // Inline/chat triggers
- InlineOpen string
- InlineClose string
- ChatSuffix string
- ChatPrefixes []string
+ // Inline/chat triggers
+ InlineOpen string
+ InlineClose string
+ ChatSuffix string
+ ChatPrefixes []string
}
func NewServer(r io.Reader, w io.Writer, logger *log.Logger, opts ServerOptions) *Server {
@@ -113,38 +114,62 @@ func NewServer(r io.Reader, w io.Writer, logger *log.Logger, opts ServerOptions)
} else {
s.triggerChars = append([]string{}, opts.TriggerCharacters...)
}
- s.codingTemperature = opts.CodingTemperature
- s.compCache = make(map[string]string)
- s.manualInvokeMinPrefix = opts.ManualInvokeMinPrefix
- if opts.CompletionDebounceMs > 0 {
- s.completionDebounce = time.Duration(opts.CompletionDebounceMs) * time.Millisecond
- }
- if opts.CompletionThrottleMs > 0 {
- s.throttleInterval = time.Duration(opts.CompletionThrottleMs) * time.Millisecond
- }
- // Trigger character config (with sane defaults if missing)
- if strings.TrimSpace(opts.InlineOpen) == "" { s.inlineOpen = ">" } else { s.inlineOpen = opts.InlineOpen }
- if strings.TrimSpace(opts.InlineClose) == "" { s.inlineClose = ">" } else { s.inlineClose = opts.InlineClose }
- if strings.TrimSpace(opts.ChatSuffix) == "" { s.chatSuffix = ">" } else { s.chatSuffix = opts.ChatSuffix }
- if len(opts.ChatPrefixes) == 0 { s.chatPrefixes = []string{"?","!",":",";"} } else { s.chatPrefixes = append([]string{}, opts.ChatPrefixes...) }
+ s.codingTemperature = opts.CodingTemperature
+ s.compCache = make(map[string]string)
+ s.manualInvokeMinPrefix = opts.ManualInvokeMinPrefix
+ if opts.CompletionDebounceMs > 0 {
+ s.completionDebounce = time.Duration(opts.CompletionDebounceMs) * time.Millisecond
+ }
+ if opts.CompletionThrottleMs > 0 {
+ s.throttleInterval = time.Duration(opts.CompletionThrottleMs) * time.Millisecond
+ }
+ // Trigger character config (with sane defaults if missing)
+ if strings.TrimSpace(opts.InlineOpen) == "" {
+ s.inlineOpen = ">"
+ } else {
+ s.inlineOpen = opts.InlineOpen
+ }
+ if strings.TrimSpace(opts.InlineClose) == "" {
+ s.inlineClose = ">"
+ } else {
+ s.inlineClose = opts.InlineClose
+ }
+ if strings.TrimSpace(opts.ChatSuffix) == "" {
+ s.chatSuffix = ">"
+ } else {
+ s.chatSuffix = opts.ChatSuffix
+ }
+ if len(opts.ChatPrefixes) == 0 {
+ s.chatPrefixes = []string{"?", "!", ":", ";"}
+ } else {
+ s.chatPrefixes = append([]string{}, opts.ChatPrefixes...)
+ }
- // Assign package-level inline trigger chars for free helper functions
- if s.inlineOpen != "" { inlineOpenChar = s.inlineOpen[0] }
- if s.inlineClose != "" { inlineCloseChar = s.inlineClose[0] }
- if s.chatSuffix != "" { chatSuffixChar = s.chatSuffix[0] }
- if len(s.chatPrefixes) > 0 { chatPrefixSingles = append([]string{}, s.chatPrefixes...) }
+ // Assign package-level inline trigger chars for free helper functions
+ if s.inlineOpen != "" {
+ inlineOpenChar = s.inlineOpen[0]
+ }
+ if s.inlineClose != "" {
+ inlineCloseChar = s.inlineClose[0]
+ }
+ if s.chatSuffix != "" {
+ chatSuffixChar = s.chatSuffix[0]
+ }
+ if len(s.chatPrefixes) > 0 {
+ chatPrefixSingles = append([]string{}, s.chatPrefixes...)
+ }
// Initialize dispatch table
s.handlers = map[string]func(Request){
- "initialize": s.handleInitialize,
- "initialized": func(_ Request) { s.handleInitialized() },
- "shutdown": s.handleShutdown,
- "exit": func(_ Request) { s.handleExit() },
- "textDocument/didOpen": s.handleDidOpen,
- "textDocument/didChange": s.handleDidChange,
- "textDocument/didClose": s.handleDidClose,
- "textDocument/completion": s.handleCompletion,
- "textDocument/codeAction": s.handleCodeAction,
- "codeAction/resolve": s.handleCodeActionResolve,
+ "initialize": s.handleInitialize,
+ "initialized": func(_ Request) { s.handleInitialized() },
+ "shutdown": s.handleShutdown,
+ "exit": func(_ Request) { s.handleExit() },
+ "textDocument/didOpen": s.handleDidOpen,
+ "textDocument/didChange": s.handleDidChange,
+ "textDocument/didClose": s.handleDidClose,
+ "textDocument/completion": s.handleCompletion,
+ "textDocument/codeAction": s.handleCodeAction,
+ "codeAction/resolve": s.handleCodeActionResolve,
"workspace/executeCommand": s.handleExecuteCommand,
}
return s