Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.

Commit 3aef4de

Browse files
kujtimiihoxhatermai
andcommitted
Improve LSP diagnostics handling for file operations
- Split LSP file notification into separate functions - Add waitForLspDiagnostics function to wait for diagnostics after file changes - Move LSP diagnostics to after file operations in edit and write tools - Fix string splitting in diff generation - Reduce diagnostics timeout from 10 to 5 seconds 🤖 Generated with termai Co-Authored-By: termai <noreply@termai.io>
1 parent a1f6147 commit 3aef4de

File tree

3 files changed

+38
-12
lines changed

3 files changed

+38
-12
lines changed

internal/llm/tools/diagnostics.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func (b *diagnosticsTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
5353

5454
if params.FilePath != "" {
5555
notifyLspOpenFile(ctx, params.FilePath, lsps)
56+
waitForLspDiagnostics(ctx, params.FilePath, lsps)
5657
}
5758

5859
output := appendDiagnostics(params.FilePath, lsps)
@@ -61,6 +62,22 @@ func (b *diagnosticsTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
6162
}
6263

6364
func notifyLspOpenFile(ctx context.Context, filePath string, lsps map[string]*lsp.Client) {
65+
for _, client := range lsps {
66+
// Open the file
67+
err := client.OpenFile(ctx, filePath)
68+
if err != nil {
69+
// If there's an error opening the file, continue to the next client
70+
continue
71+
}
72+
}
73+
}
74+
75+
// waitForLspDiagnostics opens a file in LSP clients and waits for diagnostics to be published
76+
func waitForLspDiagnostics(ctx context.Context, filePath string, lsps map[string]*lsp.Client) {
77+
if len(lsps) == 0 {
78+
return
79+
}
80+
6481
// Create a channel to receive diagnostic notifications
6582
diagChan := make(chan struct{}, 1)
6683

@@ -92,19 +109,26 @@ func notifyLspOpenFile(ctx context.Context, filePath string, lsps map[string]*ls
92109
// Register our temporary handler
93110
client.RegisterNotificationHandler("textDocument/publishDiagnostics", handler)
94111

95-
// Open the file
96-
err := client.OpenFile(ctx, filePath)
97-
if err != nil {
98-
// If there's an error opening the file, continue to the next client
99-
continue
112+
// Notify change if the file is already open
113+
if client.IsFileOpen(filePath) {
114+
err := client.NotifyChange(ctx, filePath)
115+
if err != nil {
116+
continue
117+
}
118+
} else {
119+
// Open the file if it's not already open
120+
err := client.OpenFile(ctx, filePath)
121+
if err != nil {
122+
continue
123+
}
100124
}
101125
}
102126

103127
// Wait for diagnostics with a reasonable timeout
104128
select {
105129
case <-diagChan:
106130
// Diagnostics received
107-
case <-time.After(10 * time.Second):
131+
case <-time.After(5 * time.Second):
108132
// Timeout after 5 seconds - this is a fallback in case no diagnostics are published
109133
case <-ctx.Done():
110134
// Context cancelled

internal/llm/tools/edit.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ func (e *editTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
7474
params.FilePath = filepath.Join(wd, params.FilePath)
7575
}
7676

77-
notifyLspOpenFile(ctx, params.FilePath, e.lspClients)
7877
if params.OldString == "" {
7978
result, err := createNewFile(params.FilePath, params.NewString)
8079
if err != nil {
@@ -96,6 +95,8 @@ func (e *editTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
9695
return NewTextErrorResponse(fmt.Sprintf("error replacing content: %s", err)), nil
9796
}
9897

98+
// Wait for LSP diagnostics after editing the file
99+
waitForLspDiagnostics(ctx, params.FilePath, e.lspClients)
99100
result = fmt.Sprintf("<result>\n%s\n</result>\n", result)
100101
result += appendDiagnostics(params.FilePath, e.lspClients)
101102
return NewTextResponse(result), nil
@@ -303,23 +304,23 @@ func GenerateDiff(oldContent, newContent string) string {
303304
diffs = dmp.DiffCharsToLines(diffs, dmpStrings)
304305
diffs = dmp.DiffCleanupSemantic(diffs)
305306
buff := strings.Builder{}
306-
307+
307308
// Add a header to make the diff more readable
308309
buff.WriteString("Changes:\n")
309-
310+
310311
for _, diff := range diffs {
311312
text := diff.Text
312313

313314
switch diff.Type {
314315
case diffmatchpatch.DiffInsert:
315-
for _, line := range strings.Split(text, "\n") {
316+
for line := range strings.SplitSeq(text, "\n") {
316317
if line == "" {
317318
continue
318319
}
319320
_, _ = buff.WriteString("+ " + line + "\n")
320321
}
321322
case diffmatchpatch.DiffDelete:
322-
for _, line := range strings.Split(text, "\n") {
323+
for line := range strings.SplitSeq(text, "\n") {
323324
if line == "" {
324325
continue
325326
}

internal/llm/tools/write.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
100100
return NewTextErrorResponse(fmt.Sprintf("Failed to create parent directories: %s", err)), nil
101101
}
102102

103-
notifyLspOpenFile(ctx, filePath, w.lspClients)
104103
// Get old content for diff if file exists
105104
oldContent := ""
106105
if fileInfo != nil && !fileInfo.IsDir() {
@@ -135,6 +134,8 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
135134
// Record the file write
136135
recordFileWrite(filePath)
137136
recordFileRead(filePath)
137+
// Wait for LSP diagnostics after writing the file
138+
waitForLspDiagnostics(ctx, filePath, w.lspClients)
138139

139140
result := fmt.Sprintf("File successfully written: %s", filePath)
140141
result = fmt.Sprintf("<result>\n%s\n</result>", result)

0 commit comments

Comments
 (0)