Skip to content

Commit 56cda50

Browse files
committed
update file watcher to keep files open
1 parent 055ce1b commit 56cda50

File tree

12 files changed

+262
-124
lines changed

12 files changed

+262
-124
lines changed

cmd/test-lsp/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/isaacphi/mcp-language-server/internal/lsp"
1414
"github.com/isaacphi/mcp-language-server/internal/tools"
15+
"github.com/isaacphi/mcp-language-server/internal/watcher"
1516
)
1617

1718
type config struct {
@@ -73,6 +74,8 @@ func main() {
7374
defer client.Close()
7475

7576
ctx := context.Background()
77+
workspaceWatcher := watcher.NewWorkspaceWatcher(client)
78+
7679
initResult, err := client.InitializeLSPClient(ctx, cfg.workspaceDir)
7780
if err != nil {
7881
log.Fatalf("Initialize failed: %v", err)
@@ -83,6 +86,9 @@ func main() {
8386
log.Fatalf("Server failed to become ready: %v", err)
8487
}
8588

89+
go workspaceWatcher.WatchWorkspace(ctx, cfg.workspaceDir)
90+
time.Sleep(3 * time.Second)
91+
8692
///////////////////////////////////////////////////////////////////////////
8793
// Test Tools
8894
response, err := tools.ReadDefinition(ctx, client, cfg.keyword, true)

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ go 1.24.0
55
require (
66
github.com/fsnotify/fsnotify v1.8.0
77
github.com/metoro-io/mcp-golang v0.6.0
8-
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
98
golang.org/x/text v0.21.0
109
)
1110

@@ -16,6 +15,7 @@ require (
1615
github.com/bahlo/generic-list-go v0.2.0 // indirect
1716
github.com/buger/jsonparser v1.1.1 // indirect
1817
github.com/invopop/jsonschema v0.13.0 // indirect
18+
github.com/kisielk/errcheck v1.9.0 // indirect
1919
github.com/mailru/easyjson v0.9.0 // indirect
2020
github.com/pkg/errors v0.9.1 // indirect
2121
github.com/tidwall/gjson v1.18.0 // indirect
@@ -35,6 +35,7 @@ require (
3535
)
3636

3737
tool (
38+
github.com/kisielk/errcheck
3839
golang.org/x/vuln/cmd/govulncheck
3940
honnef.co/go/tools/cmd/staticcheck
4041
)

go.sum

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
44
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
55
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
66
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
7-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
87
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
98
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
109
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
@@ -19,16 +18,14 @@ github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcI
1918
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
2019
github.com/isaacphi/mcp-golang v0.0.0-20250314121746-948e874f9887 h1:mwj41iKcwcR67wBt/fszrEJtGwuGSmSHcjC6u4ZEHdE=
2120
github.com/isaacphi/mcp-golang v0.0.0-20250314121746-948e874f9887/go.mod h1:ifLP9ZzKpN1UqFWNTpAHOqSvNkMK6b7d1FSZ5Lu0lN0=
21+
github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M=
22+
github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8=
2223
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
2324
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
2425
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
2526
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
2627
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2728
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
28-
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
29-
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
30-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
31-
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
3229
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
3330
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
3431
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -61,7 +58,6 @@ golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
6158
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
6259
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
6360
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
64-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6561
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
6662
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6763
honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI=

internal/lsp/client.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,24 @@ func (c *Client) InitializeLSPClient(ctx context.Context, workspaceDir string) (
218218
path := strings.ToLower(c.Cmd.Path)
219219
switch {
220220
case strings.Contains(path, "typescript-language-server"):
221-
err := initializeTypescriptLanguageServer(ctx, c, workspaceDir)
222-
if err != nil {
223-
return nil, err
224-
}
221+
// err := initializeTypescriptLanguageServer(ctx, c, workspaceDir)
222+
// if err != nil {
223+
// return nil, err
224+
// }
225225
}
226226

227227
return &result, nil
228228
}
229229

230230
func (c *Client) Close() error {
231-
// Close stdin first to signal the server
231+
// Try to close all open files first
232+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
233+
defer cancel()
234+
235+
// Attempt to close files but continue shutdown regardless
236+
c.CloseAllFiles(ctx)
237+
238+
// Close stdin to signal the server
232239
if err := c.stdin.Close(); err != nil {
233240
return fmt.Errorf("failed to close stdin: %w", err)
234241
}
@@ -281,6 +288,7 @@ func (c *Client) OpenFile(ctx context.Context, filepath string) error {
281288
}
282289
c.openFilesMu.Unlock()
283290

291+
// Skip files that do not exist or cannot be read
284292
content, err := os.ReadFile(filepath)
285293
if err != nil {
286294
return fmt.Errorf("error reading file: %w", err)
@@ -306,6 +314,10 @@ func (c *Client) OpenFile(ctx context.Context, filepath string) error {
306314
}
307315
c.openFilesMu.Unlock()
308316

317+
if debug {
318+
log.Printf("Opened file: %s", filepath)
319+
}
320+
309321
return nil
310322
}
311323

@@ -383,6 +395,32 @@ func (c *Client) IsFileOpen(filepath string) bool {
383395
return exists
384396
}
385397

398+
// CloseAllFiles closes all currently open files
399+
func (c *Client) CloseAllFiles(ctx context.Context) {
400+
c.openFilesMu.Lock()
401+
filesToClose := make([]string, 0, len(c.openFiles))
402+
403+
// First collect all URIs that need to be closed
404+
for uri := range c.openFiles {
405+
// Convert URI back to file path by trimming "file://" prefix
406+
filePath := strings.TrimPrefix(uri, "file://")
407+
filesToClose = append(filesToClose, filePath)
408+
}
409+
c.openFilesMu.Unlock()
410+
411+
// Then close them all
412+
for _, filePath := range filesToClose {
413+
err := c.CloseFile(ctx, filePath)
414+
if err != nil && debug {
415+
log.Printf("Error closing file %s: %v", filePath, err)
416+
}
417+
}
418+
419+
if debug {
420+
log.Printf("Closed %d files", len(filesToClose))
421+
}
422+
}
423+
386424
func (c *Client) GetFileDiagnostics(uri protocol.DocumentUri) []protocol.Diagnostic {
387425
c.diagnosticsMu.RLock()
388426
defer c.diagnosticsMu.RUnlock()

internal/lsp/initializeTypescriptLanguageServer.go

Lines changed: 0 additions & 64 deletions
This file was deleted.

internal/tools/apply-text-edit.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7-
"log"
87
"os"
98
"sort"
109
"strings"
@@ -34,11 +33,6 @@ func ApplyTextEdits(ctx context.Context, client *lsp.Client, filePath string, ed
3433
if err != nil {
3534
return "", fmt.Errorf("could not open file: %v", err)
3635
}
37-
defer func() {
38-
if err := client.CloseFile(ctx, filePath); err != nil {
39-
log.Printf("Could not close file: %v", err)
40-
}
41-
}()
4236

4337
// Sort edits by line number in descending order to process from bottom to top
4438
// This way line numbers don't shift under us as we make edits

internal/tools/diagnostics.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ func GetDiagnosticsForFile(ctx context.Context, client *lsp.Client, filePath str
1818
if err != nil {
1919
return "", fmt.Errorf("could not open file: %v", err)
2020
}
21-
defer func() {
22-
if err := client.CloseFile(ctx, filePath); err != nil {
23-
log.Printf("Could not close file: %v", err)
24-
}
25-
}()
2621

2722
// Wait for diagnostics
2823
// TODO: wait for notification

internal/tools/execute-codelens.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package tools
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"time"
87

98
"github.com/isaacphi/mcp-language-server/internal/lsp"
@@ -17,11 +16,7 @@ func ExecuteCodeLens(ctx context.Context, client *lsp.Client, filePath string, i
1716
if err != nil {
1817
return "", fmt.Errorf("could not open file: %v", err)
1918
}
20-
defer func() {
21-
if err := client.CloseFile(ctx, filePath); err != nil {
22-
log.Printf("Could not close file: %v", err)
23-
}
24-
}()
19+
// TODO: find a more appropriate way to wait
2520
time.Sleep(time.Second)
2621

2722
// Get code lenses

internal/tools/get-codelens.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package tools
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"strings"
87
"time"
98

@@ -17,11 +16,7 @@ func GetCodeLens(ctx context.Context, client *lsp.Client, filePath string) (stri
1716
if err != nil {
1817
return "", fmt.Errorf("could not open file: %v", err)
1918
}
20-
defer func() {
21-
if err := client.CloseFile(ctx, filePath); err != nil {
22-
log.Printf("Could not close file: %v", err)
23-
}
24-
}()
19+
// TODO: find a more appropriate way to wait
2520
time.Sleep(time.Second)
2621

2722
// Create document identifier

0 commit comments

Comments
 (0)