Skip to content

Commit

Permalink
Update html-language-features to use doQuoteComplete
Browse files Browse the repository at this point in the history
  • Loading branch information
jzyrobert committed Nov 12, 2021
1 parent 5248915 commit 9ae9cfb
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 0 deletions.
11 changes: 11 additions & 0 deletions extensions/html-language-features/client/src/htmlClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
LanguageClientOptions, RequestType, TextDocumentPositionParams, DocumentRangeFormattingParams,
DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, TextDocumentIdentifier, RequestType0, Range as LspRange, NotificationType, CommonLanguageClient
} from 'vscode-languageclient';
import { activateQuoteCreation } from './quoteCreation';
import { activateTagClosing } from './tagClosing';
import { RequestService } from './requests';
import { getCustomDataSource } from './customData';
Expand All @@ -23,6 +24,10 @@ namespace CustomDataChangedNotification {
export const type: NotificationType<string[]> = new NotificationType('html/customDataChanged');
}

namespace QuoteCreateRequest {
export const type: RequestType<TextDocumentPositionParams, string, any> = new RequestType('html/quote');
}

namespace TagCloseRequest {
export const type: RequestType<TextDocumentPositionParams, string, any> = new RequestType('html/tag');
}
Expand Down Expand Up @@ -125,6 +130,12 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris);
});

let quoteRequestor = (document: TextDocument, position: Position) => {
let param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position);
return client.sendRequest(QuoteCreateRequest.type, param);
};
disposable = activateQuoteCreation(quoteRequestor, { html: true, handlebars: true }, 'html.autoCreateQuotes', runtime);
toDispose.push(disposable);
let tagRequestor = (document: TextDocument, position: Position) => {
let param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position);
return client.sendRequest(TagCloseRequest.type, param);
Expand Down
86 changes: 86 additions & 0 deletions extensions/html-language-features/client/src/quoteCreation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { window, workspace, Disposable, TextDocument, Position, SnippetString, TextDocumentChangeEvent, TextDocumentChangeReason, Selection } from 'vscode';
import { Runtime } from './htmlClient';

export function activateQuoteCreation(quoteProvider: (document: TextDocument, position: Position) => Thenable<string>, supportedLanguages: { [id: string]: boolean }, configName: string, runtime: Runtime): Disposable {

const disposables: Disposable[] = [];
workspace.onDidChangeTextDocument(onDidChangeTextDocument, null, disposables);

let isEnabled = false;
updateEnabledState();
window.onDidChangeActiveTextEditor(updateEnabledState, null, disposables);

let timeout: Disposable | undefined = undefined;

disposables.push({
dispose: () => {
timeout?.dispose();
}
});

function updateEnabledState() {
isEnabled = false;
const editor = window.activeTextEditor;
if (!editor) {
return;
}
const document = editor.document;
if (!supportedLanguages[document.languageId]) {
return;
}
if (!workspace.getConfiguration(undefined, document.uri).get<boolean>(configName)) {
return;
}
isEnabled = true;
}

function onDidChangeTextDocument({ document, contentChanges, reason }: TextDocumentChangeEvent) {
if (!isEnabled || contentChanges.length === 0 || reason === TextDocumentChangeReason.Undo || reason === TextDocumentChangeReason.Redo) {
return;
}
const activeDocument = window.activeTextEditor && window.activeTextEditor.document;
if (document !== activeDocument) {
return;
}
if (timeout) {
timeout.dispose();
}

const lastChange = contentChanges[contentChanges.length - 1];
const lastCharacter = lastChange.text[lastChange.text.length - 1];
if (lastChange.rangeLength > 0 || lastCharacter !== '=') {
return;
}
const rangeStart = lastChange.range.start;
const version = document.version;
timeout = runtime.timer.setTimeout(() => {
const position = new Position(rangeStart.line, rangeStart.character + lastChange.text.length);
quoteProvider(document, position).then(text => {
if (text && isEnabled) {
const activeEditor = window.activeTextEditor;
if (activeEditor) {
const activeDocument = activeEditor.document;
if (document === activeDocument && activeDocument.version === version) {
const selections = activeEditor.selections;
if (selections.length && selections.some(s => s.active.isEqual(position))) {
activeEditor.insertSnippet(new SnippetString(text), selections.map(s => s.active));
// Move all cursors one forward
activeEditor.selections = selections.map(s => new Selection(s.active.translate(0, 1), s.active.translate(0, 1)))
} else {
activeEditor.insertSnippet(new SnippetString(text), position);
// Selections gone or moved, don't move cursor
}
}
}
}
});
timeout = undefined;
}, 100);
}
return Disposable.from(...disposables);
}
6 changes: 6 additions & 0 deletions extensions/html-language-features/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@
"default": true,
"description": "%html.validate.styles%"
},
"html.autoCreateQuotes": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%html.autoCreateQuotes%"
},
"html.autoClosingTags": {
"type": "boolean",
"scope": "resource",
Expand Down
1 change: 1 addition & 0 deletions extensions/html-language-features/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.",
"html.validate.scripts": "Controls whether the built-in HTML language support validates embedded scripts.",
"html.validate.styles": "Controls whether the built-in HTML language support validates embedded styles.",
"html.autoCreateQuotes": "Enable/disable auto creation of quotes for HTML attribute assignment.",
"html.autoClosingTags": "Enable/disable autoclosing of HTML tags.",
"html.completion.attributeDefaultValue": "Controls the default value for attributes when completion is accepted.",
"html.completion.attributeDefaultValue.doublequotes": "Attribute value is set to \"\".",
Expand Down
20 changes: 20 additions & 0 deletions extensions/html-language-features/server/src/htmlServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ namespace CustomDataChangedNotification {
export const type: NotificationType<string[]> = new NotificationType('html/customDataChanged');
}

namespace QuoteCreateRequest {
export const type: RequestType<TextDocumentPositionParams, string, any> = new RequestType('html/quote');
}

namespace TagCloseRequest {
export const type: RequestType<TextDocumentPositionParams, string | null, any> = new RequestType('html/tag');
}
Expand Down Expand Up @@ -471,6 +475,22 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
}, [], `Error while computing color presentations for ${params.textDocument.uri}`, token);
});

connection.onRequest(QuoteCreateRequest.type, (params, token) => {
return runSafe(runtime, async () => {
const document = documents.get(params.textDocument.uri);
if (document) {
const pos = params.position;
if (pos.character > 0) {
const mode = languageModes.getModeAtPosition(document, Position.create(pos.line, pos.character - 1));
if (mode && mode.doAutoQuote) {
return mode.doAutoQuote(document, pos);
}
}
}
return null;
}, null, `Error while computing tag close actions for ${params.textDocument.uri}`, token);
});

connection.onRequest(TagCloseRequest.type, (params, token) => {
return runSafe(runtime, async () => {
const document = documents.get(params.textDocument.uri);
Expand Down
12 changes: 12 additions & 0 deletions extensions/html-language-features/server/src/modes/htmlMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace:
async getFoldingRanges(document: TextDocument): Promise<FoldingRange[]> {
return htmlLanguageService.getFoldingRanges(document);
},
async doAutoQuote(document: TextDocument, position: Position, settings = workspace.settings) {
const htmlSettings = settings?.html;
const options = merge(htmlSettings?.suggest, {});
options.attributeDefaultValue = htmlSettings?.completion?.attributeDefaultValue ?? 'doublequotes';

const offset = document.offsetAt(position);
const text = document.getText();
if (offset > 0 && text.charAt(offset - 1) === '=') {
return htmlLanguageService.doQuoteComplete(document, position, htmlDocuments.get(document), options);
}
return null;
},
async doAutoClose(document: TextDocument, position: Position) {
const offset = document.offsetAt(position);
const text = document.getText();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface LanguageMode {
format?: (document: TextDocument, range: Range, options: FormattingOptions, settings?: Settings) => Promise<TextEdit[]>;
findDocumentColors?: (document: TextDocument) => Promise<ColorInformation[]>;
getColorPresentations?: (document: TextDocument, color: Color, range: Range) => Promise<ColorPresentation[]>;
doAutoQuote?: (document: TextDocument, position: Position) => Promise<string | null>;
doAutoClose?: (document: TextDocument, position: Position) => Promise<string | null>;
findMatchingTagPosition?: (document: TextDocument, position: Position) => Promise<Position | null>;
getFoldingRanges?: (document: TextDocument) => Promise<FoldingRange[]>;
Expand Down

0 comments on commit 9ae9cfb

Please sign in to comment.