on main help sign in
feat: add configurable timeout for LSP initialization (#2075)
ea8c39fhuaiyuWangh
internal/app/lsp.go+7−3
@@ -1,6 +1,7 @@
1package app
1package app
2
2
3import (
3import (
4+ "cmp"
4 "context"
5 "context"
5 "log/slog"
6 "log/slog"
6 "os/exec"
7 "os/exec"
@@ -69,7 +70,7 @@ func (app *App) initLSPClients(ctx context.Context) {
69 wg.Go(func() {
70 wg.Go(func() {
70 app.createAndStartLSPClient(
71 app.createAndStartLSPClient(
71 ctx, name,
72 ctx, name,
72− toOurConfig(server),
73+ toOurConfig(server, app.config.LSP[name]),
73 slices.Contains(userConfiguredLSPs, name),
74 slices.Contains(userConfiguredLSPs, name),
74 )
75 )
75 })
76 })
@@ -83,7 +84,9 @@ func (app *App) initLSPClients(ctx context.Context) {
83 }
84 }
84}
85}
85
86
87+// toOurConfig merges powernap default config with user config.
88+// If user config is zero value, it means no user override exists.
86−func toOurConfig(in *powernapconfig.ServerConfig) config.LSPConfig {
89+func toOurConfig(in *powernapconfig.ServerConfig, user config.LSPConfig) config.LSPConfig {
87 return config.LSPConfig{
90 return config.LSPConfig{
88 Command: in.Command,
91 Command: in.Command,
89 Args: in.Args,
92 Args: in.Args,
@@ -92,6 +95,7 @@ func toOurConfig(in *powernapconfig.ServerConfig) config.LSPConfig {
92 RootMarkers: in.RootMarkers,
95 RootMarkers: in.RootMarkers,
93 InitOptions: in.InitOptions,
96 InitOptions: in.InitOptions,
94 Options: in.Settings,
97 Options: in.Settings,
98+ Timeout: user.Timeout,
95 }
99 }
96}
100}
97
101
@@ -126,7 +130,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, config
126 lspClient.SetDiagnosticsCallback(updateLSPDiagnostics)
130 lspClient.SetDiagnosticsCallback(updateLSPDiagnostics)
127
131
128 // Increase initialization timeout as some servers take more time to start.
132 // Increase initialization timeout as some servers take more time to start.
129− initCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
133+ initCtx, cancel := context.WithTimeout(ctx, time.Duration(cmp.Or(config.Timeout, 30))*time.Second)
130 defer cancel()
134 defer cancel()
131
135
132 // Initialize LSP client.
136 // Initialize LSP client.
internal/config/config.go+1
@@ -194,6 +194,7 @@ type LSPConfig struct {
194 RootMarkers []string `json:"root_markers,omitempty" jsonschema:"description=Files or directories that indicate the project root,example=go.mod,example=package.json,example=Cargo.toml"`
194 RootMarkers []string `json:"root_markers,omitempty" jsonschema:"description=Files or directories that indicate the project root,example=go.mod,example=package.json,example=Cargo.toml"`
195 InitOptions map[string]any `json:"init_options,omitempty" jsonschema:"description=Initialization options passed to the LSP server during initialize request"`
195 InitOptions map[string]any `json:"init_options,omitempty" jsonschema:"description=Initialization options passed to the LSP server during initialize request"`
196 Options map[string]any `json:"options,omitempty" jsonschema:"description=LSP server-specific settings passed during initialization"`
196 Options map[string]any `json:"options,omitempty" jsonschema:"description=LSP server-specific settings passed during initialization"`
197+ Timeout int `json:"timeout,omitempty" jsonschema:"description=Timeout in seconds for LSP server initialization,default=30,example=60,example=120"`
197}
198}
198
199
199type TUIOptions struct {
200type TUIOptions struct {
schema.json+9
@@ -156,6 +156,15 @@
156 "options": {
156 "options": {
157 "type": "object",
157 "type": "object",
158 "description": "LSP server-specific settings passed during initialization"
158 "description": "LSP server-specific settings passed during initialization"
159+ },
160+ "timeout": {
161+ "type": "integer",
162+ "description": "Timeout in seconds for LSP server initialization",
163+ "default": 30,
164+ "examples": [
165+ 60,
166+ 120
167+ ]
159 }
168 }
160 },
169 },
161 "additionalProperties": false,
170 "additionalProperties": false,