fix(watcher): close deleted opened documents
This commit is contained in:
@@ -5,8 +5,9 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as net from "node:net";
|
||||
import * as path from "node:path";
|
||||
import type { FileSystemWatcher } from "vscode-languageserver-protocol";
|
||||
import { LspClient } from "./client.ts";
|
||||
import { findRoot, findServerById, pathToUri } from "./root.ts";
|
||||
import { findRoot, findServerById, pathToUri, uriToPath } from "./root.ts";
|
||||
import type { ServerConfig } from "./types.ts";
|
||||
import { WorkspaceWatcher, type FileEvent } from "./watcher.ts";
|
||||
import {
|
||||
@@ -21,6 +22,7 @@ import {
|
||||
const DEFAULT_IDLE_TTL_MS = 5 * 60 * 1000;
|
||||
const WATCHER_READY_TIMEOUT_MS = 5000;
|
||||
const FILE_CHANGE_DELETED = 3;
|
||||
const WATCH_KIND_DELETE = 4;
|
||||
|
||||
// Client Entry - One LspClient per (server.id, rootDir), plus the bookkeeping
|
||||
// needed to keep files in sync and evict on idleness.
|
||||
@@ -110,23 +112,34 @@ async function getOrCreateEntry(
|
||||
// Attach Watcher - Registration can happen during initialize, before the daemon subscribes.
|
||||
async function attachWatcher(entry: ClientEntry): Promise<void> {
|
||||
if (process.env.PI_LSP_DISABLE_WATCHERS) return;
|
||||
const sync = async () => {
|
||||
const patterns = entry.client.getFileWatchers();
|
||||
if (patterns.length === 0 && !entry.watcher) return;
|
||||
if (!entry.watcher) {
|
||||
entry.watcher = new WorkspaceWatcher(entry.rootDir, (events) =>
|
||||
forwardEvents(entry, events),
|
||||
);
|
||||
log(`watcher`, entry.server.id, entry.rootDir, `patterns=${patterns.length}`);
|
||||
}
|
||||
if (process.env.LSP_DEBUG) {
|
||||
log(`watcher patterns`, entry.server.id, JSON.stringify(patterns));
|
||||
}
|
||||
entry.watcher.setPatterns(patterns);
|
||||
if (patterns.length > 0) await waitForWatcherReady(entry);
|
||||
};
|
||||
entry.unsubscribeWatchers = entry.client.onWatchersChanged(() => void sync());
|
||||
await sync();
|
||||
entry.unsubscribeWatchers = entry.client.onWatchersChanged(() => void refreshWatcher(entry));
|
||||
await refreshWatcher(entry);
|
||||
}
|
||||
|
||||
function watcherPatterns(entry: ClientEntry): FileSystemWatcher[] {
|
||||
const registered = entry.client.getFileWatchers();
|
||||
const openedDeletes = [...entry.opened.keys()].map((uri) => ({
|
||||
globPattern: uriToPath(uri).split(path.sep).join("/"),
|
||||
kind: WATCH_KIND_DELETE,
|
||||
}));
|
||||
return [...registered, ...openedDeletes];
|
||||
}
|
||||
|
||||
async function refreshWatcher(entry: ClientEntry): Promise<void> {
|
||||
if (process.env.PI_LSP_DISABLE_WATCHERS) return;
|
||||
const patterns = watcherPatterns(entry);
|
||||
if (patterns.length === 0 && !entry.watcher) return;
|
||||
if (!entry.watcher) {
|
||||
entry.watcher = new WorkspaceWatcher(entry.rootDir, (events) =>
|
||||
forwardEvents(entry, events),
|
||||
);
|
||||
log(`watcher`, entry.server.id, entry.rootDir, `patterns=${patterns.length}`);
|
||||
}
|
||||
if (process.env.LSP_DEBUG) {
|
||||
log(`watcher patterns`, entry.server.id, JSON.stringify(patterns));
|
||||
}
|
||||
entry.watcher.setPatterns(patterns);
|
||||
if (patterns.length > 0) await waitForWatcherReady(entry);
|
||||
}
|
||||
|
||||
async function waitForWatcherReady(entry: ClientEntry): Promise<void> {
|
||||
@@ -157,6 +170,7 @@ function forwardEvents(entry: ClientEntry, events: FileEvent[]): void {
|
||||
if (event.type !== FILE_CHANGE_DELETED || !entry.opened.has(event.uri)) continue;
|
||||
entry.client.closeDocument(event.uri);
|
||||
entry.opened.delete(event.uri);
|
||||
void refreshWatcher(entry);
|
||||
}
|
||||
if (process.env.LSP_DEBUG) {
|
||||
log(`watcher fire`, entry.server.id, JSON.stringify(events));
|
||||
@@ -206,6 +220,7 @@ async function syncFile(
|
||||
if (prev === undefined) {
|
||||
entry.client.openDocument(filePath);
|
||||
entry.opened.set(uri, stat.mtimeMs);
|
||||
await refreshWatcher(entry);
|
||||
return { uri, changed: true };
|
||||
} else if (prev !== stat.mtimeMs) {
|
||||
entry.client.notifyChange(filePath);
|
||||
|
||||
Reference in New Issue
Block a user