From d78c235d35346722dc3004a20d451aaadb8c62c4 Mon Sep 17 00:00:00 2001 From: Lyu Jason Date: Wed, 3 Mar 2021 14:11:02 +0800 Subject: [PATCH 1/2] linked editing for html --- packages/language-server/src/ls-config.ts | 6 ++++- .../language-server/src/plugins/PluginHost.ts | 17 ++++++++++++ .../src/plugins/html/HTMLPlugin.ts | 26 ++++++++++++++++--- .../language-server/src/plugins/interfaces.ts | 11 +++++++- packages/language-server/src/server.ts | 11 ++++++-- .../test/plugins/html/HTMLPlugin.test.ts | 12 +++++++++ packages/svelte-vscode/README.md | 4 +++ packages/svelte-vscode/package.json | 6 +++++ packages/svelte2tsx/README.md | 1 - 9 files changed, 86 insertions(+), 8 deletions(-) diff --git a/packages/language-server/src/ls-config.ts b/packages/language-server/src/ls-config.ts index 164fd167f..cce195c59 100644 --- a/packages/language-server/src/ls-config.ts +++ b/packages/language-server/src/ls-config.ts @@ -36,7 +36,8 @@ const defaultLSConfig: LSConfig = { hover: { enable: true }, completions: { enable: true, emmet: true }, tagComplete: { enable: true }, - documentSymbols: { enable: true } + documentSymbols: { enable: true }, + linkedEditing: { enable: true } }, svelte: { enable: true, @@ -152,6 +153,9 @@ export interface LSHTMLConfig { documentSymbols: { enable: boolean; }; + linkedEditing: { + enable: boolean; + }; } export type CompilerWarningsSettings = Record; diff --git a/packages/language-server/src/plugins/PluginHost.ts b/packages/language-server/src/plugins/PluginHost.ts index 3ab09fb9a..c32c47228 100644 --- a/packages/language-server/src/plugins/PluginHost.ts +++ b/packages/language-server/src/plugins/PluginHost.ts @@ -12,6 +12,7 @@ import { Diagnostic, FormattingOptions, Hover, + LinkedEditingRanges, Location, Position, Range, @@ -415,6 +416,22 @@ export class PluginHost implements LSProvider, OnWatchFileChanges { ); } + async getLinkedEditingRanges( + textDocument: TextDocumentIdentifier, + position: Position + ): Promise { + const document = this.getDocument(textDocument.uri); + if (!document) { + throw new Error('Cannot call methods on an unopened document'); + } + + return await this.execute( + 'getLinkedEditingRanges', + [document, position], + ExecuteMode.FirstNonNull + ); + } + onWatchFileChanges(onWatchFileChangesParas: OnWatchFileChangesPara[]): void { for (const support of this.plugins) { support.onWatchFileChanges?.(onWatchFileChangesParas); diff --git a/packages/language-server/src/plugins/html/HTMLPlugin.ts b/packages/language-server/src/plugins/html/HTMLPlugin.ts index be23d269d..cc0b678b2 100644 --- a/packages/language-server/src/plugins/html/HTMLPlugin.ts +++ b/packages/language-server/src/plugins/html/HTMLPlugin.ts @@ -11,7 +11,8 @@ import { SymbolInformation, CompletionItem, CompletionItemKind, - TextEdit + TextEdit, + LinkedEditingRanges } from 'vscode-languageserver'; import { DocumentManager, @@ -21,10 +22,10 @@ import { } from '../../lib/documents'; import { LSConfigManager, LSHTMLConfig } from '../../ls-config'; import { svelteHtmlDataProvider } from './dataProvider'; -import { HoverProvider, CompletionsProvider } from '../interfaces'; +import { HoverProvider, CompletionsProvider, LinkedEditingRangesProvider } from '../interfaces'; import { isInsideMoustacheTag } from '../../lib/documents/utils'; -export class HTMLPlugin implements HoverProvider, CompletionsProvider { +export class HTMLPlugin implements HoverProvider, CompletionsProvider, LinkedEditingRangesProvider { private configManager: LSConfigManager; private lang = getLanguageService({ customDataProviders: [svelteHtmlDataProvider], @@ -206,6 +207,25 @@ export class HTMLPlugin implements HoverProvider, CompletionsProvider { return this.lang.findDocumentSymbols(document, html); } + getLinkedEditingRanges(document: Document, position: Position): LinkedEditingRanges | null { + if (!this.featureEnabled('linkedEditing')) { + return null; + } + + const html = this.documents.get(document); + if (!html) { + return null; + } + + const ranges = this.lang.findLinkedEditingRanges(document, position, html); + + if (!ranges) { + return null; + } + + return { ranges }; + } + private featureEnabled(feature: keyof LSHTMLConfig) { return ( this.configManager.enabled('html.enable') && diff --git a/packages/language-server/src/plugins/interfaces.ts b/packages/language-server/src/plugins/interfaces.ts index a4a7ac37d..a4d1122c5 100644 --- a/packages/language-server/src/plugins/interfaces.ts +++ b/packages/language-server/src/plugins/interfaces.ts @@ -1,6 +1,7 @@ import { CompletionContext, FileChangeType, + LinkedEditingRanges, SemanticTokens, SignatureHelpContext, TextDocumentContentChangeEvent @@ -151,6 +152,13 @@ export interface SemanticTokensProvider { getSemanticTokens(textDocument: Document, range?: Range): Resolvable; } +export interface LinkedEditingRangesProvider { + getLinkedEditingRanges( + document: Document, + position: Position + ): Resolvable; +} + export interface OnWatchFileChangesPara { fileName: string; changeType: FileChangeType; @@ -177,7 +185,8 @@ type ProviderBase = DiagnosticsProvider & FindReferencesProvider & RenameProvider & SignatureHelpProvider & - SemanticTokensProvider; + SemanticTokensProvider & + LinkedEditingRangesProvider; export type LSProvider = ProviderBase & BackwardsCompatibleDefinitionsProvider; diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index e42e1bee0..167fc9f81 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -14,7 +14,8 @@ import { TextDocumentSyncKind, WorkspaceEdit, SemanticTokensRequest, - SemanticTokensRangeRequest + SemanticTokensRangeRequest, + LinkedEditingRangeRequest } from 'vscode-languageserver'; import { IPCMessageReader, IPCMessageWriter, createConnection } from 'vscode-languageserver/node'; import { DiagnosticsManager } from './lib/DiagnosticsManager'; @@ -194,7 +195,8 @@ export function startServer(options?: LSOptions) { legend: getSemanticTokenLegends(), range: true, full: true - } + }, + linkedEditingRangeProvider: true } }; }); @@ -313,6 +315,11 @@ export function startServer(options?: LSOptions) { pluginHost.getSemanticTokens(evt.textDocument, evt.range) ); + connection.onRequest( + LinkedEditingRangeRequest.type, + async (evt) => await pluginHost.getLinkedEditingRanges(evt.textDocument, evt.position) + ); + docManager.on( 'documentChange', _.debounce(async (document: Document) => diagnosticsManager.update(document), 500) diff --git a/packages/language-server/test/plugins/html/HTMLPlugin.test.ts b/packages/language-server/test/plugins/html/HTMLPlugin.test.ts index 1f0c34b55..9970d9b8a 100644 --- a/packages/language-server/test/plugins/html/HTMLPlugin.test.ts +++ b/packages/language-server/test/plugins/html/HTMLPlugin.test.ts @@ -116,4 +116,16 @@ describe('HTML Plugin', () => { undefined ); }); + + it('provides linked editing ranges', async () => { + const { plugin, document } = setup('
'); + + const ranges = plugin.getLinkedEditingRanges(document, Position.create(0, 3)); + assert.deepStrictEqual(ranges, { + ranges: [ + { start: { line: 0, character: 1 }, end: { line: 0, character: 4 } }, + { start: { line: 0, character: 7 }, end: { line: 0, character: 10 } } + ] + }); + }); }); diff --git a/packages/svelte-vscode/README.md b/packages/svelte-vscode/README.md index 5ec40bd82..3bebf8a75 100644 --- a/packages/svelte-vscode/README.md +++ b/packages/svelte-vscode/README.md @@ -190,6 +190,10 @@ Enable HTML tag auto closing. _Default_: `true` Enable document symbols for HTML. _Default_: `true` +##### `svelte.plugin.html.linkedEditing.enable` + +Enable Linked Editing for HTML. _Default_: `true` + ##### `svelte.plugin.svelte.enable` Enable the Svelte plugin. _Default_: `true` diff --git a/packages/svelte-vscode/package.json b/packages/svelte-vscode/package.json index b1a9a6f9d..c8a91e1c8 100644 --- a/packages/svelte-vscode/package.json +++ b/packages/svelte-vscode/package.json @@ -232,6 +232,12 @@ "title": "HTML: Symbols in Outline", "description": "Enable document symbols for HTML" }, + "svelte.plugin.html.linkedEditing.enable": { + "type": "boolean", + "default": true, + "title": "HTML: Linked Editing", + "description": "Enable Linked Editing for HTML" + }, "svelte.plugin.svelte.enable": { "type": "boolean", "default": true, diff --git a/packages/svelte2tsx/README.md b/packages/svelte2tsx/README.md index f15f4a000..0870c0405 100644 --- a/packages/svelte2tsx/README.md +++ b/packages/svelte2tsx/README.md @@ -23,7 +23,6 @@ Input.svelte

hello {world}

- ``` will produce this ugly but type checkable TSX From 0eac45df875d75bf9f6fb5bee04aaf2eae883028 Mon Sep 17 00:00:00 2001 From: Lyu Jason Date: Wed, 3 Mar 2021 14:24:23 +0800 Subject: [PATCH 2/2] format --- .../language-server/src/plugins/html/HTMLPlugin.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/language-server/src/plugins/html/HTMLPlugin.ts b/packages/language-server/src/plugins/html/HTMLPlugin.ts index a5051d723..874376b95 100644 --- a/packages/language-server/src/plugins/html/HTMLPlugin.ts +++ b/packages/language-server/src/plugins/html/HTMLPlugin.ts @@ -25,10 +25,16 @@ import { } from '../../lib/documents'; import { LSConfigManager, LSHTMLConfig } from '../../ls-config'; import { svelteHtmlDataProvider } from './dataProvider'; -import { HoverProvider, CompletionsProvider, RenameProvider, LinkedEditingRangesProvider } from '../interfaces'; +import { + HoverProvider, + CompletionsProvider, + RenameProvider, + LinkedEditingRangesProvider +} from '../interfaces'; import { isInsideMoustacheTag, toRange } from '../../lib/documents/utils'; -export class HTMLPlugin implements HoverProvider, CompletionsProvider, RenameProvider, LinkedEditingRangesProvider { +export class HTMLPlugin + implements HoverProvider, CompletionsProvider, RenameProvider, LinkedEditingRangesProvider { private configManager: LSConfigManager; private lang = getLanguageService({ customDataProviders: [svelteHtmlDataProvider],