diff --git a/.golangci.yml b/.golangci.yml index 9cf93d4da8b73491c4ea2f967af527e073c41d73..6c235c71adb9bb68e2f41a3bfafbfd248abcba12 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,6 +19,7 @@ linters: # - revive - rowserrcheck - sqlclosecheck + - staticcheck - tparallel # - unconvert # - unparam @@ -27,7 +28,6 @@ linters: disable: - errcheck - ineffassign - - staticcheck - unused exclusions: generated: lax diff --git a/internal/app/app.go b/internal/app/app.go index 8a7d5ba5396a5a38c6df52b9ced3afc42da91059..f15b3361fb1d8117dc8cdac2a24ba66e1fcee69b 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -93,7 +93,7 @@ func New(ctx context.Context, conn *sql.DB, cfg *config.Config) (*App, error) { } // RunNonInteractive handles the execution flow when a prompt is provided via CLI flag. -func (a *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool) error { +func (app *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool) error { slog.Info("Running in non-interactive mode") ctx, cancel := context.WithCancel(ctx) @@ -125,21 +125,21 @@ func (a *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool) } title := titlePrefix + titleSuffix - sess, err := a.Sessions.Create(ctx, title) + sess, err := app.Sessions.Create(ctx, title) if err != nil { return fmt.Errorf("failed to create session for non-interactive mode: %w", err) } slog.Info("Created session for non-interactive run", "session_id", sess.ID) // Automatically approve all permission requests for this non-interactive session - a.Permissions.AutoApproveSession(sess.ID) + app.Permissions.AutoApproveSession(sess.ID) - done, err := a.CoderAgent.Run(ctx, sess.ID, prompt) + done, err := app.CoderAgent.Run(ctx, sess.ID, prompt) if err != nil { return fmt.Errorf("failed to start agent processing stream: %w", err) } - messageEvents := a.Messages.Subscribe(ctx) + messageEvents := app.Messages.Subscribe(ctx) readBts := 0 for { diff --git a/internal/config/load.go b/internal/config/load.go index 81cb4398e5b3a7a2147ab5388b37088788ea041b..e056847aeeda476e819439384a16e0e237b067e1 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -87,16 +87,16 @@ func Load(workingDir string, debug bool) (*Config, error) { return cfg, nil } -func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, knownProviders []provider.Provider) error { +func (c *Config) configureProviders(env env.Env, resolver VariableResolver, knownProviders []provider.Provider) error { knownProviderNames := make(map[string]bool) for _, p := range knownProviders { knownProviderNames[string(p.ID)] = true - config, configExists := cfg.Providers[string(p.ID)] + config, configExists := c.Providers[string(p.ID)] // if the user configured a known provider we need to allow it to override a couple of parameters if configExists { if config.Disable { slog.Debug("Skipping provider due to disable flag", "provider", p.ID) - delete(cfg.Providers, string(p.ID)) + delete(c.Providers, string(p.ID)) continue } if config.BaseURL != "" { @@ -151,7 +151,7 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn if !hasVertexCredentials(env) { if configExists { slog.Warn("Skipping Vertex AI provider due to missing credentials") - delete(cfg.Providers, string(p.ID)) + delete(c.Providers, string(p.ID)) } continue } @@ -161,7 +161,7 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn if !hasAWSCredentials(env) { if configExists { slog.Warn("Skipping Bedrock provider due to missing AWS credentials") - delete(cfg.Providers, string(p.ID)) + delete(c.Providers, string(p.ID)) } continue } @@ -176,16 +176,16 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn if v == "" || err != nil { if configExists { slog.Warn("Skipping provider due to missing API key", "provider", p.ID) - delete(cfg.Providers, string(p.ID)) + delete(c.Providers, string(p.ID)) } continue } } - cfg.Providers[string(p.ID)] = prepared + c.Providers[string(p.ID)] = prepared } // validate the custom providers - for id, providerConfig := range cfg.Providers { + for id, providerConfig := range c.Providers { if knownProviderNames[id] { continue } @@ -202,7 +202,7 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn if providerConfig.Disable { slog.Debug("Skipping custom provider due to disable flag", "provider", id) - delete(cfg.Providers, id) + delete(c.Providers, id) continue } if providerConfig.APIKey == "" { @@ -210,17 +210,17 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn } if providerConfig.BaseURL == "" { slog.Warn("Skipping custom provider due to missing API endpoint", "provider", id) - delete(cfg.Providers, id) + delete(c.Providers, id) continue } if len(providerConfig.Models) == 0 { slog.Warn("Skipping custom provider because the provider has no models", "provider", id) - delete(cfg.Providers, id) + delete(c.Providers, id) continue } if providerConfig.Type != provider.TypeOpenAI { slog.Warn("Skipping custom provider because the provider type is not supported", "provider", id, "type", providerConfig.Type) - delete(cfg.Providers, id) + delete(c.Providers, id) continue } @@ -231,50 +231,50 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn baseURL, err := resolver.ResolveValue(providerConfig.BaseURL) if baseURL == "" || err != nil { slog.Warn("Skipping custom provider due to missing API endpoint", "provider", id, "error", err) - delete(cfg.Providers, id) + delete(c.Providers, id) continue } - cfg.Providers[id] = providerConfig + c.Providers[id] = providerConfig } return nil } -func (cfg *Config) setDefaults(workingDir string) { - cfg.workingDir = workingDir - if cfg.Options == nil { - cfg.Options = &Options{} +func (c *Config) setDefaults(workingDir string) { + c.workingDir = workingDir + if c.Options == nil { + c.Options = &Options{} } - if cfg.Options.TUI == nil { - cfg.Options.TUI = &TUIOptions{} + if c.Options.TUI == nil { + c.Options.TUI = &TUIOptions{} } - if cfg.Options.ContextPaths == nil { - cfg.Options.ContextPaths = []string{} + if c.Options.ContextPaths == nil { + c.Options.ContextPaths = []string{} } - if cfg.Options.DataDirectory == "" { - cfg.Options.DataDirectory = filepath.Join(workingDir, defaultDataDirectory) + if c.Options.DataDirectory == "" { + c.Options.DataDirectory = filepath.Join(workingDir, defaultDataDirectory) } - if cfg.Providers == nil { - cfg.Providers = make(map[string]ProviderConfig) + if c.Providers == nil { + c.Providers = make(map[string]ProviderConfig) } - if cfg.Models == nil { - cfg.Models = make(map[SelectedModelType]SelectedModel) + if c.Models == nil { + c.Models = make(map[SelectedModelType]SelectedModel) } - if cfg.MCP == nil { - cfg.MCP = make(map[string]MCPConfig) + if c.MCP == nil { + c.MCP = make(map[string]MCPConfig) } - if cfg.LSP == nil { - cfg.LSP = make(map[string]LSPConfig) + if c.LSP == nil { + c.LSP = make(map[string]LSPConfig) } // Add the default context paths if they are not already present - cfg.Options.ContextPaths = append(defaultContextPaths, cfg.Options.ContextPaths...) - slices.Sort(cfg.Options.ContextPaths) - cfg.Options.ContextPaths = slices.Compact(cfg.Options.ContextPaths) + c.Options.ContextPaths = append(defaultContextPaths, c.Options.ContextPaths...) + slices.Sort(c.Options.ContextPaths) + c.Options.ContextPaths = slices.Compact(c.Options.ContextPaths) } -func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (largeModel SelectedModel, smallModel SelectedModel, err error) { - if len(knownProviders) == 0 && len(cfg.Providers) == 0 { +func (c *Config) defaultModelSelection(knownProviders []provider.Provider) (largeModel SelectedModel, smallModel SelectedModel, err error) { + if len(knownProviders) == 0 && len(c.Providers) == 0 { err = fmt.Errorf("no providers configured, please configure at least one provider") return } @@ -282,11 +282,11 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la // Use the first provider enabled based on the known providers order // if no provider found that is known use the first provider configured for _, p := range knownProviders { - providerConfig, ok := cfg.Providers[string(p.ID)] + providerConfig, ok := c.Providers[string(p.ID)] if !ok || providerConfig.Disable { continue } - defaultLargeModel := cfg.GetModel(string(p.ID), p.DefaultLargeModelID) + defaultLargeModel := c.GetModel(string(p.ID), p.DefaultLargeModelID) if defaultLargeModel == nil { err = fmt.Errorf("default large model %s not found for provider %s", p.DefaultLargeModelID, p.ID) return @@ -298,7 +298,7 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la ReasoningEffort: defaultLargeModel.DefaultReasoningEffort, } - defaultSmallModel := cfg.GetModel(string(p.ID), p.DefaultSmallModelID) + defaultSmallModel := c.GetModel(string(p.ID), p.DefaultSmallModelID) if defaultSmallModel == nil { err = fmt.Errorf("default small model %s not found for provider %s", p.DefaultSmallModelID, p.ID) return @@ -312,7 +312,7 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la return } - enabledProviders := cfg.EnabledProviders() + enabledProviders := c.EnabledProviders() slices.SortFunc(enabledProviders, func(a, b ProviderConfig) int { return strings.Compare(a.ID, b.ID) }) @@ -327,13 +327,13 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la err = fmt.Errorf("provider %s has no models configured", providerConfig.ID) return } - defaultLargeModel := cfg.GetModel(providerConfig.ID, providerConfig.Models[0].ID) + defaultLargeModel := c.GetModel(providerConfig.ID, providerConfig.Models[0].ID) largeModel = SelectedModel{ Provider: providerConfig.ID, Model: defaultLargeModel.ID, MaxTokens: defaultLargeModel.DefaultMaxTokens, } - defaultSmallModel := cfg.GetModel(providerConfig.ID, providerConfig.Models[0].ID) + defaultSmallModel := c.GetModel(providerConfig.ID, providerConfig.Models[0].ID) smallModel = SelectedModel{ Provider: providerConfig.ID, Model: defaultSmallModel.ID, @@ -342,14 +342,14 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la return } -func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) error { - defaultLarge, defaultSmall, err := cfg.defaultModelSelection(knownProviders) +func (c *Config) configureSelectedModels(knownProviders []provider.Provider) error { + defaultLarge, defaultSmall, err := c.defaultModelSelection(knownProviders) if err != nil { return fmt.Errorf("failed to select default models: %w", err) } large, small := defaultLarge, defaultSmall - largeModelSelected, largeModelConfigured := cfg.Models[SelectedModelTypeLarge] + largeModelSelected, largeModelConfigured := c.Models[SelectedModelTypeLarge] if largeModelConfigured { if largeModelSelected.Model != "" { large.Model = largeModelSelected.Model @@ -357,11 +357,11 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e if largeModelSelected.Provider != "" { large.Provider = largeModelSelected.Provider } - model := cfg.GetModel(large.Provider, large.Model) + model := c.GetModel(large.Provider, large.Model) if model == nil { large = defaultLarge // override the model type to large - err := cfg.UpdatePreferredModel(SelectedModelTypeLarge, large) + err := c.UpdatePreferredModel(SelectedModelTypeLarge, large) if err != nil { return fmt.Errorf("failed to update preferred large model: %w", err) } @@ -377,7 +377,7 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e large.Think = largeModelSelected.Think } } - smallModelSelected, smallModelConfigured := cfg.Models[SelectedModelTypeSmall] + smallModelSelected, smallModelConfigured := c.Models[SelectedModelTypeSmall] if smallModelConfigured { if smallModelSelected.Model != "" { small.Model = smallModelSelected.Model @@ -386,11 +386,11 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e small.Provider = smallModelSelected.Provider } - model := cfg.GetModel(small.Provider, small.Model) + model := c.GetModel(small.Provider, small.Model) if model == nil { small = defaultSmall // override the model type to small - err := cfg.UpdatePreferredModel(SelectedModelTypeSmall, small) + err := c.UpdatePreferredModel(SelectedModelTypeSmall, small) if err != nil { return fmt.Errorf("failed to update preferred small model: %w", err) } @@ -404,8 +404,8 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e small.Think = smallModelSelected.Think } } - cfg.Models[SelectedModelTypeLarge] = large - cfg.Models[SelectedModelTypeSmall] = small + c.Models[SelectedModelTypeLarge] = large + c.Models[SelectedModelTypeSmall] = small return nil } diff --git a/internal/llm/provider/gemini.go b/internal/llm/provider/gemini.go index 30da47326df114ad9d6b87f1d53712af2b463646..d2aee5090029e207ef1bdf5e0dad8e011e763267 100644 --- a/internal/llm/provider/gemini.go +++ b/internal/llm/provider/gemini.go @@ -73,7 +73,7 @@ func (g *geminiClient) convertMessages(messages []message.Message) []*genai.Cont if len(msg.ToolCalls()) > 0 { for _, call := range msg.ToolCalls() { - args, _ := parseJsonToMap(call.Input) + args, _ := parseJSONToMap(call.Input) assistantParts = append(assistantParts, &genai.Part{ FunctionCall: &genai.FunctionCall{ Name: call.Name, @@ -93,7 +93,7 @@ func (g *geminiClient) convertMessages(messages []message.Message) []*genai.Cont case message.Tool: for _, result := range msg.ToolResults() { response := map[string]any{"result": result.Content} - parsed, err := parseJsonToMap(result.Content) + parsed, err := parseJSONToMap(result.Content) if err == nil { response = parsed } @@ -468,7 +468,7 @@ func (g *geminiClient) Model() provider.Model { } // Helper functions -func parseJsonToMap(jsonStr string) (map[string]any, error) { +func parseJSONToMap(jsonStr string) (map[string]any, error) { var result map[string]any err := json.Unmarshal([]byte(jsonStr), &result) return result, err diff --git a/internal/llm/provider/openai.go b/internal/llm/provider/openai.go index 0093dd24ad77d6962780abdce84f64ba733a2df1..51baaf3a27a0596483bef18663cd2ded2ead0af9 100644 --- a/internal/llm/provider/openai.go +++ b/internal/llm/provider/openai.go @@ -463,6 +463,6 @@ func (o *openaiClient) usage(completion openai.ChatCompletion) TokenUsage { } } -func (a *openaiClient) Model() provider.Model { - return a.providerOptions.model(a.providerOptions.modelType) +func (o *openaiClient) Model() provider.Model { + return o.providerOptions.model(o.providerOptions.modelType) } diff --git a/internal/llm/tools/diagnostics.go b/internal/llm/tools/diagnostics.go index 5e0d19f9e5b3f72ea7588e4c4a15b71ae7b262d9..6d2da798a6547b11f861e8e5051d297809cbb9af 100644 --- a/internal/llm/tools/diagnostics.go +++ b/internal/llm/tools/diagnostics.go @@ -108,7 +108,7 @@ func waitForLspDiagnostics(ctx context.Context, filePath string, lsps map[string diagChan := make(chan struct{}, 1) for _, client := range lsps { - originalDiags := make(map[protocol.DocumentUri][]protocol.Diagnostic) + originalDiags := make(map[protocol.DocumentURI][]protocol.Diagnostic) maps.Copy(originalDiags, client.GetDiagnostics()) handler := func(params json.RawMessage) { @@ -148,7 +148,7 @@ func waitForLspDiagnostics(ctx context.Context, filePath string, lsps map[string } } -func hasDiagnosticsChanged(current, original map[protocol.DocumentUri][]protocol.Diagnostic) bool { +func hasDiagnosticsChanged(current, original map[protocol.DocumentURI][]protocol.Diagnostic) bool { for uri, diags := range current { origDiags, exists := original[uri] if !exists || len(diags) != len(origDiags) { diff --git a/internal/lsp/client.go b/internal/lsp/client.go index f0ace18e67e133bb5eb5b824c543cfc9fc07bab1..f7298a0d90240c020d451ace1548bef699d1b36d 100644 --- a/internal/lsp/client.go +++ b/internal/lsp/client.go @@ -42,7 +42,7 @@ type Client struct { notificationMu sync.RWMutex // Diagnostic cache - diagnostics map[protocol.DocumentUri][]protocol.Diagnostic + diagnostics map[protocol.DocumentURI][]protocol.Diagnostic diagnosticsMu sync.RWMutex // Files are currently opened by the LSP @@ -81,7 +81,7 @@ func NewClient(ctx context.Context, command string, args ...string) (*Client, er handlers: make(map[int32]chan *Message), notificationHandlers: make(map[string]NotificationHandler), serverRequestHandlers: make(map[string]ServerRequestHandler), - diagnostics: make(map[protocol.DocumentUri][]protocol.Diagnostic), + diagnostics: make(map[protocol.DocumentURI][]protocol.Diagnostic), openFiles: make(map[string]*OpenFileInfo), } @@ -449,13 +449,13 @@ func (c *Client) pingTypeScriptServer(ctx context.Context) error { // If we have any open files, try to get document symbols for one for uri := range c.openFiles { - filePath := protocol.DocumentUri(uri).Path() + filePath := protocol.DocumentURI(uri).Path() if strings.HasSuffix(filePath, ".ts") || strings.HasSuffix(filePath, ".js") || strings.HasSuffix(filePath, ".tsx") || strings.HasSuffix(filePath, ".jsx") { var symbols []protocol.DocumentSymbol err := c.Call(ctx, "textDocument/documentSymbol", protocol.DocumentSymbolParams{ TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.DocumentUri(uri), + URI: protocol.DocumentURI(uri), }, }, &symbols) if err == nil { @@ -583,7 +583,7 @@ func (c *Client) pingWithServerCapabilities(ctx context.Context) error { type OpenFileInfo struct { Version int32 - URI protocol.DocumentUri + URI protocol.DocumentURI } func (c *Client) OpenFile(ctx context.Context, filepath string) error { @@ -604,7 +604,7 @@ func (c *Client) OpenFile(ctx context.Context, filepath string) error { params := protocol.DidOpenTextDocumentParams{ TextDocument: protocol.TextDocumentItem{ - URI: protocol.DocumentUri(uri), + URI: protocol.DocumentURI(uri), LanguageID: DetectLanguageID(uri), Version: 1, Text: string(content), @@ -618,7 +618,7 @@ func (c *Client) OpenFile(ctx context.Context, filepath string) error { c.openFilesMu.Lock() c.openFiles[uri] = &OpenFileInfo{ Version: 1, - URI: protocol.DocumentUri(uri), + URI: protocol.DocumentURI(uri), } c.openFilesMu.Unlock() @@ -648,7 +648,7 @@ func (c *Client) NotifyChange(ctx context.Context, filepath string) error { params := protocol.DidChangeTextDocumentParams{ TextDocument: protocol.VersionedTextDocumentIdentifier{ TextDocumentIdentifier: protocol.TextDocumentIdentifier{ - URI: protocol.DocumentUri(uri), + URI: protocol.DocumentURI(uri), }, Version: version, }, @@ -677,7 +677,7 @@ func (c *Client) CloseFile(ctx context.Context, filepath string) error { params := protocol.DidCloseTextDocumentParams{ TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.DocumentUri(uri), + URI: protocol.DocumentURI(uri), }, } @@ -712,7 +712,7 @@ func (c *Client) CloseAllFiles(ctx context.Context) { // First collect all URIs that need to be closed for uri := range c.openFiles { // Convert URI back to file path using proper URI handling - filePath := protocol.DocumentUri(uri).Path() + filePath := protocol.DocumentURI(uri).Path() filesToClose = append(filesToClose, filePath) } c.openFilesMu.Unlock() @@ -730,7 +730,7 @@ func (c *Client) CloseAllFiles(ctx context.Context) { } } -func (c *Client) GetFileDiagnostics(uri protocol.DocumentUri) []protocol.Diagnostic { +func (c *Client) GetFileDiagnostics(uri protocol.DocumentURI) []protocol.Diagnostic { c.diagnosticsMu.RLock() defer c.diagnosticsMu.RUnlock() @@ -738,7 +738,7 @@ func (c *Client) GetFileDiagnostics(uri protocol.DocumentUri) []protocol.Diagnos } // GetDiagnostics returns all diagnostics for all files -func (c *Client) GetDiagnostics() map[protocol.DocumentUri][]protocol.Diagnostic { +func (c *Client) GetDiagnostics() map[protocol.DocumentURI][]protocol.Diagnostic { return c.diagnostics } @@ -757,7 +757,7 @@ func (c *Client) OpenFileOnDemand(ctx context.Context, filepath string) error { // GetDiagnosticsForFile ensures a file is open and returns its diagnostics // This is useful for on-demand diagnostics when using lazy loading func (c *Client) GetDiagnosticsForFile(ctx context.Context, filepath string) ([]protocol.Diagnostic, error) { - documentUri := protocol.URIFromPath(filepath) + documentURI := protocol.URIFromPath(filepath) // Make sure the file is open if !c.IsFileOpen(filepath) { @@ -771,14 +771,14 @@ func (c *Client) GetDiagnosticsForFile(ctx context.Context, filepath string) ([] // Get diagnostics c.diagnosticsMu.RLock() - diagnostics := c.diagnostics[documentUri] + diagnostics := c.diagnostics[documentURI] c.diagnosticsMu.RUnlock() return diagnostics, nil } // ClearDiagnosticsForURI removes diagnostics for a specific URI from the cache -func (c *Client) ClearDiagnosticsForURI(uri protocol.DocumentUri) { +func (c *Client) ClearDiagnosticsForURI(uri protocol.DocumentURI) { c.diagnosticsMu.Lock() defer c.diagnosticsMu.Unlock() delete(c.diagnostics, uri) diff --git a/internal/lsp/protocol/interface.go b/internal/lsp/protocol/interface.go index bfb8687463198a7adaf62eb4a525076a7eac094a..89311b31c8398db1d2da63fc15961294ff79badd 100644 --- a/internal/lsp/protocol/interface.go +++ b/internal/lsp/protocol/interface.go @@ -2,7 +2,7 @@ package protocol import "fmt" -// TextEditResult is an interface for types that represent workspace symbols +// WorkspaceSymbolResult is an interface for types that represent workspace symbols type WorkspaceSymbolResult interface { GetName() string GetLocation() Location @@ -48,7 +48,7 @@ func (r Or_Result_workspace_symbol) Results() ([]WorkspaceSymbolResult, error) { } } -// TextEditResult is an interface for types that represent document symbols +// DocumentSymbolResult is an interface for types that represent document symbols type DocumentSymbolResult interface { GetRange() Range GetName() string @@ -98,7 +98,7 @@ func (te *TextEdit) GetRange() Range { return te.Range } func (te *TextEdit) GetNewText() string { return te.NewText } func (te *TextEdit) isTextEdit() {} -// Convert Or_TextDocumentEdit_edits_Elem to TextEdit +// AsTextEdit converts Or_TextDocumentEdit_edits_Elem to TextEdit func (e Or_TextDocumentEdit_edits_Elem) AsTextEdit() (TextEdit, error) { if e.Value == nil { return TextEdit{}, fmt.Errorf("nil text edit") diff --git a/internal/lsp/protocol/pattern_interfaces.go b/internal/lsp/protocol/pattern_interfaces.go index ed68969faffd439732d34a150f6bbec9f6e0c264..9ee48cb4565cef6bc9168467aaa7e4fdc21a36a8 100644 --- a/internal/lsp/protocol/pattern_interfaces.go +++ b/internal/lsp/protocol/pattern_interfaces.go @@ -44,8 +44,8 @@ func (g *GlobPattern) AsPattern() (PatternInfo, error) { basePath := "" switch baseURI := v.BaseURI.Value.(type) { case string: - basePath = DocumentUri(baseURI).Path() - case DocumentUri: + basePath = DocumentURI(baseURI).Path() + case DocumentURI: basePath = baseURI.Path() default: return nil, fmt.Errorf("unknown BaseURI type: %T", v.BaseURI.Value) diff --git a/internal/lsp/protocol/tsdocument-changes.go b/internal/lsp/protocol/tsdocument-changes.go index 63b9914eb7358870aeec108d6492075b70a428bd..f18825719efad72e04502094931280e78ccbad59 100644 --- a/internal/lsp/protocol/tsdocument-changes.go +++ b/internal/lsp/protocol/tsdocument-changes.go @@ -23,18 +23,18 @@ type DocumentChange struct { // Valid reports whether the DocumentChange sum-type value is valid, // that is, exactly one of create, delete, edit, or rename. -func (ch DocumentChange) Valid() bool { +func (d DocumentChange) Valid() bool { n := 0 - if ch.TextDocumentEdit != nil { + if d.TextDocumentEdit != nil { n++ } - if ch.CreateFile != nil { + if d.CreateFile != nil { n++ } - if ch.RenameFile != nil { + if d.RenameFile != nil { n++ } - if ch.DeleteFile != nil { + if d.DeleteFile != nil { n++ } return n == 1 diff --git a/internal/lsp/protocol/tsprotocol.go b/internal/lsp/protocol/tsprotocol.go index ce4e58d4785275337ac5bfb784b596fe2d832b28..0e6356cdfe6203882c208fe9447fd5d9ee56923f 100644 --- a/internal/lsp/protocol/tsprotocol.go +++ b/internal/lsp/protocol/tsprotocol.go @@ -133,7 +133,7 @@ type CallHierarchyItem struct { // More detail for this item, e.g. the signature of a function. Detail string `json:"detail,omitempty"` // The resource identifier of this item. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. Range Range `json:"range"` // The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. @@ -225,16 +225,18 @@ type ChangeAnnotation struct { // An identifier to refer to a change annotation stored with a workspace edit. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#changeAnnotationIdentifier -type ChangeAnnotationIdentifier = string // (alias) -// @since 3.18.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#changeAnnotationsSupportOptions -type ChangeAnnotationsSupportOptions struct { - // Whether the client groups edits with equal labels into tree nodes, - // for instance all edits labelled with "Changes in Strings" would - // be a tree node. - GroupsOnLabel bool `json:"groupsOnLabel,omitempty"` -} +type ( + ChangeAnnotationIdentifier = string // (alias) + // @since 3.18.0 + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#changeAnnotationsSupportOptions + ChangeAnnotationsSupportOptions struct { + // Whether the client groups edits with equal labels into tree nodes, + // for instance all edits labelled with "Changes in Strings" would + // be a tree node. + GroupsOnLabel bool `json:"groupsOnLabel,omitempty"` + } +) // Defines the capabilities provided by the client. // @@ -1249,7 +1251,7 @@ type CreateFile struct { // A create Kind string `json:"kind"` // The resource to create. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // Additional options Options *CreateFileOptions `json:"options,omitempty"` ResourceOperation @@ -1279,18 +1281,20 @@ type CreateFilesParams struct { // The declaration of a symbol representation as one or many {@link Location locations}. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declaration -type Declaration = Or_Declaration // (alias) -// @since 3.14.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declarationClientCapabilities -type DeclarationClientCapabilities struct { - // Whether declaration supports dynamic registration. If this is set to `true` - // the client supports the new `DeclarationRegistrationOptions` return value - // for the corresponding server capability as well. - DynamicRegistration bool `json:"dynamicRegistration,omitempty"` - // The client supports additional metadata in the form of declaration links. - LinkSupport bool `json:"linkSupport,omitempty"` -} +type ( + Declaration = Or_Declaration // (alias) + // @since 3.14.0 + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declarationClientCapabilities + DeclarationClientCapabilities struct { + // Whether declaration supports dynamic registration. If this is set to `true` + // the client supports the new `DeclarationRegistrationOptions` return value + // for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + // The client supports additional metadata in the form of declaration links. + LinkSupport bool `json:"linkSupport,omitempty"` + } +) // Information about where a symbol is declared. // @@ -1301,11 +1305,13 @@ type DeclarationClientCapabilities struct { // by the client. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declarationLink -type DeclarationLink = LocationLink // (alias) -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declarationOptions -type DeclarationOptions struct { - WorkDoneProgressOptions -} +type ( + DeclarationLink = LocationLink // (alias) + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declarationOptions + DeclarationOptions struct { + WorkDoneProgressOptions + } +) // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#declarationParams type DeclarationParams struct { @@ -1329,18 +1335,20 @@ type DeclarationRegistrationOptions struct { // by the client. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#definition -type Definition = Or_Definition // (alias) -// Client Capabilities for a {@link DefinitionRequest}. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#definitionClientCapabilities -type DefinitionClientCapabilities struct { - // Whether definition supports dynamic registration. - DynamicRegistration bool `json:"dynamicRegistration,omitempty"` - // The client supports additional metadata in the form of definition links. - // - // @since 3.14.0 - LinkSupport bool `json:"linkSupport,omitempty"` -} +type ( + Definition = Or_Definition // (alias) + // Client Capabilities for a {@link DefinitionRequest}. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#definitionClientCapabilities + DefinitionClientCapabilities struct { + // Whether definition supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + // The client supports additional metadata in the form of definition links. + // + // @since 3.14.0 + LinkSupport bool `json:"linkSupport,omitempty"` + } +) // Information about where a symbol is defined. // @@ -1348,13 +1356,15 @@ type DefinitionClientCapabilities struct { // the defining symbol // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#definitionLink -type DefinitionLink = LocationLink // (alias) -// Server Capabilities for a {@link DefinitionRequest}. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#definitionOptions -type DefinitionOptions struct { - WorkDoneProgressOptions -} +type ( + DefinitionLink = LocationLink // (alias) + // Server Capabilities for a {@link DefinitionRequest}. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#definitionOptions + DefinitionOptions struct { + WorkDoneProgressOptions + } +) // Parameters for a {@link DefinitionRequest}. // @@ -1380,7 +1390,7 @@ type DeleteFile struct { // A delete Kind string `json:"kind"` // The file to delete. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // Delete options. Options *DeleteFileOptions `json:"options,omitempty"` ResourceOperation @@ -1783,11 +1793,13 @@ type DocumentDiagnosticParams struct { // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentDiagnosticReport -type DocumentDiagnosticReport = Or_DocumentDiagnosticReport // (alias) -// The document diagnostic report kinds. -// -// @since 3.17.0 -type DocumentDiagnosticReportKind string +type ( + DocumentDiagnosticReport = Or_DocumentDiagnosticReport // (alias) + // The document diagnostic report kinds. + // + // @since 3.17.0 + DocumentDiagnosticReportKind string +) // A partial result for a document diagnostic report. // @@ -1795,7 +1807,7 @@ type DocumentDiagnosticReportKind string // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentDiagnosticReportPartialResult type DocumentDiagnosticReportPartialResult struct { - RelatedDocuments map[DocumentUri]interface{} `json:"relatedDocuments"` + RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments"` } // A document filter describes a top level text document or @@ -1804,14 +1816,16 @@ type DocumentDiagnosticReportPartialResult struct { // @since 3.17.0 - proposed support for NotebookCellTextDocumentFilter. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentFilter -type DocumentFilter = Or_DocumentFilter // (alias) -// Client capabilities of a {@link DocumentFormattingRequest}. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentFormattingClientCapabilities -type DocumentFormattingClientCapabilities struct { - // Whether formatting supports dynamic registration. - DynamicRegistration bool `json:"dynamicRegistration,omitempty"` -} +type ( + DocumentFilter = Or_DocumentFilter // (alias) + // Client capabilities of a {@link DocumentFormattingRequest}. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentFormattingClientCapabilities + DocumentFormattingClientCapabilities struct { + // Whether formatting supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } +) // Provider options for a {@link DocumentFormattingRequest}. // @@ -2061,39 +2075,41 @@ type DocumentRangesFormattingParams struct { // The use of a string as a document filter is deprecated @since 3.16.0. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentSelector -type DocumentSelector = []DocumentFilter // (alias) -// Represents programming constructs like variables, classes, interfaces etc. -// that appear in a document. Document symbols can be hierarchical and they -// have two ranges: one that encloses its definition and one that points to -// its most interesting range, e.g. the range of an identifier. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentSymbol -type DocumentSymbol struct { - // The name of this symbol. Will be displayed in the user interface and therefore must not be - // an empty string or a string only consisting of white spaces. - Name string `json:"name"` - // More detail for this symbol, e.g the signature of a function. - Detail string `json:"detail,omitempty"` - // The kind of this symbol. - Kind SymbolKind `json:"kind"` - // Tags for this document symbol. - // - // @since 3.16.0 - Tags []SymbolTag `json:"tags,omitempty"` - // Indicates if this symbol is deprecated. - // - // @deprecated Use tags instead - Deprecated bool `json:"deprecated,omitempty"` - // The range enclosing this symbol not including leading/trailing whitespace but everything else - // like comments. This information is typically used to determine if the clients cursor is - // inside the symbol to reveal in the symbol in the UI. - Range Range `json:"range"` - // The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. - // Must be contained by the `range`. - SelectionRange Range `json:"selectionRange"` - // Children of this symbol, e.g. properties of a class. - Children []DocumentSymbol `json:"children,omitempty"` -} +type ( + DocumentSelector = []DocumentFilter // (alias) + // Represents programming constructs like variables, classes, interfaces etc. + // that appear in a document. Document symbols can be hierarchical and they + // have two ranges: one that encloses its definition and one that points to + // its most interesting range, e.g. the range of an identifier. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentSymbol + DocumentSymbol struct { + // The name of this symbol. Will be displayed in the user interface and therefore must not be + // an empty string or a string only consisting of white spaces. + Name string `json:"name"` + // More detail for this symbol, e.g the signature of a function. + Detail string `json:"detail,omitempty"` + // The kind of this symbol. + Kind SymbolKind `json:"kind"` + // Tags for this document symbol. + // + // @since 3.16.0 + Tags []SymbolTag `json:"tags,omitempty"` + // Indicates if this symbol is deprecated. + // + // @deprecated Use tags instead + Deprecated bool `json:"deprecated,omitempty"` + // The range enclosing this symbol not including leading/trailing whitespace but everything else + // like comments. This information is typically used to determine if the clients cursor is + // inside the symbol to reveal in the symbol in the UI. + Range Range `json:"range"` + // The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + // Must be contained by the `range`. + SelectionRange Range `json:"selectionRange"` + // Children of this symbol, e.g. properties of a class. + Children []DocumentSymbol `json:"children,omitempty"` + } +) // Client Capabilities for a {@link DocumentSymbolRequest}. // @@ -2237,7 +2253,7 @@ type FileDelete struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#fileEvent type FileEvent struct { // The file's uri. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The change type. Type FileChangeType `json:"type"` } @@ -2556,17 +2572,19 @@ type GeneralClientCapabilities struct { // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#globPattern -type GlobPattern = Or_GlobPattern // (alias) -// The result of a hover request. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#hover -type Hover struct { - // The hover's content - Contents MarkupContent `json:"contents"` - // An optional range inside the text document that is used to - // visualize the hover, e.g. by changing the background color. - Range Range `json:"range,omitempty"` -} +type ( + GlobPattern = Or_GlobPattern // (alias) + // The result of a hover request. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#hover + Hover struct { + // The hover's content + Contents MarkupContent `json:"contents"` + // An optional range inside the text document that is used to + // visualize the hover, e.g. by changing the background color. + Range Range `json:"range,omitempty"` + } +) // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#hoverClientCapabilities type HoverClientCapabilities struct { @@ -2664,8 +2682,7 @@ type InitializeResult struct { } // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#initializedParams -type InitializedParams struct { -} +type InitializedParams struct{} // Inlay hint information. // @@ -2918,16 +2935,18 @@ type InlineCompletionTriggerKind uint32 // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#inlineValue -type InlineValue = Or_InlineValue // (alias) -// Client capabilities specific to inline values. -// -// @since 3.17.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#inlineValueClientCapabilities -type InlineValueClientCapabilities struct { - // Whether implementation supports dynamic registration for inline value providers. - DynamicRegistration bool `json:"dynamicRegistration,omitempty"` -} +type ( + InlineValue = Or_InlineValue // (alias) + // Client capabilities specific to inline values. + // + // @since 3.17.0 + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#inlineValueClientCapabilities + InlineValueClientCapabilities struct { + // Whether implementation supports dynamic registration for inline value providers. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } +) // @since 3.17.0 // @@ -3058,25 +3077,31 @@ type InsertTextFormat uint32 // item insertion. // // @since 3.16.0 -type InsertTextMode uint32 -type LSPAny = interface{} +type ( + InsertTextMode uint32 + LSPAny = interface{} +) // LSP arrays. // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#lSPArray -type LSPArray = []interface{} // (alias) -type LSPErrorCodes int32 +type ( + LSPArray = []interface{} // (alias) + LSPErrorCodes int32 +) // LSP object definition. // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#lSPObject -type LSPObject = map[string]LSPAny // (alias) -// Predefined Language kinds -// @since 3.18.0 -// @proposed -type LanguageKind string +type ( + LSPObject = map[string]LSPAny // (alias) + // Predefined Language kinds + // @since 3.18.0 + // @proposed + LanguageKind string +) // Client capabilities for the linked editing range request. // @@ -3124,19 +3149,17 @@ type LinkedEditingRanges struct { } // created for Literal (Lit_ClientSemanticTokensRequestOptions_range_Item1) -type Lit_ClientSemanticTokensRequestOptions_range_Item1 struct { -} +type Lit_ClientSemanticTokensRequestOptions_range_Item1 struct{} // created for Literal (Lit_SemanticTokensOptions_range_Item1) -type Lit_SemanticTokensOptions_range_Item1 struct { -} +type Lit_SemanticTokensOptions_range_Item1 struct{} // Represents a location inside a resource, such as a line // inside a text file. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#location type Location struct { - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` Range Range `json:"range"` } @@ -3151,7 +3174,7 @@ type LocationLink struct { // the definition position. OriginSelectionRange *Range `json:"originSelectionRange,omitempty"` // The target resource identifier of this link. - TargetURI DocumentUri `json:"targetUri"` + TargetURI DocumentURI `json:"targetUri"` // The full target range of this link. If the target for example is a symbol then target range is the // range enclosing this symbol not including leading/trailing whitespace but everything else // like comments. This information is typically used to highlight the range in the editor. @@ -3167,7 +3190,7 @@ type LocationLink struct { // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#locationUriOnly type LocationUriOnly struct { - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` } // The log message parameters. @@ -3217,15 +3240,17 @@ type MarkdownClientCapabilities struct { // @deprecated use MarkupContent instead. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#markedString -type MarkedString = Or_MarkedString // (alias) -// @since 3.18.0 -// @deprecated use MarkupContent instead. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#markedStringWithLanguage -type MarkedStringWithLanguage struct { - Language string `json:"language"` - Value string `json:"value"` -} +type ( + MarkedString = Or_MarkedString // (alias) + // @since 3.18.0 + // @deprecated use MarkupContent instead. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#markedStringWithLanguage + MarkedStringWithLanguage struct { + Language string `json:"language"` + Value string `json:"value"` + } +) // A `MarkupContent` literal represents a string value which content is interpreted base on its // kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. @@ -3342,7 +3367,7 @@ type NotebookCell struct { Kind NotebookCellKind `json:"kind"` // The URI of the cell's text document // content. - Document DocumentUri `json:"document"` + Document DocumentURI `json:"document"` // Additional metadata stored with the cell. // // Note: should always be an object literal (e.g. LSPObject) @@ -3493,20 +3518,22 @@ type NotebookDocumentClientCapabilities struct { // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#notebookDocumentFilter -type NotebookDocumentFilter = Or_NotebookDocumentFilter // (alias) -// A notebook document filter where `notebookType` is required field. -// -// @since 3.18.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#notebookDocumentFilterNotebookType -type NotebookDocumentFilterNotebookType struct { - // The type of the enclosing notebook. - NotebookType string `json:"notebookType"` - // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. - Scheme string `json:"scheme,omitempty"` - // A glob pattern. - Pattern *GlobPattern `json:"pattern,omitempty"` -} +type ( + NotebookDocumentFilter = Or_NotebookDocumentFilter // (alias) + // A notebook document filter where `notebookType` is required field. + // + // @since 3.18.0 + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#notebookDocumentFilterNotebookType + NotebookDocumentFilterNotebookType struct { + // The type of the enclosing notebook. + NotebookType string `json:"notebookType"` + // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. + Scheme string `json:"scheme,omitempty"` + // A glob pattern. + Pattern *GlobPattern `json:"pattern,omitempty"` + } +) // A notebook document filter where `pattern` is required field. // @@ -4101,51 +4128,53 @@ type PartialResultParams struct { // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#pattern -type Pattern = string // (alias) -// Position in a text document expressed as zero-based line and character -// offset. Prior to 3.17 the offsets were always based on a UTF-16 string -// representation. So a string of the form `a𐐀b` the character offset of the -// character `a` is 0, the character offset of `𐐀` is 1 and the character -// offset of b is 3 since `𐐀` is represented using two code units in UTF-16. -// Since 3.17 clients and servers can agree on a different string encoding -// representation (e.g. UTF-8). The client announces it's supported encoding -// via the client capability [`general.positionEncodings`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#clientCapabilities). -// The value is an array of position encodings the client supports, with -// decreasing preference (e.g. the encoding at index `0` is the most preferred -// one). To stay backwards compatible the only mandatory encoding is UTF-16 -// represented via the string `utf-16`. The server can pick one of the -// encodings offered by the client and signals that encoding back to the -// client via the initialize result's property -// [`capabilities.positionEncoding`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#serverCapabilities). If the string value -// `utf-16` is missing from the client's capability `general.positionEncodings` -// servers can safely assume that the client supports UTF-16. If the server -// omits the position encoding in its initialize result the encoding defaults -// to the string value `utf-16`. Implementation considerations: since the -// conversion from one encoding into another requires the content of the -// file / line the conversion is best done where the file is read which is -// usually on the server side. -// -// Positions are line end character agnostic. So you can not specify a position -// that denotes `\r|\n` or `\n|` where `|` represents the character offset. -// -// @since 3.17.0 - support for negotiated position encoding. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#position -type Position struct { - // Line position in a document (zero-based). - // - // If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. - // If a line number is negative, it defaults to 0. - Line uint32 `json:"line"` - // Character offset on a line in a document (zero-based). - // - // The meaning of this offset is determined by the negotiated - // `PositionEncodingKind`. - // - // If the character value is greater than the line length it defaults back to the - // line length. - Character uint32 `json:"character"` -} +type ( + Pattern = string // (alias) + // Position in a text document expressed as zero-based line and character + // offset. Prior to 3.17 the offsets were always based on a UTF-16 string + // representation. So a string of the form `a𐐀b` the character offset of the + // character `a` is 0, the character offset of `𐐀` is 1 and the character + // offset of b is 3 since `𐐀` is represented using two code units in UTF-16. + // Since 3.17 clients and servers can agree on a different string encoding + // representation (e.g. UTF-8). The client announces it's supported encoding + // via the client capability [`general.positionEncodings`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#clientCapabilities). + // The value is an array of position encodings the client supports, with + // decreasing preference (e.g. the encoding at index `0` is the most preferred + // one). To stay backwards compatible the only mandatory encoding is UTF-16 + // represented via the string `utf-16`. The server can pick one of the + // encodings offered by the client and signals that encoding back to the + // client via the initialize result's property + // [`capabilities.positionEncoding`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#serverCapabilities). If the string value + // `utf-16` is missing from the client's capability `general.positionEncodings` + // servers can safely assume that the client supports UTF-16. If the server + // omits the position encoding in its initialize result the encoding defaults + // to the string value `utf-16`. Implementation considerations: since the + // conversion from one encoding into another requires the content of the + // file / line the conversion is best done where the file is read which is + // usually on the server side. + // + // Positions are line end character agnostic. So you can not specify a position + // that denotes `\r|\n` or `\n|` where `|` represents the character offset. + // + // @since 3.17.0 - support for negotiated position encoding. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#position + Position struct { + // Line position in a document (zero-based). + // + // If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. + // If a line number is negative, it defaults to 0. + Line uint32 `json:"line"` + // Character offset on a line in a document (zero-based). + // + // The meaning of this offset is determined by the negotiated + // `PositionEncodingKind`. + // + // If the character value is greater than the line length it defaults back to the + // line length. + Character uint32 `json:"character"` + } +) // A set of predefined position encoding kinds. // @@ -4174,8 +4203,10 @@ type PrepareRenamePlaceholder struct { } // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#prepareRenameResult -type PrepareRenameResult = Or_PrepareRenameResult // (alias) -type PrepareSupportDefaultBehavior uint32 +type ( + PrepareRenameResult = Or_PrepareRenameResult // (alias) + PrepareSupportDefaultBehavior uint32 +) // A previous result id in a workspace pull request. // @@ -4185,7 +4216,7 @@ type PrepareSupportDefaultBehavior uint32 type PreviousResultID struct { // The URI for which the client knowns a // result id. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The value of the previous result id. Value string `json:"value"` } @@ -4198,7 +4229,7 @@ type PreviousResultID struct { type PreviousResultId struct { // The URI for which the client knowns a // result id. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The value of the previous result id. Value string `json:"value"` } @@ -4212,25 +4243,27 @@ type ProgressParams struct { } // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#progressToken -type ProgressToken = Or_ProgressToken // (alias) -// The publish diagnostic client capabilities. -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#publishDiagnosticsClientCapabilities -type PublishDiagnosticsClientCapabilities struct { - // Whether the client interprets the version property of the - // `textDocument/publishDiagnostics` notification's parameter. - // - // @since 3.15.0 - VersionSupport bool `json:"versionSupport,omitempty"` - DiagnosticsCapabilities -} +type ( + ProgressToken = Or_ProgressToken // (alias) + // The publish diagnostic client capabilities. + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#publishDiagnosticsClientCapabilities + PublishDiagnosticsClientCapabilities struct { + // Whether the client interprets the version property of the + // `textDocument/publishDiagnostics` notification's parameter. + // + // @since 3.15.0 + VersionSupport bool `json:"versionSupport,omitempty"` + DiagnosticsCapabilities + } +) // The publish diagnostic notification's parameters. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#publishDiagnosticsParams type PublishDiagnosticsParams struct { // The URI for which diagnostic information is reported. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // Optional the version number of the document the diagnostics are published for. // // @since 3.15.0 @@ -4322,18 +4355,20 @@ type RegistrationParams struct { } // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#regularExpressionEngineKind -type RegularExpressionEngineKind = string // (alias) -// Client capabilities specific to regular expressions. -// -// @since 3.16.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#regularExpressionsClientCapabilities -type RegularExpressionsClientCapabilities struct { - // The engine's name. - Engine RegularExpressionEngineKind `json:"engine"` - // The engine's version. - Version string `json:"version,omitempty"` -} +type ( + RegularExpressionEngineKind = string // (alias) + // Client capabilities specific to regular expressions. + // + // @since 3.16.0 + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#regularExpressionsClientCapabilities + RegularExpressionsClientCapabilities struct { + // The engine's name. + Engine RegularExpressionEngineKind `json:"engine"` + // The engine's version. + Version string `json:"version,omitempty"` + } +) // A full diagnostic report with a set of related documents. // @@ -4348,7 +4383,7 @@ type RelatedFullDocumentDiagnosticReport struct { // a.cpp and result in errors in a header file b.hpp. // // @since 3.17.0 - RelatedDocuments map[DocumentUri]interface{} `json:"relatedDocuments,omitempty"` + RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments,omitempty"` FullDocumentDiagnosticReport } @@ -4365,7 +4400,7 @@ type RelatedUnchangedDocumentDiagnosticReport struct { // a.cpp and result in errors in a header file b.hpp. // // @since 3.17.0 - RelatedDocuments map[DocumentUri]interface{} `json:"relatedDocuments,omitempty"` + RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments,omitempty"` UnchangedDocumentDiagnosticReport } @@ -4417,9 +4452,9 @@ type RenameFile struct { // A rename Kind string `json:"kind"` // The old (existing) location. - OldURI DocumentUri `json:"oldUri"` + OldURI DocumentURI `json:"oldUri"` // The new location. - NewURI DocumentUri `json:"newUri"` + NewURI DocumentURI `json:"newUri"` // Rename options. Options *RenameFileOptions `json:"options,omitempty"` ResourceOperation @@ -5337,20 +5372,22 @@ type TextDocumentClientCapabilities struct { // it is considered to be the full content of the document. // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentContentChangeEvent -type TextDocumentContentChangeEvent = Or_TextDocumentContentChangeEvent // (alias) -// @since 3.18.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentContentChangePartial -type TextDocumentContentChangePartial struct { - // The range of the document that changed. - Range *Range `json:"range,omitempty"` - // The optional length of the range that got replaced. +type ( + TextDocumentContentChangeEvent = Or_TextDocumentContentChangeEvent // (alias) + // @since 3.18.0 // - // @deprecated use range instead. - RangeLength uint32 `json:"rangeLength,omitempty"` - // The new text for the provided range. - Text string `json:"text"` -} + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentContentChangePartial + TextDocumentContentChangePartial struct { + // The range of the document that changed. + Range *Range `json:"range,omitempty"` + // The optional length of the range that got replaced. + // + // @deprecated use range instead. + RangeLength uint32 `json:"rangeLength,omitempty"` + // The new text for the provided range. + Text string `json:"text"` + } +) // @since 3.18.0 // @@ -5390,7 +5427,7 @@ type TextDocumentContentOptions struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentContentParams type TextDocumentContentParams struct { // The uri of the text document. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` } // Parameters for the `workspace/textDocumentContent/refresh` request. @@ -5401,7 +5438,7 @@ type TextDocumentContentParams struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentContentRefreshParams type TextDocumentContentRefreshParams struct { // The uri of the text document to refresh. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` } // Text document content provider registration options. @@ -5453,22 +5490,24 @@ type TextDocumentEdit struct { // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentFilter -type TextDocumentFilter = Or_TextDocumentFilter // (alias) -// A document filter where `language` is required field. -// -// @since 3.18.0 -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentFilterLanguage -type TextDocumentFilterLanguage struct { - // A language id, like `typescript`. - Language string `json:"language"` - // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. - Scheme string `json:"scheme,omitempty"` - // A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. +type ( + TextDocumentFilter = Or_TextDocumentFilter // (alias) + // A document filter where `language` is required field. // - // @since 3.18.0 - support for relative patterns. - Pattern *GlobPattern `json:"pattern,omitempty"` -} + // @since 3.18.0 + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentFilterLanguage + TextDocumentFilterLanguage struct { + // A language id, like `typescript`. + Language string `json:"language"` + // A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. + Scheme string `json:"scheme,omitempty"` + // A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. + // + // @since 3.18.0 - support for relative patterns. + Pattern *GlobPattern `json:"pattern,omitempty"` + } +) // A document filter where `pattern` is required field. // @@ -5507,7 +5546,7 @@ type TextDocumentFilterScheme struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentIdentifier type TextDocumentIdentifier struct { // The text document's uri. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` } // An item to transfer a text document from the client to the @@ -5516,7 +5555,7 @@ type TextDocumentIdentifier struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocumentItem type TextDocumentItem struct { // The text document's uri. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The text document's language identifier. LanguageID LanguageKind `json:"languageId"` // The version number of this document (it will increase after each @@ -5605,8 +5644,10 @@ type TextEdit struct { // empty string. NewText string `json:"newText"` } -type TokenFormat string -type TraceValue string +type ( + TokenFormat string + TraceValue string +) // created for Tuple type Tuple_ParameterInformation_label_Item1 struct { @@ -5670,7 +5711,7 @@ type TypeHierarchyItem struct { // More detail for this item, e.g. the signature of a function. Detail string `json:"detail,omitempty"` // The resource identifier of this item. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The range enclosing this symbol not including leading/trailing whitespace // but everything else, e.g. comments and code. Range Range `json:"range"` @@ -5795,14 +5836,16 @@ type VersionedTextDocumentIdentifier struct { Version int32 `json:"version"` TextDocumentIdentifier } -type WatchKind = uint32 // The parameters sent in a will save text document notification. -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#willSaveTextDocumentParams -type WillSaveTextDocumentParams struct { - // The document that will be saved. - TextDocument TextDocumentIdentifier `json:"textDocument"` - // The 'TextDocumentSaveReason'. - Reason TextDocumentSaveReason `json:"reason"` -} +type ( + WatchKind = uint32 // The parameters sent in a will save text document notification. + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#willSaveTextDocumentParams + WillSaveTextDocumentParams struct { + // The document that will be saved. + TextDocument TextDocumentIdentifier `json:"textDocument"` + // The 'TextDocumentSaveReason'. + Reason TextDocumentSaveReason `json:"reason"` + } +) // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#windowClientCapabilities type WindowClientCapabilities struct { @@ -6012,43 +6055,45 @@ type WorkspaceDiagnosticReportPartialResult struct { // @since 3.17.0 // // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspaceDocumentDiagnosticReport -type WorkspaceDocumentDiagnosticReport = Or_WorkspaceDocumentDiagnosticReport // (alias) -// A workspace edit represents changes to many resources managed in the workspace. The edit -// should either provide `changes` or `documentChanges`. If documentChanges are present -// they are preferred over `changes` if the client can handle versioned document edits. -// -// Since version 3.13.0 a workspace edit can contain resource operations as well. If resource -// operations are present clients need to execute the operations in the order in which they -// are provided. So a workspace edit for example can consist of the following two changes: -// (1) a create file a.txt and (2) a text document edit which insert text into file a.txt. -// -// An invalid sequence (e.g. (1) delete file a.txt and (2) insert text into file a.txt) will -// cause failure of the operation. How the client recovers from the failure is described by -// the client capability: `workspace.workspaceEdit.failureHandling` -// -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspaceEdit -type WorkspaceEdit struct { - // Holds changes to existing resources. - Changes map[DocumentUri][]TextEdit `json:"changes,omitempty"` - // Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes - // are either an array of `TextDocumentEdit`s to express changes to n different text documents - // where each text document edit addresses a specific version of a text document. Or it can contain - // above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. - // - // Whether a client supports versioned document edits is expressed via - // `workspace.workspaceEdit.documentChanges` client capability. - // - // If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then - // only plain `TextEdit`s using the `changes` property are supported. - DocumentChanges []DocumentChange `json:"documentChanges,omitempty"` - // A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and - // delete file / folder operations. - // - // Whether clients honor this property depends on the client capability `workspace.changeAnnotationSupport`. - // - // @since 3.16.0 - ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations,omitempty"` -} +type ( + WorkspaceDocumentDiagnosticReport = Or_WorkspaceDocumentDiagnosticReport // (alias) + // A workspace edit represents changes to many resources managed in the workspace. The edit + // should either provide `changes` or `documentChanges`. If documentChanges are present + // they are preferred over `changes` if the client can handle versioned document edits. + // + // Since version 3.13.0 a workspace edit can contain resource operations as well. If resource + // operations are present clients need to execute the operations in the order in which they + // are provided. So a workspace edit for example can consist of the following two changes: + // (1) a create file a.txt and (2) a text document edit which insert text into file a.txt. + // + // An invalid sequence (e.g. (1) delete file a.txt and (2) insert text into file a.txt) will + // cause failure of the operation. How the client recovers from the failure is described by + // the client capability: `workspace.workspaceEdit.failureHandling` + // + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspaceEdit + WorkspaceEdit struct { + // Holds changes to existing resources. + Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"` + // Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + // are either an array of `TextDocumentEdit`s to express changes to n different text documents + // where each text document edit addresses a specific version of a text document. Or it can contain + // above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + // + // Whether a client supports versioned document edits is expressed via + // `workspace.workspaceEdit.documentChanges` client capability. + // + // If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + // only plain `TextEdit`s using the `changes` property are supported. + DocumentChanges []DocumentChange `json:"documentChanges,omitempty"` + // A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and + // delete file / folder operations. + // + // Whether clients honor this property depends on the client capability `workspace.changeAnnotationSupport`. + // + // @since 3.16.0 + ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations,omitempty"` + } +) // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspaceEditClientCapabilities type WorkspaceEditClientCapabilities struct { @@ -6154,7 +6199,7 @@ type WorkspaceFoldersServerCapabilities struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspaceFullDocumentDiagnosticReport type WorkspaceFullDocumentDiagnosticReport struct { // The URI for which diagnostic information is reported. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The version number for which the diagnostics are reported. // If the document is not marked as open `null` can be provided. Version int32 `json:"version"` @@ -6266,7 +6311,7 @@ type WorkspaceSymbolRegistrationOptions struct { // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspaceUnchangedDocumentDiagnosticReport type WorkspaceUnchangedDocumentDiagnosticReport struct { // The URI for which diagnostic information is reported. - URI DocumentUri `json:"uri"` + URI DocumentURI `json:"uri"` // The version number for which the diagnostics are reported. // If the document is not marked as open `null` can be provided. Version int32 `json:"version"` @@ -6306,7 +6351,7 @@ type XInitializeParams struct { // `rootUri` wins. // // @deprecated in favour of workspaceFolders. - RootURI DocumentUri `json:"rootUri"` + RootURI DocumentURI `json:"rootUri"` // The capabilities provided by the client (editor or tool) Capabilities ClientCapabilities `json:"capabilities"` // User provided initialization options. @@ -6349,7 +6394,7 @@ type _InitializeParams struct { // `rootUri` wins. // // @deprecated in favour of workspaceFolders. - RootURI DocumentUri `json:"rootUri"` + RootURI DocumentURI `json:"rootUri"` // The capabilities provided by the client (editor or tool) Capabilities ClientCapabilities `json:"capabilities"` // User provided initialization options. diff --git a/internal/lsp/protocol/uri.go b/internal/lsp/protocol/uri.go index 18fd5ea75d836168e7cae41024a82c514b3fd9b7..a63ed406cc319c2f293406fe4cdd83c237c0c74a 100644 --- a/internal/lsp/protocol/uri.go +++ b/internal/lsp/protocol/uri.go @@ -17,7 +17,7 @@ import ( "unicode" ) -// A DocumentUri is the URI of a client editor document. +// A DocumentURI is the URI of a client editor document. // // According to the LSP specification: // @@ -38,8 +38,8 @@ import ( // file:///C%3A/project/readme.md // // This is done during JSON unmarshalling; -// see [DocumentUri.UnmarshalText] for details. -type DocumentUri string +// see [DocumentURI.UnmarshalText] for details. +type DocumentURI string // A URI is an arbitrary URL (e.g. https), not necessarily a file. type URI = string @@ -60,8 +60,8 @@ type URI = string // // Non-empty DocumentUris are valid "file"-scheme URIs. // The empty DocumentUri is valid. -func (uri *DocumentUri) UnmarshalText(data []byte) (err error) { - *uri, err = ParseDocumentUri(string(data)) +func (uri *DocumentURI) UnmarshalText(data []byte) (err error) { + *uri, err = ParseDocumentURI(string(data)) return } @@ -70,7 +70,7 @@ func (uri *DocumentUri) UnmarshalText(data []byte) (err error) { // DocumentUri("").Path() returns the empty string. // // Path panics if called on a URI that is not a valid filename. -func (uri DocumentUri) Path() string { +func (uri DocumentURI) Path() string { filename, err := filename(uri) if err != nil { // e.g. ParseRequestURI failed. @@ -85,7 +85,7 @@ func (uri DocumentUri) Path() string { } // Dir returns the URI for the directory containing the receiver. -func (uri DocumentUri) Dir() DocumentUri { +func (uri DocumentURI) Dir() DocumentURI { // This function could be more efficiently implemented by avoiding any call // to Path(), but at least consolidates URI manipulation. return URIFromPath(uri.DirPath()) @@ -93,11 +93,11 @@ func (uri DocumentUri) Dir() DocumentUri { // DirPath returns the file path to the directory containing this URI, which // must be a file URI. -func (uri DocumentUri) DirPath() string { +func (uri DocumentURI) DirPath() string { return filepath.Dir(uri.Path()) } -func filename(uri DocumentUri) (string, error) { +func filename(uri DocumentURI) (string, error) { if uri == "" { return "", nil } @@ -137,9 +137,9 @@ slow: return u.Path, nil } -// ParseDocumentUri interprets a string as a DocumentUri, applying VS -// Code workarounds; see [DocumentUri.UnmarshalText] for details. -func ParseDocumentUri(s string) (DocumentUri, error) { +// ParseDocumentURI interprets a string as a DocumentUri, applying VS +// Code workarounds; see [DocumentURI.UnmarshalText] for details. +func ParseDocumentURI(s string) (DocumentURI, error) { if s == "" { return "", nil } @@ -169,12 +169,12 @@ func ParseDocumentUri(s string) (DocumentUri, error) { path = path[:1] + strings.ToUpper(string(path[1])) + path[2:] } u := url.URL{Scheme: fileScheme, Path: path} - return DocumentUri(u.String()), nil + return DocumentURI(u.String()), nil } // URIFromPath returns DocumentUri for the supplied file path. // Given "", it returns "". -func URIFromPath(path string) DocumentUri { +func URIFromPath(path string) DocumentURI { if path == "" { return "" } @@ -192,7 +192,7 @@ func URIFromPath(path string) DocumentUri { Scheme: fileScheme, Path: path, } - return DocumentUri(u.String()) + return DocumentURI(u.String()) } const fileScheme = "file" diff --git a/internal/lsp/transport.go b/internal/lsp/transport.go index 9a3dfd261fb68b1afdd17f614daab761f9294327..b468101dbc36537c9f306399b4af6cbbe451d96f 100644 --- a/internal/lsp/transport.go +++ b/internal/lsp/transport.go @@ -12,7 +12,7 @@ import ( "github.com/charmbracelet/crush/internal/config" ) -// Write writes an LSP message to the given writer +// WriteMessage writes an LSP message to the given writer func WriteMessage(w io.Writer, msg *Message) error { data, err := json.Marshal(msg) if err != nil { diff --git a/internal/lsp/util/edit.go b/internal/lsp/util/edit.go index 6cf37105bb81808130c81567ade3277ad879de4b..b32eac0c66cffe7d50066a3e5db3e81332e4fa83 100644 --- a/internal/lsp/util/edit.go +++ b/internal/lsp/util/edit.go @@ -10,7 +10,7 @@ import ( "github.com/charmbracelet/crush/internal/lsp/protocol" ) -func applyTextEdits(uri protocol.DocumentUri, edits []protocol.TextEdit) error { +func applyTextEdits(uri protocol.DocumentURI, edits []protocol.TextEdit) error { path := uri.Path() // Read the file content diff --git a/internal/lsp/watcher/watcher.go b/internal/lsp/watcher/watcher.go index 5bd016eebe413a17acca29ef628612825d40b923..58f7830eb19f9841e72aa0356ad1d4c3d2aec7d1 100644 --- a/internal/lsp/watcher/watcher.go +++ b/internal/lsp/watcher/watcher.go @@ -77,7 +77,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc switch u := v.BaseURI.Value.(type) { case string: slog.Debug("BaseURI", "baseURI", u) - case protocol.DocumentUri: + case protocol.DocumentURI: slog.Debug("BaseURI", "baseURI", u) default: slog.Debug("BaseURI", "baseURI", u) @@ -514,8 +514,8 @@ func matchesGlob(pattern, path string) bool { // matchesSimpleGlob handles glob patterns with ** wildcards func matchesSimpleGlob(pattern, path string) bool { // Handle special case for **/*.ext pattern (common in LSP) - if strings.HasPrefix(pattern, "**/") { - rest := strings.TrimPrefix(pattern, "**/") + if after, ok := strings.CutPrefix(pattern, "**/"); ok { + rest := after // If the rest is a simple file extension pattern like *.go if strings.HasPrefix(rest, "*.") { @@ -607,7 +607,7 @@ func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPatt } // For relative patterns - basePath = protocol.DocumentUri(basePath).Path() + basePath = protocol.DocumentURI(basePath).Path() basePath = filepath.ToSlash(basePath) // Make path relative to basePath for matching @@ -650,9 +650,9 @@ func (w *WorkspaceWatcher) debounceHandleFileEvent(ctx context.Context, uri stri // handleFileEvent sends file change notifications func (w *WorkspaceWatcher) handleFileEvent(ctx context.Context, uri string, changeType protocol.FileChangeType) { // If the file is open and it's a change event, use didChange notification - filePath := protocol.DocumentUri(uri).Path() + filePath := protocol.DocumentURI(uri).Path() if changeType == protocol.FileChangeType(protocol.Deleted) { - w.client.ClearDiagnosticsForURI(protocol.DocumentUri(uri)) + w.client.ClearDiagnosticsForURI(protocol.DocumentURI(uri)) } else if changeType == protocol.FileChangeType(protocol.Changed) && w.client.IsFileOpen(filePath) { err := w.client.NotifyChange(ctx, filePath) if err != nil { @@ -680,7 +680,7 @@ func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, chan params := protocol.DidChangeWatchedFilesParams{ Changes: []protocol.FileEvent{ { - URI: protocol.DocumentUri(uri), + URI: protocol.DocumentURI(uri), Type: changeType, }, }, diff --git a/internal/tui/components/core/status/status.go b/internal/tui/components/core/status/status.go index b7339705649f24129dc61c28471f23044ba7dafb..59d873a94b0fc6713951b82caebd75a3a79a9623 100644 --- a/internal/tui/components/core/status/status.go +++ b/internal/tui/components/core/status/status.go @@ -6,7 +6,6 @@ import ( "github.com/charmbracelet/bubbles/v2/help" tea "github.com/charmbracelet/bubbletea/v2" - "github.com/charmbracelet/crush/internal/session" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" @@ -23,7 +22,6 @@ type statusCmp struct { info util.InfoMsg width int messageTTL time.Duration - session session.Session help help.Model keyMap help.KeyMap } diff --git a/internal/tui/components/logo/logo.go b/internal/tui/components/logo/logo.go index dbd3229e9b6c49b9f59b1a477fac9a5dc1c84d6e..195830632f1af0a681bb3075042a76a24d814155 100644 --- a/internal/tui/components/logo/logo.go +++ b/internal/tui/components/logo/logo.go @@ -233,42 +233,6 @@ func letterR(stretch bool) string { ) } -// letterS renders the letter S in a stylized way. It takes an integer that -// determines how many cells to stretch the letter. If the stretch is less than -// 1, it defaults to no stretching. -func letterS(stretch bool) string { - // Here's what we're making: - // - // ▄▀▀▀▀ - // ▀▀▀▄ - // ▀▀▀▀ - - left := heredoc.Doc(` - ▄ - - ▀ - `) - center := heredoc.Doc(` - ▀ - ▀ - ▀ - `) - right := heredoc.Doc(` - ▀ - ▄ - `) - return joinLetterform( - left, - stretchLetterformPart(center, letterformProps{ - stretch: stretch, - width: 3, - minStretch: 7, - maxStretch: 12, - }), - right, - ) -} - // letterSStylized renders the letter S in a stylized way, more so than // [letterS]. It takes an integer that determines how many cells to stretch the // letter. If the stretch is less than 1, it defaults to no stretching. diff --git a/internal/tui/exp/diffview/diffview.go b/internal/tui/exp/diffview/diffview.go index 1cb56a678f51d0809c584edc1bedd73befc59966..8bcb9b019a8769ee03b4de4cf53a6bccd6734774 100644 --- a/internal/tui/exp/diffview/diffview.go +++ b/internal/tui/exp/diffview/diffview.go @@ -9,7 +9,6 @@ import ( "github.com/alecthomas/chroma/v2" "github.com/alecthomas/chroma/v2/lexers" "github.com/aymanbagabas/go-udiff" - "github.com/aymanbagabas/go-udiff/myers" "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/x/ansi" ) @@ -210,7 +209,7 @@ func (dv *DiffView) computeDiff() error { return dv.err } dv.isComputed = true - dv.edits = myers.ComputeEdits( //nolint:staticcheck + dv.edits = udiff.Strings( dv.before.content, dv.after.content, ) diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden index 29845f3aad7de5830772ab61ff3cf0806da5510c..8658bf80ec430b0059df4411e6bccf338f2f5710 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden @@ -1,7 +1,7 @@  …  …  @@ -1,3 +1,3 @@    1    - a  - 2    - b  - 3    - c      1 + d  + 2    - b      2 + e  + 3    - c      3 + f  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden index 79f1ed7bcf7b9dde3bcf5858d7c4a92049e34792..5d41f8afc11d54173e68aad39e8d45c034b96fa0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden @@ -1,7 +1,7 @@  …  …  @@ -1,3 +1,3 @@    1    - a  - 2    - b  - 3    - c      1 + d  + 2    - b      2 + e  + 3    - c      3 + f  \ No newline at end of file diff --git a/internal/tui/exp/diffview/udiff_test.go b/internal/tui/exp/diffview/udiff_test.go index 400c5ba0cd143ec5398316f1910b884479cde2b7..7165ddfd32a37d256978611eb66d0823c289c725 100644 --- a/internal/tui/exp/diffview/udiff_test.go +++ b/internal/tui/exp/diffview/udiff_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/aymanbagabas/go-udiff" - "github.com/aymanbagabas/go-udiff/myers" "github.com/charmbracelet/x/exp/golden" ) @@ -39,7 +38,7 @@ func TestUdiff(t *testing.T) { t.Run("ToUnifiedDiff", func(t *testing.T) { toUnifiedDiff := func(t *testing.T, before, after string, contextLines int) udiff.UnifiedDiff { - edits := myers.ComputeEdits(before, after) //nolint:staticcheck + edits := udiff.Strings(before, after) unifiedDiff, err := udiff.ToUnifiedDiff("main.go", "main.go", before, edits, contextLines) if err != nil { t.Fatalf("ToUnifiedDiff failed: %v", err) diff --git a/internal/tui/exp/list/list.go b/internal/tui/exp/list/list.go index 0ba79c0d378df96c2f6e9938eb0b7e20ff802cd6..d2cb49d7ab09048e518dbff8ce55427d4a16dc75 100644 --- a/internal/tui/exp/list/list.go +++ b/internal/tui/exp/list/list.go @@ -21,8 +21,6 @@ type list struct { items []Item - renderedView string - // Filter options filterable bool filterPlaceholder string diff --git a/internal/tui/page/chat/chat.go b/internal/tui/page/chat/chat.go index 07fac7133a6003ad951962c8dd5ad55c52bcb67f..be7c0f2658202ea59e70778df1785b98310bc458 100644 --- a/internal/tui/page/chat/chat.go +++ b/internal/tui/page/chat/chat.go @@ -591,11 +591,11 @@ func (p *chatPage) Bindings() []key.Binding { return bindings } -func (a *chatPage) Help() help.KeyMap { +func (p *chatPage) Help() help.KeyMap { var shortList []key.Binding var fullList [][]key.Binding switch { - case a.isOnboarding && !a.splash.IsShowingAPIKey(): + case p.isOnboarding && !p.splash.IsShowingAPIKey(): shortList = append(shortList, // Choose model key.NewBinding( @@ -617,7 +617,7 @@ func (a *chatPage) Help() help.KeyMap { for _, v := range shortList { fullList = append(fullList, []key.Binding{v}) } - case a.isOnboarding && a.splash.IsShowingAPIKey(): + case p.isOnboarding && p.splash.IsShowingAPIKey(): shortList = append(shortList, // Go back key.NewBinding( @@ -634,7 +634,7 @@ func (a *chatPage) Help() help.KeyMap { for _, v := range shortList { fullList = append(fullList, []key.Binding{v}) } - case a.isProjectInit: + case p.isProjectInit: shortList = append(shortList, key.NewBinding( key.WithKeys("ctrl+c"), @@ -646,7 +646,7 @@ func (a *chatPage) Help() help.KeyMap { fullList = append(fullList, []key.Binding{v}) } default: - if a.editor.IsCompletionsOpen() { + if p.editor.IsCompletionsOpen() { shortList = append(shortList, key.NewBinding( key.WithKeys("tab", "enter"), @@ -666,12 +666,12 @@ func (a *chatPage) Help() help.KeyMap { } return core.NewSimpleHelp(shortList, fullList) } - if a.app.CoderAgent != nil && a.app.CoderAgent.IsBusy() { + if p.app.CoderAgent != nil && p.app.CoderAgent.IsBusy() { cancelBinding := key.NewBinding( key.WithKeys("esc"), key.WithHelp("esc", "cancel"), ) - if a.isCanceling { + if p.isCanceling { cancelBinding = key.NewBinding( key.WithKeys("esc"), key.WithHelp("esc", "press again to cancel"), @@ -686,12 +686,12 @@ func (a *chatPage) Help() help.KeyMap { } globalBindings := []key.Binding{} // we are in a session - if a.session.ID != "" { + if p.session.ID != "" { tabKey := key.NewBinding( key.WithKeys("tab"), key.WithHelp("tab", "focus chat"), ) - if a.focusedPane == PanelTypeChat { + if p.focusedPane == PanelTypeChat { tabKey = key.NewBinding( key.WithKeys("tab"), key.WithHelp("tab", "focus editor"), @@ -715,7 +715,7 @@ func (a *chatPage) Help() help.KeyMap { key.WithHelp("ctrl+s", "sessions"), ), ) - if a.session.ID != "" { + if p.session.ID != "" { globalBindings = append(globalBindings, key.NewBinding( key.WithKeys("ctrl+n"), @@ -728,7 +728,8 @@ func (a *chatPage) Help() help.KeyMap { ) fullList = append(fullList, globalBindings) - if a.focusedPane == PanelTypeChat { + switch p.focusedPane { + case PanelTypeChat: shortList = append(shortList, key.NewBinding( key.WithKeys("up", "down"), @@ -773,7 +774,7 @@ func (a *chatPage) Help() help.KeyMap { ), }, ) - } else if a.focusedPane == PanelTypeEditor { + case PanelTypeEditor: newLineBinding := key.NewBinding( key.WithKeys("shift+enter", "ctrl+j"), // "ctrl+j" is a common keybinding for newline in many editors. If @@ -781,7 +782,7 @@ func (a *chatPage) Help() help.KeyMap { // to reflect that. key.WithHelp("ctrl+j", "newline"), ) - if a.keyboardEnhancements.SupportsKeyDisambiguation() { + if p.keyboardEnhancements.SupportsKeyDisambiguation() { newLineBinding.SetHelp("shift+enter", newLineBinding.Help().Desc) } shortList = append(shortList, newLineBinding) diff --git a/internal/version/version.go b/internal/version/version.go index fc8b560c52b7c46c92909a30c2be269dd477de5c..0b616e122dcf4ffb3fbbf4cb7d3b8665300c23ef 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -3,6 +3,7 @@ package version import "runtime/debug" // Build-time parameters set via -ldflags + var Version = "unknown" // A user may install crush using `go install github.com/charmbracelet/crush@latest`.