-
Notifications
You must be signed in to change notification settings - Fork 113
/
config-file-watcher.ts
113 lines (100 loc) · 3.86 KB
/
config-file-watcher.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import * as vscode from 'vscode';
import * as vscodelc from 'vscode-languageclient/node';
import {ClangdContext} from './clangd-context';
import * as config from './config';
export function activate(context: ClangdContext) {
if (config.get<string>('onConfigChanged') !== 'ignore') {
context.client.registerFeature(new ConfigFileWatcherFeature(context));
}
}
// Clangd extension capabilities.
interface ClangdClientCapabilities {
compilationDatabase?: {automaticReload?: boolean;},
}
class ConfigFileWatcherFeature implements vscodelc.StaticFeature {
constructor(private context: ClangdContext) {}
fillClientCapabilities(capabilities: vscodelc.ClientCapabilities) {}
initialize(capabilities: vscodelc.ServerCapabilities,
_documentSelector: vscodelc.DocumentSelector|undefined) {
if ((capabilities as ClangdClientCapabilities)
.compilationDatabase?.automaticReload)
return;
this.context.subscriptions.push(new ConfigFileWatcher(this.context));
}
getState(): vscodelc.FeatureState { return {kind: 'static'}; }
dispose() {}
}
class ConfigFileWatcher implements vscode.Disposable {
private databaseWatcher?: vscode.FileSystemWatcher;
private debounceTimer?: NodeJS.Timer;
dispose() {
if (this.databaseWatcher)
this.databaseWatcher.dispose();
}
constructor(private context: ClangdContext) {
this.createFileSystemWatcher();
context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(
() => { this.createFileSystemWatcher(); }));
}
createFileSystemWatcher() {
if (this.databaseWatcher)
this.databaseWatcher.dispose();
if (vscode.workspace.workspaceFolders) {
this.databaseWatcher = vscode.workspace.createFileSystemWatcher(
'{' +
vscode.workspace.workspaceFolders.map(f => f.uri.fsPath).join(',') +
'}/{build/compile_commands.json,compile_commands.json,compile_flags.txt}');
this.context.subscriptions.push(this.databaseWatcher.onDidChange(
this.debouncedHandleConfigFilesChanged.bind(this)));
this.context.subscriptions.push(this.databaseWatcher.onDidCreate(
this.debouncedHandleConfigFilesChanged.bind(this)));
this.context.subscriptions.push(this.databaseWatcher);
}
}
async debouncedHandleConfigFilesChanged(uri: vscode.Uri) {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(async () => {
await this.handleConfigFilesChanged(uri);
this.debounceTimer = undefined;
}, 2000);
}
async handleConfigFilesChanged(uri: vscode.Uri) {
// Sometimes the tools that generate the compilation database, before
// writing to it, they create a new empty file or they clear the existing
// one, and after the compilation they write the new content. In this cases
// the server is not supposed to restart
if ((await vscode.workspace.fs.stat(uri)).size <= 0)
return;
switch (config.get<string>('onConfigChanged')) {
case 'restart':
vscode.commands.executeCommand('clangd.restart');
break;
case 'ignore':
break;
case 'prompt':
default:
switch (await vscode.window.showInformationMessage(
`Clangd configuration file at '${
uri.fsPath}' has been changed. Do you want to restart it?`,
'Yes', 'Yes, always', 'No, never')) {
case 'Yes':
vscode.commands.executeCommand('clangd.restart');
break;
case 'Yes, always':
vscode.commands.executeCommand('clangd.restart');
config.update<string>('onConfigChanged', 'restart',
vscode.ConfigurationTarget.Global);
break;
case 'No, never':
config.update<string>('onConfigChanged', 'ignore',
vscode.ConfigurationTarget.Global);
break;
default:
break;
}
break;
}
}
}