Skip to content

Commit 1254d6b

Browse files
committed
redhat-developer#327 use 'workspace/configuration' to fetch settings
Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
1 parent 38aad39 commit 1254d6b

File tree

5 files changed

+133
-21
lines changed

5 files changed

+133
-21
lines changed

src/languageserver/handlers/settingsHandlers.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55
import { xhr, configure as configureHttpRequests } from 'request-light';
6-
import { DidChangeConfigurationParams, DocumentFormattingRequest, Connection } from 'vscode-languageserver';
6+
import { DocumentFormattingRequest, Connection, DidChangeConfigurationNotification } from 'vscode-languageserver';
77
import { isRelativePath, relativeToAbsolutePath } from '../../languageservice/utils/paths';
88
import { checkSchemaURI, JSON_SCHEMASTORE_URL, KUBERNETES_SCHEMA_URL } from '../../languageservice/utils/schemaUrls';
99
import { LanguageService, LanguageSettings, SchemaPriority } from '../../languageservice/yamlLanguageService';
@@ -21,16 +21,35 @@ export class SettingsHandler {
2121
) {}
2222

2323
public registerHandlers(): void {
24-
this.connection.onDidChangeConfiguration((change) => this.configurationChangeHandler(change));
24+
if (this.yamlSettings.hasConfigurationCapability) {
25+
// Register for all configuration changes.
26+
this.connection.client.register(DidChangeConfigurationNotification.type, undefined);
27+
}
28+
this.connection.onDidChangeConfiguration(() => this.pullConfiguration());
2529
}
2630

2731
/**
28-
* Run when the editor configuration is changed
29-
* The client syncs the 'yaml', 'http.proxy', 'http.proxyStrictSSL' settings sections
30-
* Update relevant settings with fallback to defaults if needed
32+
* The server pull the 'yaml', 'http.proxy', 'http.proxyStrictSSL', '[yaml]' settings sections
3133
*/
32-
private configurationChangeHandler(change: DidChangeConfigurationParams): void {
33-
const settings = change.settings as Settings;
34+
async pullConfiguration(): Promise<void> {
35+
const config = await this.connection.workspace.getConfiguration([
36+
{ section: 'yaml' },
37+
{ section: 'http.proxy' },
38+
{ section: 'http.proxyStrictSSL' },
39+
{ section: '[yaml]' },
40+
]);
41+
const settings: Settings = {
42+
yaml: config[0],
43+
http: {
44+
proxy: config[1],
45+
proxyStrictSSL: config[2],
46+
},
47+
yamlEditor: config[3],
48+
};
49+
this.setConfiguration(settings);
50+
}
51+
52+
setConfiguration(settings: Settings): void {
3453
configureHttpRequests(settings.http && settings.http.proxy, settings.http && settings.http.proxyStrictSSL);
3554

3655
this.yamlSettings.specificValidatorPaths = [];
@@ -81,10 +100,8 @@ export class SettingsHandler {
81100

82101
this.yamlSettings.schemaConfigurationSettings = [];
83102

84-
if (settings['[yaml]'] && settings['[yaml]']['editor.tabSize']) {
85-
this.yamlSettings.indentation = ' '.repeat(settings['[yaml]']['editor.tabSize']);
86-
} else if (settings.editor?.tabSize) {
87-
this.yamlSettings.indentation = ' '.repeat(settings.editor.tabSize);
103+
if (settings.yamlEditor && settings.yamlEditor['editor.tabSize']) {
104+
this.yamlSettings.indentation = ' '.repeat(settings.yamlEditor['editor.tabSize']);
88105
}
89106

90107
for (const uri in this.yamlSettings.yamlConfigurationSettings) {

src/yamlServerInit.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export class YAMLServerInit {
2222
languageService: LanguageService;
2323
languageHandler: LanguageHandlers;
2424
validationHandler: ValidationHandler;
25+
settingsHandler: SettingsHandler;
2526

2627
private telemetry: Telemetry;
2728
constructor(
@@ -48,6 +49,9 @@ export class YAMLServerInit {
4849
this.yamlSettings.workspaceFolders = workspaceFoldersChanged(this.yamlSettings.workspaceFolders, changedFolders);
4950
});
5051
}
52+
// need to call this after connection initialized
53+
this.settingsHandler.registerHandlers();
54+
this.settingsHandler.pullConfiguration();
5155
});
5256
}
5357

@@ -81,6 +85,9 @@ export class YAMLServerInit {
8185
this.yamlSettings.hasWorkspaceFolderCapability =
8286
this.yamlSettings.capabilities.workspace && !!this.yamlSettings.capabilities.workspace.workspaceFolders;
8387

88+
this.yamlSettings.hasConfigurationCapability = !!(
89+
this.yamlSettings.capabilities.workspace && !!this.yamlSettings.capabilities.workspace.configuration
90+
);
8491
this.registerHandlers();
8592

8693
return {
@@ -117,17 +124,17 @@ export class YAMLServerInit {
117124
private registerHandlers(): void {
118125
// Register all features that the language server has
119126
this.validationHandler = new ValidationHandler(this.connection, this.languageService, this.yamlSettings);
120-
const settingsHandler = new SettingsHandler(
127+
this.settingsHandler = new SettingsHandler(
121128
this.connection,
122129
this.languageService,
123130
this.yamlSettings,
124131
this.validationHandler,
125132
this.telemetry
126133
);
127-
settingsHandler.registerHandlers();
134+
// this.settingsHandler.registerHandlers();
128135
this.languageHandler = new LanguageHandlers(this.connection, this.languageService, this.yamlSettings, this.validationHandler);
129136
this.languageHandler.registerHandlers();
130-
new NotificationHandlers(this.connection, this.languageService, this.yamlSettings, settingsHandler).registerHandlers();
137+
new NotificationHandlers(this.connection, this.languageService, this.yamlSettings, this.settingsHandler).registerHandlers();
131138
new RequestHandlers(this.connection, this.languageService).registerHandlers();
132139
new WorkspaceHandlers(this.connection, commandExecutor).registerHandlers();
133140
}

src/yamlSettings.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ export interface Settings {
2626
proxy: string;
2727
proxyStrictSSL: boolean;
2828
};
29-
editor: {
30-
tabSize: number;
29+
yamlEditor: {
30+
'editor.tabSize': number;
31+
'editor.insertSpaces': boolean;
32+
'editor.formatOnType': boolean;
3133
};
3234
}
3335

@@ -77,6 +79,7 @@ export class SettingsState {
7779
clientDynamicRegisterSupport = false;
7880
hierarchicalDocumentSymbolSupport = false;
7981
hasWorkspaceFolderCapability = false;
82+
hasConfigurationCapability = false;
8083
useVSCodeContentRequest = false;
8184
}
8285

test/settingsHandlers.test.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,30 @@ import { SettingsHandler } from '../src/languageserver/handlers/settingsHandlers
77
import * as sinon from 'sinon';
88
import * as chai from 'chai';
99
import * as sinonChai from 'sinon-chai';
10-
import { Connection } from 'vscode-languageserver';
10+
import { Connection, RemoteWorkspace } from 'vscode-languageserver';
1111
import { SettingsState } from '../src/yamlSettings';
1212
import { ValidationHandler } from '../src/languageserver/handlers/validationHandlers';
1313
import { LanguageService, LanguageSettings, SchemaConfiguration, SchemaPriority } from '../src';
1414
import * as request from 'request-light';
1515
import { setupLanguageService } from './utils/testHelper';
1616
import { Telemetry } from '../src/languageserver/telemetry';
17+
import { TestWorkspace } from './utils/testsTypes';
1718

1819
const expect = chai.expect;
1920
chai.use(sinonChai);
2021

2122
describe('Settings Handlers Tests', () => {
2223
const sandbox = sinon.createSandbox();
23-
let connectionStub: sinon.SinonMockStatic;
24+
const connection: Connection = {} as Connection;
25+
let workspaceStub: sinon.SinonStubbedInstance<RemoteWorkspace>;
2426
let languageService: sinon.SinonMockStatic;
2527
let settingsState: SettingsState;
2628
let validationHandler: sinon.SinonMock;
2729
let xhrStub: sinon.SinonStub;
2830

2931
beforeEach(() => {
30-
connectionStub = sandbox.mock();
32+
workspaceStub = sandbox.createStubInstance(TestWorkspace);
33+
connection.workspace = (workspaceStub as unknown) as RemoteWorkspace;
3134
languageService = sandbox.mock();
3235
settingsState = new SettingsState();
3336
validationHandler = sandbox.mock(ValidationHandler);
@@ -51,7 +54,7 @@ describe('Settings Handlers Tests', () => {
5154
}]}`,
5255
});
5356
const settingsHandler = new SettingsHandler(
54-
(connectionStub as unknown) as Connection,
57+
connection,
5558
(languageService as unknown) as LanguageService,
5659
settingsState,
5760
(validationHandler as unknown) as ValidationHandler,
@@ -78,7 +81,7 @@ describe('Settings Handlers Tests', () => {
7881

7982
const languageService = languageServerSetup.languageService;
8083
const settingsHandler = new SettingsHandler(
81-
(connectionStub as unknown) as Connection,
84+
connection,
8285
languageService,
8386
settingsState,
8487
(validationHandler as unknown) as ValidationHandler,
@@ -143,4 +146,29 @@ describe('Settings Handlers Tests', () => {
143146
});
144147
});
145148
});
149+
150+
describe('Settings fetch', () => {
151+
it('should fetch preferences', async () => {
152+
const settingsHandler = new SettingsHandler(
153+
connection,
154+
(languageService as unknown) as LanguageService,
155+
settingsState,
156+
(validationHandler as unknown) as ValidationHandler,
157+
{} as Telemetry
158+
);
159+
workspaceStub.getConfiguration.resolves([{}, {}, {}, {}]);
160+
const setConfigurationStub = sandbox.stub(settingsHandler, 'setConfiguration');
161+
162+
await settingsHandler.pullConfiguration();
163+
164+
expect(workspaceStub.getConfiguration).calledOnceWith([
165+
{ section: 'yaml' },
166+
{ section: 'http.proxy' },
167+
{ section: 'http.proxyStrictSSL' },
168+
{ section: '[yaml]' },
169+
]);
170+
171+
expect(setConfigurationStub).calledOnce;
172+
});
173+
});
146174
});

test/utils/testsTypes.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { Event, NotificationHandler, RequestHandler } from 'vscode-jsonrpc';
7+
import {
8+
ApplyWorkspaceEditParams,
9+
WorkspaceEdit,
10+
ApplyWorkspaceEditResponse,
11+
ConfigurationItem,
12+
WorkspaceFolder,
13+
WorkspaceFoldersChangeEvent,
14+
CreateFilesParams,
15+
RenameFilesParams,
16+
DeleteFilesParams,
17+
} from 'vscode-languageserver-protocol';
18+
import { Connection, RemoteWorkspace } from 'vscode-languageserver/lib/common/server';
19+
20+
/* eslint-disable @typescript-eslint/no-explicit-any */
21+
/* eslint-disable @typescript-eslint/no-unused-vars */
22+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
23+
export class TestWorkspace implements RemoteWorkspace {
24+
connection: Connection;
25+
applyEdit(paramOrEdit: ApplyWorkspaceEditParams | WorkspaceEdit): Promise<ApplyWorkspaceEditResponse> {
26+
throw new Error('Method not implemented.');
27+
}
28+
getConfiguration(): Promise<any>;
29+
getConfiguration(section: string): Promise<any>;
30+
getConfiguration(item: ConfigurationItem): Promise<any>;
31+
getConfiguration(items: ConfigurationItem[]): Promise<any[]>;
32+
getConfiguration(items?: any): Promise<any | any[]> {
33+
throw new Error('Method not implemented.');
34+
}
35+
getWorkspaceFolders(): Promise<WorkspaceFolder[]> {
36+
throw new Error('Method not implemented.');
37+
}
38+
onDidChangeWorkspaceFolders: Event<WorkspaceFoldersChangeEvent>;
39+
onDidCreateFiles(handler: NotificationHandler<CreateFilesParams>): void {
40+
throw new Error('Method not implemented.');
41+
}
42+
onDidRenameFiles(handler: NotificationHandler<RenameFilesParams>): void {
43+
throw new Error('Method not implemented.');
44+
}
45+
onDidDeleteFiles(handler: NotificationHandler<DeleteFilesParams>): void {
46+
throw new Error('Method not implemented.');
47+
}
48+
onWillCreateFiles(handler: RequestHandler<CreateFilesParams, WorkspaceEdit, never>): void {
49+
throw new Error('Method not implemented.');
50+
}
51+
onWillRenameFiles(handler: RequestHandler<RenameFilesParams, WorkspaceEdit, never>): void {
52+
throw new Error('Method not implemented.');
53+
}
54+
onWillDeleteFiles(handler: RequestHandler<DeleteFilesParams, WorkspaceEdit, never>): void {
55+
throw new Error('Method not implemented.');
56+
}
57+
}

0 commit comments

Comments
 (0)