Skip to content

Commit bb7728a

Browse files
committed
Index: track off-editor file changes via didChangeWatchedFiles
The cross-index previously only learned about changes through open documents -- files created, changed, or deleted outside the editor (git pull, code generators) went stale until a server restart. Now: - client.js registers file watchers for **/*.{lpc,c,h} and the driver config spots (config, config.*, *.cfg, *.conf), forwarding events to the server. - The server's onDidChangeWatchedFiles re-indexes changed/created files from disk (open documents stay authoritative via their live buffers), removes deleted ones, and clears the driver-config discovery cache when a config-looking path changes -- a config appearing mid-session is picked up without a restart. - indexer.updateFromDisk() drops the mtime short-circuit so a watched change always re-reads. Harness: create a file on disk (never opened) -> notify -> it serves workspace/symbol; delete -> notify -> it's gone. Both green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AXqX4Kf55ArA39suS9cdCv
1 parent a3da145 commit bb7728a

4 files changed

Lines changed: 56 additions & 1 deletion

File tree

extension/client.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,15 @@ async function start(ctx) {
2929
},
3030
{
3131
documentSelector: [{ language: 'lpc' }],
32-
synchronize: { configurationSection: 'lpc' },
32+
synchronize: {
33+
configurationSection: 'lpc',
34+
// Off-editor changes (git pull, generators): keeps the workspace
35+
// cross-index fresh and re-triggers driver-config discovery.
36+
fileEvents: [
37+
vscode.workspace.createFileSystemWatcher('**/*.{lpc,c,h}'),
38+
vscode.workspace.createFileSystemWatcher('**/{config,config.*,*.cfg,*.conf}'),
39+
],
40+
},
3341
initializationOptions: {
3442
settings: vscode.workspace.getConfiguration('lpc'),
3543
},

extension/server/indexer.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ function createIndex({ tokenize, outline }) {
8383
if (roots.length > 0 && !roots.some((r) => abs.startsWith(r + path.sep))) return;
8484
indexText(abs, text, Date.now());
8585
},
86+
// Re-index one file from disk (didChangeWatchedFiles: files changed
87+
// OUTSIDE the editor -- git pull, generators).
88+
updateFromDisk(abs) {
89+
if (roots.length > 0 && !roots.some((r) => abs.startsWith(r + path.sep))) return;
90+
if (!/\.(lpc|c|h)$/.test(abs)) return;
91+
files.delete(abs); // drop the mtime short-circuit: always re-read
92+
indexFile(abs);
93+
},
8694
remove(abs) { files.delete(abs); },
8795

8896
// name -> [{file, kind, name, line, col}] (tokenizer 1-based positions

extension/server/main.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,25 @@ connection.onInitialize((params) => {
620620

621621
connection.onInitialized(() => startIndex());
622622

623+
// Files changed OUTSIDE the editor (git pull, generators, deletes). The VS
624+
// Code client watches **/*.{lpc,c,h} plus driver-config spots; other
625+
// clients can send the same notification.
626+
connection.onDidChangeWatchedFiles((params) => {
627+
for (const change of params.changes || []) {
628+
let abs;
629+
try { abs = fileURLToPath(change.uri); } catch (_e) { continue; }
630+
// A driver config appearing/changing invalidates discovery.
631+
if (/(^|[\\/])(config[^\\/]*|[^\\/]+\.(cfg|conf))$/i.test(abs)) configDiscovery.clear();
632+
if (!index) continue;
633+
if (change.type === 3 /* Deleted */) {
634+
index.remove(abs);
635+
} else if (!documents.get(pathToFileURL(abs).href)) {
636+
// open documents are already authoritative via reindexDoc
637+
index.updateFromDisk(abs);
638+
}
639+
}
640+
});
641+
623642
connection.onDidChangeConfiguration((change) => {
624643
settings = (change.settings && change.settings.lpc) || {};
625644
configDiscovery.clear();

scripts/test-lsp.mjs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,26 @@ const wsym = await request('workspace/symbol', { query: 'util_f' });
295295
check('workspace/symbol: substring search over the index',
296296
wsym && wsym.some((s) => s.name === 'util_fn' && s.location.uri === utilUri));
297297

298+
// watched-files: a file created OUTSIDE the editor enters the index...
299+
const latePath = path.join(mudlib, 'lib', 'late.lpc');
300+
fs.writeFileSync(latePath, 'int late_fn() { return 9; }\n');
301+
notify('workspace/didChangeWatchedFiles', {
302+
changes: [{ uri: pathToFileURL(latePath).href, type: 1 }],
303+
});
304+
await new Promise((r) => setTimeout(r, 200));
305+
const lateSym = await request('workspace/symbol', { query: 'late_fn' });
306+
check('watched files: off-editor create is indexed',
307+
lateSym && lateSym.some((s) => s.name === 'late_fn'));
308+
// ... and an off-editor delete leaves the index
309+
fs.unlinkSync(latePath);
310+
notify('workspace/didChangeWatchedFiles', {
311+
changes: [{ uri: pathToFileURL(latePath).href, type: 3 }],
312+
});
313+
await new Promise((r) => setTimeout(r, 200));
314+
const goneSym = await request('workspace/symbol', { query: 'late_fn' });
315+
check('watched files: off-editor delete leaves the index',
316+
goneSym && !goneSym.some((s) => s.name === 'late_fn'));
317+
298318
const comp = await request('textDocument/completion', {
299319
textDocument: { uri: sampleUri }, position: { line: greetUse, character: 2 },
300320
});

0 commit comments

Comments
 (0)