Skip to content

Commit

Permalink
(feat) Fallback ts/js watcher for clients which don't support didChan…
Browse files Browse the repository at this point in the history
…geWatchedFiles (#841)

When a language server client doesn't support didChangeWatchedFiles. Initialize our own fallback file watcher.
This should fix the ts, js file doesn't get updated issue on the sublime text.
  • Loading branch information
jasonlyu123 committed Feb 24, 2021
1 parent f0f24a8 commit 34a936f
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 4 deletions.
44 changes: 44 additions & 0 deletions packages/language-server/src/lib/FallbackWatcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { FSWatcher, watch } from 'chokidar';
import { join } from 'path';
import { DidChangeWatchedFilesParams, FileChangeType, FileEvent } from 'vscode-languageserver';
import { pathToUrl } from '../utils';

type DidChangeHandler = (para: DidChangeWatchedFilesParams) => void;

export class FallbackWatcher {
private readonly watcher: FSWatcher;
private readonly callbacks: DidChangeHandler[] = [];

constructor(glob: string, workspacePaths: string[]) {
this.watcher = watch(workspacePaths.map((workspacePath) => join(workspacePath, glob)));

this.watcher
.on('add', (path) => this.callback(path, FileChangeType.Created))
.on('unlink', (path) => this.callback(path, FileChangeType.Deleted))
.on('change', (path) => this.callback(path, FileChangeType.Changed));
}

private convert(path: string, type: FileChangeType): DidChangeWatchedFilesParams {
const event: FileEvent = {
type,
uri: pathToUrl(path)
};

return {
changes: [event]
};
}

private callback(path: string, type: FileChangeType) {
const para = this.convert(path, type);
this.callbacks.forEach((callback) => callback(para));
}

onDidChangeWatchedFiles(callback: DidChangeHandler) {
this.callbacks.push(callback);
}

dispose() {
this.watcher.close();
}
}
24 changes: 20 additions & 4 deletions packages/language-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
TextDocumentSyncKind,
WorkspaceEdit,
SemanticTokensRequest,
SemanticTokensRangeRequest
SemanticTokensRangeRequest,
DidChangeWatchedFilesParams
} from 'vscode-languageserver';
import { IPCMessageReader, IPCMessageWriter, createConnection } from 'vscode-languageserver/node';
import { DiagnosticsManager } from './lib/DiagnosticsManager';
Expand All @@ -31,7 +32,8 @@ import {
TypeScriptPlugin,
OnWatchFileChangesPara
} from './plugins';
import { urlToPath } from './utils';
import { isNotNullOrUndefined, urlToPath } from './utils';
import { FallbackWatcher } from './lib/FallbackWatcher';

namespace TagCloseRequest {
export const type: RequestType<
Expand Down Expand Up @@ -85,6 +87,7 @@ export function startServer(options?: LSOptions) {
const configManager = new LSConfigManager();
const pluginHost = new PluginHost(docManager);
let sveltePlugin: SveltePlugin = undefined as any;
let watcher: FallbackWatcher | undefined;

connection.onInitialize((evt) => {
const workspaceUris = evt.workspaceFolders?.map((folder) => folder.uri.toString()) ?? [
Expand All @@ -95,6 +98,12 @@ export function startServer(options?: LSOptions) {
Logger.error('No workspace path set');
}

if (!evt.capabilities.workspace?.didChangeWatchedFiles) {
const workspacePaths = workspaceUris.map(urlToPath).filter(isNotNullOrUndefined);
watcher = new FallbackWatcher('**/*.{ts,js}', workspacePaths);
watcher.onDidChangeWatchedFiles(onDidChangeWatchedFiles);
}

configManager.update(evt.initializationOptions?.config || {});
configManager.updateTsJsUserPreferences(evt.initializationOptions?.typescriptConfig || {});
configManager.updateEmmetConfig(evt.initializationOptions?.emmetConfig || {});
Expand Down Expand Up @@ -199,6 +208,10 @@ export function startServer(options?: LSOptions) {
};
});

connection.onExit(() => {
watcher?.dispose();
});

connection.onRenameRequest((req) =>
pluginHost.rename(req.textDocument, req.position, req.newName)
);
Expand Down Expand Up @@ -285,7 +298,9 @@ export function startServer(options?: LSOptions) {
);

const updateAllDiagnostics = _.debounce(() => diagnosticsManager.updateAll(), 1000);
connection.onDidChangeWatchedFiles((para) => {

connection.onDidChangeWatchedFiles(onDidChangeWatchedFiles);
function onDidChangeWatchedFiles(para: DidChangeWatchedFilesParams) {
const onWatchFileChangesParas = para.changes
.map((change) => ({
fileName: urlToPath(change.uri),
Expand All @@ -296,7 +311,8 @@ export function startServer(options?: LSOptions) {
pluginHost.onWatchFileChanges(onWatchFileChangesParas);

updateAllDiagnostics();
});
}

connection.onDidSaveTextDocument(updateAllDiagnostics);
connection.onNotification('$/onDidChangeTsOrJsFile', async (e: any) => {
const path = urlToPath(e.uri);
Expand Down

0 comments on commit 34a936f

Please sign in to comment.