css/html/json update to lsp 8 (#148715)

This commit is contained in:
Martin Aeschlimann
2022-05-19 12:48:53 +02:00
committed by GitHub
parent 14925e336d
commit e783fdc25e
30 changed files with 603 additions and 533 deletions

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, ExtensionContext, Uri } from 'vscode';
import { LanguageClientOptions } from 'vscode-languageclient';
import { BaseLanguageClient, LanguageClientOptions } from 'vscode-languageclient';
import { startClient, LanguageClientConstructor } from '../htmlClient';
import { LanguageClient } from 'vscode-languageclient/browser';
@@ -15,8 +15,10 @@ declare const TextDecoder: {
new(encoding?: string): { decode(buffer: ArrayBuffer): string };
};
let client: BaseLanguageClient | undefined;
// this method is called when vs code is activated
export function activate(context: ExtensionContext) {
export async function activate(context: ExtensionContext) {
const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/htmlServerMain.js');
try {
const worker = new Worker(serverMain.toString());
@@ -31,9 +33,17 @@ export function activate(context: ExtensionContext) {
}
};
startClient(context, newLanguageClient, { TextDecoder, timer });
client = await startClient(context, newLanguageClient, { TextDecoder, timer });
} catch (e) {
console.log(e);
}
}
export async function deactivate(): Promise<void> {
if (client) {
await client.stop();
client = undefined;
}
}

View File

@@ -13,7 +13,7 @@ import {
} from 'vscode';
import {
LanguageClientOptions, RequestType, DocumentRangeFormattingParams,
DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, TextDocumentIdentifier, RequestType0, Range as LspRange, Position as LspPosition, NotificationType, CommonLanguageClient
DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, TextDocumentIdentifier, RequestType0, Range as LspRange, Position as LspPosition, NotificationType, BaseLanguageClient
} from 'vscode-languageclient';
import { FileSystemProvider, serveFileSystemRequests } from './requests';
import { getCustomDataSource } from './customData';
@@ -72,7 +72,7 @@ export interface TelemetryReporter {
}): void;
}
export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => CommonLanguageClient;
export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient;
export interface Runtime {
TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string } };
@@ -83,18 +83,17 @@ export interface Runtime {
};
}
export function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime) {
export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise<BaseLanguageClient> {
let toDispose = context.subscriptions;
const toDispose = context.subscriptions;
let documentSelector = ['html', 'handlebars'];
let embeddedLanguages = { css: true, javascript: true };
const documentSelector = ['html', 'handlebars'];
const embeddedLanguages = { css: true, javascript: true };
let rangeFormatting: Disposable | undefined = undefined;
// Options to control the language client
let clientOptions: LanguageClientOptions = {
const clientOptions: LanguageClientOptions = {
documentSelector,
synchronize: {
configurationSection: ['html', 'css', 'javascript'], // the settings to synchronize
@@ -135,67 +134,65 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
let client = newLanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), clientOptions);
client.registerProposedFeatures();
let disposable = client.start();
toDispose.push(disposable);
client.onReady().then(() => {
await client.start();
toDispose.push(serveFileSystemRequests(client, runtime));
toDispose.push(serveFileSystemRequests(client, runtime));
const customDataSource = getCustomDataSource(runtime, context.subscriptions);
const customDataSource = getCustomDataSource(runtime, context.subscriptions);
client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris);
customDataSource.onDidChange(() => {
client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris);
customDataSource.onDidChange(() => {
client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris);
});
client.onRequest(CustomDataContent.type, customDataSource.getContent);
const insertRequestor = (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position): Promise<string> => {
let param: AutoInsertParams = {
kind,
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
position: client.code2ProtocolConverter.asPosition(position)
};
return client.sendRequest(AutoInsertRequest.type, param);
};
let disposable = activateAutoInsertion(insertRequestor, { html: true, handlebars: true }, runtime);
toDispose.push(disposable);
disposable = client.onTelemetry(e => {
runtime.telemetry?.sendTelemetryEvent(e.key, e.data);
});
toDispose.push(disposable);
// manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652.
updateFormatterRegistration();
toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() });
toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration(SettingIds.formatEnable) && updateFormatterRegistration()));
client.sendRequest(SemanticTokenLegendRequest.type).then(legend => {
if (legend) {
const provider: DocumentSemanticTokensProvider & DocumentRangeSemanticTokensProvider = {
provideDocumentSemanticTokens(doc) {
const params: SemanticTokenParams = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc),
};
return client.sendRequest(SemanticTokenRequest.type, params).then(data => {
return data && new SemanticTokens(new Uint32Array(data));
});
},
provideDocumentRangeSemanticTokens(doc, range) {
const params: SemanticTokenParams = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc),
ranges: [client.code2ProtocolConverter.asRange(range)]
};
return client.sendRequest(SemanticTokenRequest.type, params).then(data => {
return data && new SemanticTokens(new Uint32Array(data));
});
}
};
toDispose.push(languages.registerDocumentSemanticTokensProvider(documentSelector, provider, new SemanticTokensLegend(legend.types, legend.modifiers)));
}
});
});
client.onRequest(CustomDataContent.type, customDataSource.getContent);
const insertRequestor = (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position): Promise<string> => {
const param: AutoInsertParams = {
kind,
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
position: client.code2ProtocolConverter.asPosition(position)
};
return client.sendRequest(AutoInsertRequest.type, param);
};
const disposable = activateAutoInsertion(insertRequestor, { html: true, handlebars: true }, runtime);
toDispose.push(disposable);
const disposable2 = client.onTelemetry(e => {
runtime.telemetry?.sendTelemetryEvent(e.key, e.data);
});
toDispose.push(disposable2);
// manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652.
updateFormatterRegistration();
toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() });
toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration(SettingIds.formatEnable) && updateFormatterRegistration()));
client.sendRequest(SemanticTokenLegendRequest.type).then(legend => {
if (legend) {
const provider: DocumentSemanticTokensProvider & DocumentRangeSemanticTokensProvider = {
provideDocumentSemanticTokens(doc) {
const params: SemanticTokenParams = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc),
};
return client.sendRequest(SemanticTokenRequest.type, params).then(data => {
return data && new SemanticTokens(new Uint32Array(data));
});
},
provideDocumentRangeSemanticTokens(doc, range) {
const params: SemanticTokenParams = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc),
ranges: [client.code2ProtocolConverter.asRange(range)]
};
return client.sendRequest(SemanticTokenRequest.type, params).then(data => {
return data && new SemanticTokens(new Uint32Array(data));
});
}
};
toDispose.push(languages.registerDocumentSemanticTokensProvider(documentSelector, provider, new SemanticTokensLegend(legend.types, legend.modifiers)));
}
});
function updateFormatterRegistration() {
const formatEnabled = workspace.getConfiguration().get(SettingIds.formatEnable);
@@ -219,7 +216,7 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then(
client.protocol2CodeConverter.asTextEdits,
(error) => {
client.handleFailedRequest(DocumentRangeFormattingRequest.type, error, []);
client.handleFailedRequest(DocumentRangeFormattingRequest.type, undefined, error, []);
return Promise.resolve([]);
}
);
@@ -300,4 +297,6 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
}
}
return client;
}

View File

@@ -6,16 +6,17 @@
import { getNodeFileFS } from './nodeFs';
import { Disposable, ExtensionContext } from 'vscode';
import { startClient, LanguageClientConstructor } from '../htmlClient';
import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient } from 'vscode-languageclient/node';
import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient, BaseLanguageClient } from 'vscode-languageclient/node';
import { TextDecoder } from 'util';
import * as fs from 'fs';
import TelemetryReporter from '@vscode/extension-telemetry';
let telemetry: TelemetryReporter | undefined;
let client: BaseLanguageClient | undefined;
// this method is called when vs code is activated
export function activate(context: ExtensionContext) {
export async function activate(context: ExtensionContext) {
let clientPackageJSON = getPackageInfo(context);
telemetry = new TelemetryReporter(clientPackageJSON.name, clientPackageJSON.version, clientPackageJSON.aiKey);
@@ -44,7 +45,14 @@ export function activate(context: ExtensionContext) {
}
};
startClient(context, newLanguageClient, { fileFs: getNodeFileFS(), TextDecoder, telemetry, timer });
client = await startClient(context, newLanguageClient, { fileFs: getNodeFileFS(), TextDecoder, telemetry, timer });
}
export async function deactivate(): Promise<void> {
if (client) {
await client.stop();
client = undefined;
}
}
interface IPackageInfo {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Uri, workspace, Disposable } from 'vscode';
import { RequestType, CommonLanguageClient } from 'vscode-languageclient';
import { RequestType, BaseLanguageClient } from 'vscode-languageclient';
import { Runtime } from './htmlClient';
export namespace FsStatRequest {
@@ -15,7 +15,7 @@ export namespace FsReadDirRequest {
export const type: RequestType<string, [string, FileType][], any> = new RequestType('fs/readDir');
}
export function serveFileSystemRequests(client: CommonLanguageClient, runtime: Runtime): Disposable {
export function serveFileSystemRequests(client: BaseLanguageClient, runtime: Runtime): Disposable {
const disposables = [];
disposables.push(client.onRequest(FsReadDirRequest.type, (uriString: string) => {
const uri = Uri.parse(uriString);