From adf61a891c139667ba999ea4cfa2877f5ceb9458 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 17 Dec 2019 11:04:54 +0100 Subject: [PATCH] adopt selection provider & rename provider --- src/htmlMode.ts | 2 + src/htmlWorker.ts | 13 ++- src/languageFeatures.ts | 230 +++++++++++++++++++++++++--------------- 3 files changed, 159 insertions(+), 86 deletions(-) diff --git a/src/htmlMode.ts b/src/htmlMode.ts index da96f530..c1dd9795 100644 --- a/src/htmlMode.ts +++ b/src/htmlMode.ts @@ -29,6 +29,8 @@ export function setupMode(defaults: LanguageServiceDefaultsImpl): void { monaco.languages.registerLinkProvider(languageId, new languageFeatures.DocumentLinkAdapter(worker)); monaco.languages.registerFoldingRangeProvider(languageId, new languageFeatures.FoldingRangeAdapter(worker)); monaco.languages.registerDocumentSymbolProvider(languageId, new languageFeatures.DocumentSymbolAdapter(worker)); + monaco.languages.registerSelectionRangeProvider(languageId, new languageFeatures.SelectionRangeAdapter(worker)); + monaco.languages.registerRenameProvider(languageId, new languageFeatures.RenameAdapter(worker)); // only html if (languageId === 'html') { diff --git a/src/htmlWorker.ts b/src/htmlWorker.ts index a1a26f12..884ac6d4 100644 --- a/src/htmlWorker.ts +++ b/src/htmlWorker.ts @@ -65,11 +65,22 @@ export class HTMLWorker { let symbols = this._languageService.findDocumentSymbols(document, htmlDocument); return Promise.resolve(symbols); } - provideFoldingRanges(uri: string, context?: { rangeLimit?: number; }): Thenable { + getFoldingRanges(uri: string, context?: { rangeLimit?: number; }): Thenable { let document = this._getTextDocument(uri); let ranges = this._languageService.getFoldingRanges(document, context); return Promise.resolve(ranges); } + getSelectionRanges(uri: string, positions: htmlService.Position[]): Thenable { + let document = this._getTextDocument(uri); + let ranges = this._languageService.getSelectionRanges(document, positions); + return Promise.resolve(ranges); + } + doRename(uri: string, position: htmlService.Position, newName: string): Thenable { + let document = this._getTextDocument(uri); + let htmlDocument = this._languageService.parseHTMLDocument(document); + let renames = this._languageService.doRename(document, position, newName, htmlDocument); + return Promise.resolve(renames); + } private _getTextDocument(uri: string): htmlService.TextDocument { let models = this._ctx.getMirrorModels(); for (let model of models) { diff --git a/src/languageFeatures.ts b/src/languageFeatures.ts index 1b5654ce..58adacca 100644 --- a/src/languageFeatures.ts +++ b/src/languageFeatures.ts @@ -7,7 +7,7 @@ import { LanguageServiceDefaultsImpl } from './monaco.contribution'; import { HTMLWorker } from './htmlWorker'; -import * as ls from 'vscode-languageserver-types'; +import * as htmlService from 'vscode-html-languageservice'; import Uri = monaco.Uri; import Position = monaco.Position; @@ -103,16 +103,16 @@ export class DiagnosticsAdapter { function toSeverity(lsSeverity: number): monaco.MarkerSeverity { switch (lsSeverity) { - case ls.DiagnosticSeverity.Error: return monaco.MarkerSeverity.Error; - case ls.DiagnosticSeverity.Warning: return monaco.MarkerSeverity.Warning; - case ls.DiagnosticSeverity.Information: return monaco.MarkerSeverity.Info; - case ls.DiagnosticSeverity.Hint: return monaco.MarkerSeverity.Hint; + case htmlService.DiagnosticSeverity.Error: return monaco.MarkerSeverity.Error; + case htmlService.DiagnosticSeverity.Warning: return monaco.MarkerSeverity.Warning; + case htmlService.DiagnosticSeverity.Information: return monaco.MarkerSeverity.Info; + case htmlService.DiagnosticSeverity.Hint: return monaco.MarkerSeverity.Hint; default: return monaco.MarkerSeverity.Info; } } -function toDiagnostics(resource: Uri, diag: ls.Diagnostic): monaco.editor.IMarkerData { +function toDiagnostics(resource: Uri, diag: htmlService.Diagnostic): monaco.editor.IMarkerData { const code = typeof diag.code === 'number' ? String(diag.code) : diag.code; return { @@ -129,21 +129,21 @@ function toDiagnostics(resource: Uri, diag: ls.Diagnostic): monaco.editor.IMarke // --- completion ------ -function fromPosition(position: Position): ls.Position { +function fromPosition(position: Position): htmlService.Position { if (!position) { return void 0; } return { character: position.column - 1, line: position.lineNumber - 1 }; } -function fromRange(range: Range): ls.Range { +function fromRange(range: Range): htmlService.Range { if (!range) { return void 0; } return { start: fromPosition(range.getStartPosition()), end: fromPosition(range.getEndPosition()) }; } -function toRange(range: ls.Range): Range { +function toRange(range: htmlService.Range): Range { if (!range) { return void 0; } @@ -154,55 +154,55 @@ function toCompletionItemKind(kind: number): monaco.languages.CompletionItemKind const mItemKind = monaco.languages.CompletionItemKind; switch (kind) { - case ls.CompletionItemKind.Text: return mItemKind.Text; - case ls.CompletionItemKind.Method: return mItemKind.Method; - case ls.CompletionItemKind.Function: return mItemKind.Function; - case ls.CompletionItemKind.Constructor: return mItemKind.Constructor; - case ls.CompletionItemKind.Field: return mItemKind.Field; - case ls.CompletionItemKind.Variable: return mItemKind.Variable; - case ls.CompletionItemKind.Class: return mItemKind.Class; - case ls.CompletionItemKind.Interface: return mItemKind.Interface; - case ls.CompletionItemKind.Module: return mItemKind.Module; - case ls.CompletionItemKind.Property: return mItemKind.Property; - case ls.CompletionItemKind.Unit: return mItemKind.Unit; - case ls.CompletionItemKind.Value: return mItemKind.Value; - case ls.CompletionItemKind.Enum: return mItemKind.Enum; - case ls.CompletionItemKind.Keyword: return mItemKind.Keyword; - case ls.CompletionItemKind.Snippet: return mItemKind.Snippet; - case ls.CompletionItemKind.Color: return mItemKind.Color; - case ls.CompletionItemKind.File: return mItemKind.File; - case ls.CompletionItemKind.Reference: return mItemKind.Reference; + case htmlService.CompletionItemKind.Text: return mItemKind.Text; + case htmlService.CompletionItemKind.Method: return mItemKind.Method; + case htmlService.CompletionItemKind.Function: return mItemKind.Function; + case htmlService.CompletionItemKind.Constructor: return mItemKind.Constructor; + case htmlService.CompletionItemKind.Field: return mItemKind.Field; + case htmlService.CompletionItemKind.Variable: return mItemKind.Variable; + case htmlService.CompletionItemKind.Class: return mItemKind.Class; + case htmlService.CompletionItemKind.Interface: return mItemKind.Interface; + case htmlService.CompletionItemKind.Module: return mItemKind.Module; + case htmlService.CompletionItemKind.Property: return mItemKind.Property; + case htmlService.CompletionItemKind.Unit: return mItemKind.Unit; + case htmlService.CompletionItemKind.Value: return mItemKind.Value; + case htmlService.CompletionItemKind.Enum: return mItemKind.Enum; + case htmlService.CompletionItemKind.Keyword: return mItemKind.Keyword; + case htmlService.CompletionItemKind.Snippet: return mItemKind.Snippet; + case htmlService.CompletionItemKind.Color: return mItemKind.Color; + case htmlService.CompletionItemKind.File: return mItemKind.File; + case htmlService.CompletionItemKind.Reference: return mItemKind.Reference; } return mItemKind.Property; } -function fromCompletionItemKind(kind: monaco.languages.CompletionItemKind): ls.CompletionItemKind { +function fromCompletionItemKind(kind: monaco.languages.CompletionItemKind): htmlService.CompletionItemKind { const mItemKind = monaco.languages.CompletionItemKind; switch (kind) { - case mItemKind.Text: return ls.CompletionItemKind.Text; - case mItemKind.Method: return ls.CompletionItemKind.Method; - case mItemKind.Function: return ls.CompletionItemKind.Function; - case mItemKind.Constructor: return ls.CompletionItemKind.Constructor; - case mItemKind.Field: return ls.CompletionItemKind.Field; - case mItemKind.Variable: return ls.CompletionItemKind.Variable; - case mItemKind.Class: return ls.CompletionItemKind.Class; - case mItemKind.Interface: return ls.CompletionItemKind.Interface; - case mItemKind.Module: return ls.CompletionItemKind.Module; - case mItemKind.Property: return ls.CompletionItemKind.Property; - case mItemKind.Unit: return ls.CompletionItemKind.Unit; - case mItemKind.Value: return ls.CompletionItemKind.Value; - case mItemKind.Enum: return ls.CompletionItemKind.Enum; - case mItemKind.Keyword: return ls.CompletionItemKind.Keyword; - case mItemKind.Snippet: return ls.CompletionItemKind.Snippet; - case mItemKind.Color: return ls.CompletionItemKind.Color; - case mItemKind.File: return ls.CompletionItemKind.File; - case mItemKind.Reference: return ls.CompletionItemKind.Reference; - } - return ls.CompletionItemKind.Property; + case mItemKind.Text: return htmlService.CompletionItemKind.Text; + case mItemKind.Method: return htmlService.CompletionItemKind.Method; + case mItemKind.Function: return htmlService.CompletionItemKind.Function; + case mItemKind.Constructor: return htmlService.CompletionItemKind.Constructor; + case mItemKind.Field: return htmlService.CompletionItemKind.Field; + case mItemKind.Variable: return htmlService.CompletionItemKind.Variable; + case mItemKind.Class: return htmlService.CompletionItemKind.Class; + case mItemKind.Interface: return htmlService.CompletionItemKind.Interface; + case mItemKind.Module: return htmlService.CompletionItemKind.Module; + case mItemKind.Property: return htmlService.CompletionItemKind.Property; + case mItemKind.Unit: return htmlService.CompletionItemKind.Unit; + case mItemKind.Value: return htmlService.CompletionItemKind.Value; + case mItemKind.Enum: return htmlService.CompletionItemKind.Enum; + case mItemKind.Keyword: return htmlService.CompletionItemKind.Keyword; + case mItemKind.Snippet: return htmlService.CompletionItemKind.Snippet; + case mItemKind.Color: return htmlService.CompletionItemKind.Color; + case mItemKind.File: return htmlService.CompletionItemKind.File; + case mItemKind.Reference: return htmlService.CompletionItemKind.Reference; + } + return htmlService.CompletionItemKind.Property; } -function toTextEdit(textEdit: ls.TextEdit): monaco.editor.ISingleEditOperation { +function toTextEdit(textEdit: htmlService.TextEdit): monaco.editor.ISingleEditOperation { if (!textEdit) { return void 0; } @@ -251,7 +251,7 @@ export class CompletionAdapter implements monaco.languages.CompletionItemProvide if (entry.additionalTextEdits) { item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit) } - if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) { + if (entry.insertTextFormat === htmlService.InsertTextFormat.Snippet) { item.insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet; } return item; @@ -267,11 +267,11 @@ export class CompletionAdapter implements monaco.languages.CompletionItemProvide // --- hover ------ -function isMarkupContent(thing: any): thing is ls.MarkupContent { - return thing && typeof thing === 'object' && typeof (thing).kind === 'string'; +function isMarkupContent(thing: any): thing is htmlService.MarkupContent { + return thing && typeof thing === 'object' && typeof (thing).kind === 'string'; } -function toMarkdownString(entry: ls.MarkupContent | ls.MarkedString): monaco.IMarkdownString { +function toMarkdownString(entry: htmlService.MarkupContent | htmlService.MarkedString): monaco.IMarkdownString { if (typeof entry === 'string') { return { value: entry @@ -291,7 +291,7 @@ function toMarkdownString(entry: ls.MarkupContent | ls.MarkedString): monaco.IMa return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' }; } -function toMarkedStringArray(contents: ls.MarkupContent | ls.MarkedString | ls.MarkedString[]): monaco.IMarkdownString[] { +function toMarkedStringArray(contents: htmlService.MarkupContent | htmlService.MarkedString | htmlService.MarkedString[]): monaco.IMarkdownString[] { if (!contents) { return void 0; } @@ -325,13 +325,13 @@ export class HoverAdapter implements monaco.languages.HoverProvider { // --- document highlights ------ -function toHighlighKind(kind: ls.DocumentHighlightKind): monaco.languages.DocumentHighlightKind { +function toHighlighKind(kind: htmlService.DocumentHighlightKind): monaco.languages.DocumentHighlightKind { const mKind = monaco.languages.DocumentHighlightKind; switch (kind) { - case ls.DocumentHighlightKind.Read: return mKind.Read; - case ls.DocumentHighlightKind.Write: return mKind.Write; - case ls.DocumentHighlightKind.Text: return mKind.Text; + case htmlService.DocumentHighlightKind.Read: return mKind.Read; + case htmlService.DocumentHighlightKind.Write: return mKind.Write; + case htmlService.DocumentHighlightKind.Text: return mKind.Text; } return mKind.Text; } @@ -359,28 +359,28 @@ export class DocumentHighlightAdapter implements monaco.languages.DocumentHighli // --- document symbols ------ -function toSymbolKind(kind: ls.SymbolKind): monaco.languages.SymbolKind { +function toSymbolKind(kind: htmlService.SymbolKind): monaco.languages.SymbolKind { let mKind = monaco.languages.SymbolKind; switch (kind) { - case ls.SymbolKind.File: return mKind.Array; - case ls.SymbolKind.Module: return mKind.Module; - case ls.SymbolKind.Namespace: return mKind.Namespace; - case ls.SymbolKind.Package: return mKind.Package; - case ls.SymbolKind.Class: return mKind.Class; - case ls.SymbolKind.Method: return mKind.Method; - case ls.SymbolKind.Property: return mKind.Property; - case ls.SymbolKind.Field: return mKind.Field; - case ls.SymbolKind.Constructor: return mKind.Constructor; - case ls.SymbolKind.Enum: return mKind.Enum; - case ls.SymbolKind.Interface: return mKind.Interface; - case ls.SymbolKind.Function: return mKind.Function; - case ls.SymbolKind.Variable: return mKind.Variable; - case ls.SymbolKind.Constant: return mKind.Constant; - case ls.SymbolKind.String: return mKind.String; - case ls.SymbolKind.Number: return mKind.Number; - case ls.SymbolKind.Boolean: return mKind.Boolean; - case ls.SymbolKind.Array: return mKind.Array; + case htmlService.SymbolKind.File: return mKind.Array; + case htmlService.SymbolKind.Module: return mKind.Module; + case htmlService.SymbolKind.Namespace: return mKind.Namespace; + case htmlService.SymbolKind.Package: return mKind.Package; + case htmlService.SymbolKind.Class: return mKind.Class; + case htmlService.SymbolKind.Method: return mKind.Method; + case htmlService.SymbolKind.Property: return mKind.Property; + case htmlService.SymbolKind.Field: return mKind.Field; + case htmlService.SymbolKind.Constructor: return mKind.Constructor; + case htmlService.SymbolKind.Enum: return mKind.Enum; + case htmlService.SymbolKind.Interface: return mKind.Interface; + case htmlService.SymbolKind.Function: return mKind.Function; + case htmlService.SymbolKind.Variable: return mKind.Variable; + case htmlService.SymbolKind.Constant: return mKind.Constant; + case htmlService.SymbolKind.String: return mKind.String; + case htmlService.SymbolKind.Number: return mKind.Number; + case htmlService.SymbolKind.Boolean: return mKind.Boolean; + case htmlService.SymbolKind.Array: return mKind.Array; } return mKind.Function; } @@ -433,7 +433,7 @@ export class DocumentLinkAdapter implements monaco.languages.LinkProvider { } -function fromFormattingOptions(options: monaco.languages.FormattingOptions): ls.FormattingOptions { +function fromFormattingOptions(options: monaco.languages.FormattingOptions): htmlService.FormattingOptions { return { tabSize: options.tabSize, insertSpaces: options.insertSpaces @@ -478,6 +478,42 @@ export class DocumentRangeFormattingEditProvider implements monaco.languages.Doc } } +export class RenameAdapter implements monaco.languages.RenameProvider { + + constructor(private _worker: WorkerAccessor) { + } + + provideRenameEdits(model: monaco.editor.IReadOnlyModel, position: Position, newName: string, token: CancellationToken): Thenable { + const resource = model.uri; + + return this._worker(resource).then(worker => { + return worker.doRename(resource.toString(), fromPosition(position), newName); + }).then(edit => { + return toWorkspaceEdit(edit); + }); + } +} + +function toWorkspaceEdit(edit: htmlService.WorkspaceEdit): monaco.languages.WorkspaceEdit { + if (!edit || !edit.changes) { + return void 0; + } + let resourceEdits: monaco.languages.ResourceTextEdit[] = []; + for (let uri in edit.changes) { + let edits: monaco.languages.TextEdit[] = []; + for (let e of edit.changes[uri]) { + edits.push({ + range: toRange(e.range), + text: e.newText + }); + } + resourceEdits.push({ resource: Uri.parse(uri), edits: edits }); + } + return { + edits: resourceEdits + } +} + export class FoldingRangeAdapter implements monaco.languages.FoldingRangeProvider { constructor(private _worker: WorkerAccessor) { @@ -486,7 +522,7 @@ export class FoldingRangeAdapter implements monaco.languages.FoldingRangeProvide public provideFoldingRanges(model: monaco.editor.IReadOnlyModel, context: monaco.languages.FoldingContext, token: CancellationToken): Thenable { const resource = model.uri; - return this._worker(resource).then(worker => worker.provideFoldingRanges(resource.toString(), context)).then(ranges => { + return this._worker(resource).then(worker => worker.getFoldingRanges(resource.toString(), context)).then(ranges => { if (!ranges) { return; } @@ -496,7 +532,7 @@ export class FoldingRangeAdapter implements monaco.languages.FoldingRangeProvide end: range.endLine + 1 }; if (typeof range.kind !== 'undefined') { - result.kind = toFoldingRangeKind(range.kind); + result.kind = toFoldingRangeKind(range.kind); } return result; }); @@ -505,11 +541,35 @@ export class FoldingRangeAdapter implements monaco.languages.FoldingRangeProvide } -function toFoldingRangeKind(kind: ls.FoldingRangeKind): monaco.languages.FoldingRangeKind { +function toFoldingRangeKind(kind: htmlService.FoldingRangeKind): monaco.languages.FoldingRangeKind { switch (kind) { - case ls.FoldingRangeKind.Comment: return monaco.languages.FoldingRangeKind.Comment; - case ls.FoldingRangeKind.Imports: return monaco.languages.FoldingRangeKind.Imports; - case ls.FoldingRangeKind.Region: return monaco.languages.FoldingRangeKind.Region; + case htmlService.FoldingRangeKind.Comment: return monaco.languages.FoldingRangeKind.Comment; + case htmlService.FoldingRangeKind.Imports: return monaco.languages.FoldingRangeKind.Imports; + case htmlService.FoldingRangeKind.Region: return monaco.languages.FoldingRangeKind.Region; } - return void 0; } + +export class SelectionRangeAdapter implements monaco.languages.SelectionRangeProvider { + + constructor(private _worker: WorkerAccessor) { + } + + public provideSelectionRanges(model: monaco.editor.IReadOnlyModel, positions: Position[], token: CancellationToken): Thenable { + const resource = model.uri; + + return this._worker(resource).then(worker => worker.getSelectionRanges(resource.toString(), positions.map(fromPosition))).then(selectionRanges => { + if (!selectionRanges) { + return; + } + return selectionRanges.map(selectionRange => { + const result: monaco.languages.SelectionRange[] = []; + while (selectionRange) { + result.push({ range: toRange(selectionRange.range) }); + selectionRange = selectionRange.parent; + } + return result; + }); + }); + } + +} \ No newline at end of file