-
-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathextension.ts
214 lines (187 loc) · 6.11 KB
/
extension.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
import process from 'node:process';
import {
type ConfigurationChangeEvent,
type ExtensionContext,
workspace,
window,
commands
} from 'vscode';
import {
LanguageClient,
TransportKind,
type LanguageClientOptions,
type ServerOptions
} from 'vscode-languageclient/node';
import Queue from 'queue';
import pkg from '../package.json';
import {updateStatusBar} from './status-bar';
import {xoRootCache} from './cache';
import {fixAllProblems} from './fix-all-problems';
const languageClient: LanguageClient | undefined = undefined;
const queue = new Queue({autostart: true, concurrency: 1});
export async function activate(context: ExtensionContext) {
const logger = window.createOutputChannel('xo', {log: true});
xoRootCache.logger = logger;
logger.info(`[client] Activating XO extension v${pkg.version}`);
const xoConfig = workspace.getConfiguration('xo');
const runtime = xoConfig.get<string>('runtime');
const hasValidXoRoot = await xoRootCache.get(window.activeTextEditor?.document.uri.fsPath);
const serverModule = context.asAbsolutePath('dist/server.js');
const serverOptions: ServerOptions = {
run: {
module: serverModule,
runtime,
transport: TransportKind.ipc,
options: {cwd: process.cwd()}
},
debug: {
module: serverModule,
runtime,
transport: TransportKind.ipc,
options: {
execArgv: ['--nolazy', '--inspect=6004'],
cwd: process.cwd()
}
}
};
const clientOptions: LanguageClientOptions = {
documentSelector: xoConfig.get<string[]>('validate', []).flatMap((language) => [
{language, scheme: 'file'},
{language, scheme: 'untitled'}
]),
outputChannel: logger,
synchronize: {
configurationSection: 'xo'
}
};
const languageClient = new LanguageClient('xo', serverOptions, clientOptions);
const restart = async () => {
try {
logger.info('[client] Restarting client');
await languageClient.restart();
logger.info('[client] Restarting client success');
} catch (error) {
languageClient.error(`[client] Restarting client failed`, error, 'force');
throw error;
}
};
/**
* Update status bar on activation, and dispose of the status bar when the extension is deactivated
*/
const statusBar = await updateStatusBar(window.activeTextEditor?.document);
context.subscriptions.push(
/**
* register xo extensions provided commands
*/
commands.registerCommand('xo.fix', async () => fixAllProblems(languageClient)),
commands.registerCommand('xo.showOutputChannel', () => {
logger.show();
}),
commands.registerCommand('xo.restart', restart),
...[
// we relint all open textDocuments whenever a config changes
// that may possibly affect the options xo should be using
workspace.createFileSystemWatcher('**/.eslintignore'),
workspace.createFileSystemWatcher('**/.xo-confi{g.cjs,g.json,g.js,g}'),
workspace.createFileSystemWatcher('**/xo.confi{g.cjs,g.js,g.ts,g.cts,g.mts}'),
workspace.createFileSystemWatcher('**/package.json')
].map((watcher) => watcher.onDidChange(restart)),
/**
* react to config changes - if the `xo.validate` setting changes, we need to restart the client
*/
workspace.onDidChangeConfiguration((configChange: ConfigurationChangeEvent) => {
queue.push(async () => {
try {
logger.debug('[client] Configuration change detected');
const isValidateChanged = configChange.affectsConfiguration('xo.validate');
if (isValidateChanged) {
logger.info(
'[client] xo.validate change detected, restarting client with new options.'
);
statusBar.text = '$(gear~spin)';
statusBar.show();
languageClient.clientOptions.documentSelector = xoConfig
.get<string[]>('validate', [])
.flatMap((language) => [
{language, scheme: 'file'},
{language, scheme: 'untitled'}
]);
await restart();
statusBar.text = '$(xo-logo)';
statusBar.hide();
logger.info('[client] Restarted client with new xo.validate options.');
}
} catch (error) {
if (error instanceof Error) {
logger.error(`[client] There was a problem handling the configuration change.`);
logger.error(error);
}
}
});
}),
/**
* Only show status bar on relevant files where xo is set up to lint
* updated on every active editor change, also check if we should start the
* server for the first time if xo wasn't originally in the workspace
*/
window.onDidChangeActiveTextEditor((textEditor) => {
queue.push(async () => {
try {
const {document: textDocument} = textEditor ?? {};
logger.debug('[client] onDidChangeActiveTextEditor', textDocument?.uri.fsPath);
const isEnabled = workspace
.getConfiguration('xo', textDocument)
.get<boolean>('enable', true);
if (!isEnabled) {
logger.debug('[client] onDidChangeActiveTextEditor > XO is not enabled');
return;
}
await updateStatusBar(textDocument);
if (
isEnabled &&
textDocument &&
languageClient.needsStart() &&
(await xoRootCache.get(textDocument.uri.fsPath))
) {
logger.debug('[client] Starting Language Client');
await languageClient.start();
}
} catch (error) {
if (error instanceof Error) {
statusBar.text = '$(xo-logo)';
logger.error(`[client] There was a problem handling the active text editor change.`);
logger.error(error);
}
}
});
}),
/**
* Check again whether or not we need a server instance
* if folders are added are removed from the workspace
*/
workspace.onDidCloseTextDocument((textDocument) => {
queue.push(async () => {
xoRootCache.delete(textDocument.uri.fsPath);
});
}),
/**
* Dispose of the status bar when the extension is deactivated
*/
statusBar
);
if (hasValidXoRoot) {
logger.info('[client] XO is enabled and is needed for linting file, server is now starting.');
await languageClient.start();
context.subscriptions.push(languageClient);
return;
}
if (!hasValidXoRoot) {
logger.info('[client] XO is enabled and server will start when a relevant file is opened.');
}
}
export async function deactivate() {
if (!languageClient) {
return undefined;
}
return languageClient.stop();
}