Skip to content

Commit

Permalink
Fixes #1295: No LSP workspace/didChangeConfiguration notifications af…
Browse files Browse the repository at this point in the history
…ter language server restart (#1298)
  • Loading branch information
dbaeumer authored Aug 21, 2023
1 parent 7792b0b commit 7899568
Show file tree
Hide file tree
Showing 13 changed files with 38 additions and 34 deletions.
4 changes: 2 additions & 2 deletions client/src/common/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1434,9 +1434,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
if (this._syncedDocuments) {
this._syncedDocuments.clear();
}
// Dispose features in reverse order;
// Clear features in reverse order;
for (const feature of Array.from(this._features.entries()).map(entry => entry[1]).reverse()) {
feature.dispose();
feature.clear();
}
if (mode === 'stop' && this._diagnostics !== undefined) {
this._diagnostics.dispose();
Expand Down
13 changes: 7 additions & 6 deletions client/src/common/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class ConfigurationFeature implements StaticFeature {
return result;
}

public dispose(): void {
public clear(): void {
}
}

Expand Down Expand Up @@ -149,11 +149,11 @@ export type $ConfigurationOptions = {

export class SyncConfigurationFeature implements DynamicFeature<DidChangeConfigurationRegistrationOptions> {

private isDisposed: boolean;
private isCleared: boolean;
private readonly _listeners: Map<string, Disposable>;

constructor(private _client: FeatureClient<DidChangeConfigurationWorkspaceMiddleware, $ConfigurationOptions>) {
this.isDisposed = false;
this.isCleared = false;
this._listeners = new Map();
}

Expand All @@ -170,6 +170,7 @@ export class SyncConfigurationFeature implements DynamicFeature<DidChangeConfigu
}

public initialize(): void {
this.isCleared = false;
let section = this._client.clientOptions.synchronize?.configurationSection;
if (section !== undefined) {
this.register({
Expand Down Expand Up @@ -199,16 +200,16 @@ export class SyncConfigurationFeature implements DynamicFeature<DidChangeConfigu
}
}

public dispose(): void {
public clear(): void {
for (const disposable of this._listeners.values()) {
disposable.dispose();
}
this._listeners.clear();
this.isDisposed = true;
this.isCleared = true;
}

private onDidChangeConfiguration(configurationSection: string | string[] | undefined, event: ConfigurationChangeEvent | undefined): void {
if (this.isDisposed) {
if (this.isCleared) {
return;
}
let sections: string[] | undefined;
Expand Down
4 changes: 2 additions & 2 deletions client/src/common/diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1056,12 +1056,12 @@ export class DiagnosticFeature extends TextDocumentLanguageFeature<DiagnosticOpt
this.register({ id: id, registerOptions: options });
}

public dispose(): void {
public clear(): void {
if (this.tabs !== undefined) {
this.tabs.dispose();
this.tabs = undefined;
}
super.dispose();
super.clear();
}

protected registerLanguageProvider(options: DiagnosticRegistrationOptions): [Disposable, DiagnosticProviderShape] {
Expand Down
2 changes: 1 addition & 1 deletion client/src/common/executeCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class ExecuteCommandFeature implements DynamicFeature<ExecuteCommandRegis
}
}

public dispose(): void {
public clear(): void {
this._commands.forEach((value) => {
value.forEach(disposable => disposable.dispose());
});
Expand Down
26 changes: 14 additions & 12 deletions client/src/common/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,18 @@ export interface StaticFeature {
getState(): FeatureState;

/**
* Called when the client is stopped to dispose this feature. Usually a feature
* un-registers listeners registered hooked up with the VS Code extension host.
* Called when the client is stopped or re-started to clear this feature.
* Usually a feature un-registers listeners registered hooked up with the
* VS Code extension host.
*/
dispose(): void;
clear(): void;
}

export namespace StaticFeature {
export function is (value: any): value is StaticFeature {
const candidate: StaticFeature = value;
return candidate !== undefined && candidate !== null &&
Is.func(candidate.fillClientCapabilities) && Is.func(candidate.initialize) && Is.func(candidate.getState) && Is.func(candidate.dispose) &&
Is.func(candidate.fillClientCapabilities) && Is.func(candidate.initialize) && Is.func(candidate.getState) && Is.func(candidate.clear) &&
(candidate.fillInitializeParams === undefined || Is.func(candidate.fillInitializeParams));
}
}
Expand Down Expand Up @@ -237,17 +238,18 @@ export interface DynamicFeature<RO> {
unregister(id: string): void;

/**
* Called when the client is stopped to dispose this feature. Usually a feature
* un-registers listeners registered hooked up with the VS Code extension host.
* Called when the client is stopped or re-started to clear this feature.
* Usually a feature un-registers listeners registered hooked up with the
* VS Code extension host.
*/
dispose(): void;
clear(): void;
}

export namespace DynamicFeature {
export function is<T>(value: any): value is DynamicFeature<T> {
const candidate: DynamicFeature<T> = value;
return candidate !== undefined && candidate !== null &&
Is.func(candidate.fillClientCapabilities) && Is.func(candidate.initialize) && Is.func(candidate.getState) && Is.func(candidate.dispose) &&
Is.func(candidate.fillClientCapabilities) && Is.func(candidate.initialize) && Is.func(candidate.getState) && Is.func(candidate.clear) &&
(candidate.fillInitializeParams === undefined || Is.func(candidate.fillInitializeParams)) && Is.func(candidate.register) &&
Is.func(candidate.unregister) && candidate.registrationType !== undefined;
}
Expand Down Expand Up @@ -285,7 +287,7 @@ export abstract class DynamicDocumentFeature<RO, MW, CO = object> implements Dyn
public abstract registrationType: RegistrationType<RO>;
public abstract register(data: RegistrationData<RO>): void;
public abstract unregister(id: string): void;
public abstract dispose(): void;
public abstract clear(): void;

/**
* Returns the state the feature is in.
Expand Down Expand Up @@ -424,7 +426,7 @@ export abstract class TextDocumentEventFeature<P extends { textDocument: TextDoc
}
}

public dispose(): void {
public clear(): void {
this._selectors.clear();
this._onNotificationSent.dispose();
if (this._listener) {
Expand Down Expand Up @@ -518,7 +520,7 @@ export abstract class TextDocumentLanguageFeature<PO, RO extends TextDocumentReg
}
}

public dispose(): void {
public clear(): void {
this._registrations.forEach((value) => {
value.disposable.dispose();
});
Expand Down Expand Up @@ -618,7 +620,7 @@ export abstract class WorkspaceFeature<RO, PR, M> implements DynamicFeature<RO>
}
}

public dispose(): void {
public clear(): void {
this._registrations.forEach((registration) => {
registration.disposable.dispose();
});
Expand Down
6 changes: 3 additions & 3 deletions client/src/common/fileOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ abstract class FileOperationFeature<I, E extends Event<I>> implements DynamicFea
}
}

public dispose(): void {
public clear(): void {
this._filters.clear();
if (this._listener) {
this._listener.dispose();
Expand Down Expand Up @@ -276,8 +276,8 @@ abstract class CachingNotificationFileOperationFeature<I, E extends { readonly f
}
}

public dispose(): void {
super.dispose();
public clear(): void {
super.clear();
if (this._willListener) {
this._willListener.dispose();
this._willListener = undefined;
Expand Down
2 changes: 1 addition & 1 deletion client/src/common/fileSystemWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class FileSystemWatcherFeature implements DynamicFeature<DidChangeWatched
}
}

public dispose(): void {
public clear(): void {
this._watchers.forEach((disposables) => {
for (let disposable of disposables) {
disposable.dispose();
Expand Down
2 changes: 1 addition & 1 deletion client/src/common/notebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ export class NotebookDocumentSyncFeature implements DynamicFeature<proto.Noteboo
provider && provider.dispose();
}

public dispose(): void {
public clear(): void {
for (const provider of this.registrations.values()) {
provider.dispose();
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/common/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class ProgressFeature implements StaticFeature {
client.onRequest(WorkDoneProgressCreateRequest.type, createHandler);
}

public dispose(): void {
public clear(): void {
for (const part of this.activeParts) {
part.done();
}
Expand Down
4 changes: 2 additions & 2 deletions client/src/common/textSynchronization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ export class DidChangeTextDocumentFeature extends DynamicDocumentFeature<TextDoc
}
}

public dispose(): void {
public clear(): void {
this._pendingTextDocumentChanges.clear();
this._changeData.clear();
this._syncKind = TextDocumentSyncKind.None;
Expand Down Expand Up @@ -484,7 +484,7 @@ export class WillSaveWaitUntilFeature extends DynamicDocumentFeature<TextDocumen
}
}

public dispose(): void {
public clear(): void {
this._selectors.clear();
if (this._listener) {
this._listener.dispose();
Expand Down
2 changes: 1 addition & 1 deletion client/src/common/workspaceFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export class WorkspaceFoldersFeature implements DynamicFeature<void> {
disposable.dispose();
}

public dispose(): void {
public clear(): void {
for (let disposable of this._listeners.values()) {
disposable.dispose();
}
Expand Down
2 changes: 1 addition & 1 deletion testbed/client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export async function activate(context: ExtensionContext) {
{ scheme: 'file', pattern: '**/.vscode/test.txt' }
],
synchronize: {
configurationSection: 'testbed'
// configurationSection: 'testbed'
// fileEvents: workspace.createFileSystemWatcher('**/*'),
},
diagnosticCollectionName: 'markers',
Expand Down
3 changes: 2 additions & 1 deletion testbed/server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
TextEdit, ProposedFeatures, DiagnosticTag, InsertTextFormat, SelectionRangeRequest, SelectionRange, InsertReplaceEdit,
SemanticTokensClientCapabilities, SemanticTokensLegend, SemanticTokensBuilder, SemanticTokensRegistrationType,
SemanticTokensRegistrationOptions, ProtocolNotificationType, ChangeAnnotation, WorkspaceChange, CompletionItemKind, DiagnosticSeverity,
DocumentDiagnosticReportKind, WorkspaceDiagnosticReport, NotebookDocuments, CompletionList, DocumentLinkResolveRequest
DocumentDiagnosticReportKind, WorkspaceDiagnosticReport, NotebookDocuments, CompletionList, DocumentLinkResolveRequest, DidChangeConfigurationNotification
} from 'vscode-languageserver/node';

import {
Expand Down Expand Up @@ -187,6 +187,7 @@ connection.onInitialize((params, cancel, progress): Thenable<InitializeResult> |
});

connection.onInitialized((params) => {
void connection.client.register(DidChangeConfigurationNotification.type, undefined);
connection.workspace.onDidChangeWorkspaceFolders((event) => {
connection.console.log('Workspace folder changed received');
});
Expand Down

0 comments on commit 7899568

Please sign in to comment.