diff options
| author | Paul Buetow <paul@buetow.org> | 2025-09-06 10:56:27 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-09-06 10:56:27 +0300 |
| commit | 320de746f7a2985b60c8564a0e65bdf231e840b7 (patch) | |
| tree | e70bcf50813dba411afa2934e774383124bbc99e /internal/lsp/server.go | |
| parent | 06247527d5170f329b454b42f59a3e4434ab1f4b (diff) | |
use gofumpt
Diffstat (limited to 'internal/lsp/server.go')
| -rw-r--r-- | internal/lsp/server.go | 163 |
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 |
