summaryrefslogtreecommitdiff
path: root/vscode/packages/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'vscode/packages/client/src')
-rw-r--r--vscode/packages/client/src/features/defaultSettings.ts30
-rw-r--r--vscode/packages/client/src/html/autoClose.ts108
-rw-r--r--vscode/packages/client/src/index.ts73
3 files changed, 138 insertions, 73 deletions
diff --git a/vscode/packages/client/src/features/defaultSettings.ts b/vscode/packages/client/src/features/defaultSettings.ts
deleted file mode 100644
index ec3de70a1..000000000
--- a/vscode/packages/client/src/features/defaultSettings.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as vscode from 'vscode';
-
-export async function activate() {
- onConfigUpdated();
-
- vscode.workspace.onDidChangeConfiguration(onConfigUpdated);
-
- function onConfigUpdated() {
- const astro = vscode.extensions.getExtension('skypack.astro');
- if (!astro) {
- return;
- }
- const emmet = vscode.extensions.getExtension('vscode.emmet');
- if (!emmet) {
- return;
- }
-
- const emmetIncludeLanguages = getEmmetIncludeLanguages();
- if (emmetIncludeLanguages && emmetIncludeLanguages['astro']) {
- return;
- }
- setEmmetIncludeLanguages({ ...emmetIncludeLanguages, astro: 'html' });
- }
- function getEmmetIncludeLanguages() {
- return vscode.workspace.getConfiguration('emmet').get<Record<string, string>>('includeLanguages');
- }
- function setEmmetIncludeLanguages(value: Record<string, string>) {
- return vscode.workspace.getConfiguration('emmet').set('includeLanguages', value);
- }
-}
diff --git a/vscode/packages/client/src/html/autoClose.ts b/vscode/packages/client/src/html/autoClose.ts
new file mode 100644
index 000000000..0dbce66c8
--- /dev/null
+++ b/vscode/packages/client/src/html/autoClose.ts
@@ -0,0 +1,108 @@
+// Original source: https://github.com/Microsoft/vscode/blob/master/extensions/html-language-features/client/src/tagClosing.ts
+
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+'use strict';
+
+import { window, workspace, Disposable, TextDocument, Position, SnippetString } from 'vscode';
+
+import { TextDocumentContentChangeEvent } from 'vscode-languageserver-protocol';
+
+/** */
+export function activateTagClosing(
+ tagProvider: (document: TextDocument, position: Position) => Thenable<string>,
+ supportedLanguages: { [id: string]: boolean },
+ configName: string
+): Disposable {
+ const disposables: Disposable[] = [];
+ workspace.onDidChangeTextDocument(
+ (event) => onDidChangeTextDocument(event.document, event.contentChanges),
+ null,
+ disposables
+ );
+
+ let isEnabled = false;
+ updateEnabledState();
+ window.onDidChangeActiveTextEditor(updateEnabledState, null, disposables);
+
+ let timeout: NodeJS.Timer | undefined = void 0;
+
+ /** Check if this feature is enabled */
+ function updateEnabledState() {
+ isEnabled = false;
+ const editor = window.activeTextEditor;
+ if (!editor) {
+ return;
+ }
+ const document = editor.document;
+ if (!supportedLanguages[document.languageId]) {
+ return;
+ }
+ if (!workspace.getConfiguration(void 0, document.uri).get<boolean>(configName)) {
+ return;
+ }
+ isEnabled = true;
+ }
+
+ /** Handle text document changes */
+ function onDidChangeTextDocument(
+ document: TextDocument,
+ changes: readonly TextDocumentContentChangeEvent[]
+ ) {
+ if (!isEnabled) {
+ return;
+ }
+ const activeDocument = window.activeTextEditor && window.activeTextEditor.document;
+ if (document !== activeDocument || changes.length === 0) {
+ return;
+ }
+ if (typeof timeout !== 'undefined') {
+ clearTimeout(timeout);
+ }
+ const lastChange = changes[changes.length - 1];
+ const lastCharacter = lastChange.text[lastChange.text.length - 1];
+ if (
+ ('range' in lastChange && (lastChange.rangeLength ?? 0) > 0) ||
+ (lastCharacter !== '>' && lastCharacter !== '/')
+ ) {
+ return;
+ }
+ const rangeStart =
+ 'range' in lastChange
+ ? lastChange.range.start
+ : new Position(0, document.getText().length);
+ const version = document.version;
+ timeout = setTimeout(() => {
+ const position = new Position(
+ rangeStart.line,
+ rangeStart.character + lastChange.text.length
+ );
+ tagProvider(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)
+ );
+ } else {
+ activeEditor.insertSnippet(new SnippetString(text), position);
+ }
+ }
+ }
+ }
+ });
+ timeout = void 0;
+ }, 100);
+ }
+ return Disposable.from(...disposables);
+}
diff --git a/vscode/packages/client/src/index.ts b/vscode/packages/client/src/index.ts
index c7233892b..9ed016eb0 100644
--- a/vscode/packages/client/src/index.ts
+++ b/vscode/packages/client/src/index.ts
@@ -1,21 +1,22 @@
import * as path from 'path';
import * as vscode from 'vscode';
import * as lsp from 'vscode-languageclient/node';
-
-import * as defaultSettings from './features/defaultSettings.js';
+import { activateTagClosing } from './html/autoClose';
let docClient: lsp.LanguageClient;
+const TagCloseRequest: lsp.RequestType<lsp.TextDocumentPositionParams, string, any> = new lsp.RequestType('html/tag');
+
+/** */
export async function activate(context: vscode.ExtensionContext) {
docClient = createLanguageService(context, 'doc', 'astro', 'Astro', 6040);
- defaultSettings.activate();
-
await docClient.onReady();
- startEmbeddedLanguageServices();
}
+/** */
function createLanguageService(context: vscode.ExtensionContext, mode: 'doc', id: string, name: string, port: number) {
+ const { workspace } = vscode;
const serverModule = context.asAbsolutePath(path.join('dist', 'server.js'));
const debugOptions = { execArgv: ['--nolazy', '--inspect=' + port] };
const serverOptions: lsp.ServerOptions = {
@@ -33,47 +34,33 @@ function createLanguageService(context: vscode.ExtensionContext, mode: 'doc', id
};
const clientOptions: lsp.LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'astro' }],
- initializationOptions: serverInitOptions,
+ synchronize: {
+ configurationSection: ['javascript', 'typescript', 'prettier'],
+ fileEvents: workspace.createFileSystemWatcher('{**/*.js,**/*.ts}', false, false, false),
+ },
+ initializationOptions: {
+ ...serverInitOptions,
+ configuration: {
+ prettier: workspace.getConfiguration('prettier'),
+ emmet: workspace.getConfiguration('emmet'),
+ typescript: workspace.getConfiguration('typescript'),
+ javascript: workspace.getConfiguration('javascript'),
+ },
+ dontFilterIncompleteCompletions: true, // VSCode filters client side and is smarter at it than us
+ },
};
const client = new lsp.LanguageClient(id, name, serverOptions, clientOptions);
- context.subscriptions.push(client.start());
- return client;
-}
-
-async function startEmbeddedLanguageServices() {
- const ts = vscode.extensions.getExtension('vscode.typescript-language-features');
- const css = vscode.extensions.getExtension('vscode.css-language-features');
- const html = vscode.extensions.getExtension('vscode.html-language-features');
-
- if (ts && !ts.isActive) {
- await ts.activate();
- }
- if (css && !css.isActive) {
- await css.activate();
- }
- if (html && !html.isActive) {
- await html.activate();
- }
+ context.subscriptions.push(client.start());
- /* from html-language-features */
- const EMPTY_ELEMENTS: string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'];
- vscode.languages.setLanguageConfiguration('astro', {
- indentationRules: {
- increaseIndentPattern: /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|link|meta|param)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|<!--(?!.*-->)|\{[^}"']*$/,
- decreaseIndentPattern: /^\s*(<\/(?!html)[-_\.A-Za-z0-9]+\b[^>]*>|-->|\})/,
- },
- wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,
- onEnterRules: [
- {
- beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'),
- afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>/i,
- action: { indentAction: vscode.IndentAction.IndentOutdent },
- },
- {
- beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'),
- action: { indentAction: vscode.IndentAction.Indent },
- },
- ],
+ client.onReady().then(() => {
+ const tagRequestor = (document: vscode.TextDocument, position: vscode.Position) => {
+ const param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position);
+ return client.sendRequest(TagCloseRequest, param);
+ };
+ const disposable = activateTagClosing(tagRequestor, { astro: true }, 'html.autoClosingTags');
+ context.subscriptions.push(disposable);
});
+
+ return client;
}