Skip to content

Commit c9d8c2f

Browse files
Merge pull request #304 from mcecode/deleted-file-diagnostics
feat(harper-ls): remove deleted file/s diagnostics
2 parents 448ff91 + 19977c2 commit c9d8c2f

File tree

2 files changed

+97
-7
lines changed

2 files changed

+97
-7
lines changed

harper-ls/src/backend.rs

+60-5
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@ use tower_lsp::lsp_types::notification::PublishDiagnostics;
1818
use tower_lsp::lsp_types::{
1919
CodeActionOrCommand, CodeActionParams, CodeActionProviderCapability, CodeActionResponse,
2020
Command, ConfigurationItem, Diagnostic, DidChangeConfigurationParams,
21-
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
22-
DidSaveTextDocumentParams, ExecuteCommandOptions, ExecuteCommandParams, InitializeParams,
21+
DidChangeTextDocumentParams, DidChangeWatchedFilesParams,
22+
DidChangeWatchedFilesRegistrationOptions, DidCloseTextDocumentParams,
23+
DidOpenTextDocumentParams, DidSaveTextDocumentParams, ExecuteCommandOptions,
24+
ExecuteCommandParams, FileChangeType, FileSystemWatcher, GlobPattern, InitializeParams,
2325
InitializeResult, InitializedParams, MessageType, PublishDiagnosticsParams, Range,
24-
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
25-
TextDocumentSyncSaveOptions, Url,
26+
Registration, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
27+
TextDocumentSyncOptions, TextDocumentSyncSaveOptions, Url, WatchKind,
2628
};
2729
use tower_lsp::{Client, LanguageServer};
28-
use tracing::{error, info};
30+
use tracing::{error, info, warn};
2931

3032
use crate::config::Config;
3133
use crate::diagnostics::{lint_to_code_actions, lints_to_diagnostics};
@@ -372,6 +374,27 @@ impl LanguageServer for Backend {
372374
.await;
373375

374376
self.pull_config().await;
377+
378+
let did_change_watched_files = Registration {
379+
id: "workspace/didChangeWatchedFiles".to_owned(),
380+
method: "workspace/didChangeWatchedFiles".to_owned(),
381+
register_options: Some(
382+
serde_json::to_value(DidChangeWatchedFilesRegistrationOptions {
383+
watchers: vec![FileSystemWatcher {
384+
glob_pattern: GlobPattern::String("**/*".to_owned()),
385+
kind: Some(WatchKind::Delete),
386+
}],
387+
})
388+
.unwrap(),
389+
),
390+
};
391+
if let Err(err) = self
392+
.client
393+
.register_capability(vec![did_change_watched_files])
394+
.await
395+
{
396+
warn!("Unable to register watch file capability: {}", err);
397+
}
375398
}
376399

377400
async fn did_save(&self, params: DidSaveTextDocumentParams) {
@@ -411,6 +434,38 @@ impl LanguageServer for Backend {
411434

412435
async fn did_close(&self, _params: DidCloseTextDocumentParams) {}
413436

437+
async fn did_change_watched_files(&self, params: DidChangeWatchedFilesParams) {
438+
let mut doc_lock = self.doc_state.lock().await;
439+
let mut urls_to_clear = Vec::new();
440+
441+
for change in &params.changes {
442+
if change.typ != FileChangeType::DELETED {
443+
continue;
444+
}
445+
446+
doc_lock.retain(|url, _| {
447+
// `change.uri` could be a directory so use `starts_with` instead of `==`.
448+
let to_remove = url.as_str().starts_with(change.uri.as_str());
449+
450+
if to_remove {
451+
urls_to_clear.push(url.clone());
452+
}
453+
454+
!to_remove
455+
});
456+
}
457+
458+
for url in &urls_to_clear {
459+
self.client
460+
.send_notification::<PublishDiagnostics>(PublishDiagnosticsParams {
461+
uri: url.clone(),
462+
diagnostics: vec![],
463+
version: None,
464+
})
465+
.await;
466+
}
467+
}
468+
414469
async fn execute_command(&self, params: ExecuteCommandParams) -> Result<Option<Value>> {
415470
let mut string_args = params
416471
.arguments

packages/vscode-plugin/src/tests/suite/integration.test.ts

+37-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Extension } from 'vscode';
22

3-
import { ConfigurationTarget, Uri, workspace } from 'vscode';
3+
import { commands, ConfigurationTarget, Uri, workspace } from 'vscode';
44

55
import {
66
activateHarper,
@@ -48,7 +48,7 @@ describe('Integration >', () => {
4848
const config = workspace.getConfiguration('harper-ls.linters');
4949
await config.update('repeated_words', false, ConfigurationTarget.Workspace);
5050
// Wait for `harper-ls` to update diagnostics
51-
await sleep(250);
51+
await sleep(300);
5252

5353
compareActualVsExpectedDiagnostics(
5454
getActualDiagnostics(markdownUri),
@@ -61,4 +61,39 @@ describe('Integration >', () => {
6161
// Set config back to default value
6262
await config.update('repeated_words', true, ConfigurationTarget.Workspace);
6363
});
64+
65+
it('updates diagnostics when files are deleted', async () => {
66+
const markdownContent = await workspace.fs.readFile(markdownUri);
67+
68+
// Delete file through VSCode
69+
await commands.executeCommand('workbench.files.action.showActiveFileInExplorer');
70+
await commands.executeCommand('deleteFile');
71+
// Wait for `harper-ls` to update diagnostics
72+
await sleep(450);
73+
74+
compareActualVsExpectedDiagnostics(
75+
getActualDiagnostics(markdownUri),
76+
createExpectedDiagnostics()
77+
);
78+
79+
// Restore and reopen deleted file
80+
await workspace.fs.writeFile(markdownUri, markdownContent);
81+
await openFile('integration.md');
82+
// Wait for `harper-ls` to update diagnostics
83+
await sleep(75);
84+
85+
// Delete file directly
86+
await workspace.fs.delete(markdownUri);
87+
// Wait for `harper-ls` to update diagnostics
88+
await sleep(450);
89+
90+
compareActualVsExpectedDiagnostics(
91+
getActualDiagnostics(markdownUri),
92+
createExpectedDiagnostics()
93+
);
94+
95+
// Restore and reopen deleted file
96+
await workspace.fs.writeFile(markdownUri, markdownContent);
97+
await openFile('integration.md');
98+
});
6499
});

0 commit comments

Comments
 (0)