From 263ab1fb98faf2d5c2951aaaf132cfcb108c349d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 11 Apr 2018 14:57:57 -0700 Subject: [PATCH] Fix #46639 --- .../css-language-features/.vscode/launch.json | 4 +- .../server/src/cssServerMain.ts | 4 +- .../server/src/pathCompletion.ts | 48 +++++++++++-------- .../server/src/test/completion.test.ts | 30 ++++++++++++ 4 files changed, 62 insertions(+), 24 deletions(-) diff --git a/extensions/css-language-features/.vscode/launch.json b/extensions/css-language-features/.vscode/launch.json index 43e9880333e5d..68f7c70e450ee 100644 --- a/extensions/css-language-features/.vscode/launch.json +++ b/extensions/css-language-features/.vscode/launch.json @@ -17,8 +17,8 @@ ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceFolder}/client/out/**/*.js"] - // "preLaunchTask": "npm" + "outFiles": ["${workspaceFolder}/client/out/**/*.js"], + "preLaunchTask": "npm" }, { "name": "Launch Tests", diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index 77eedcb624da3..bd2a13c712424 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -76,7 +76,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { let capabilities: ServerCapabilities & FoldingProviderServerCapabilities = { // Tell the client that the server works in FULL text document sync mode textDocumentSync: documents.syncKind, - completionProvider: snippetSupport ? { resolveProvider: false } : undefined, + completionProvider: snippetSupport ? { resolveProvider: false, triggerCharacters: ['/'] } : undefined, hoverProvider: true, documentSymbolProvider: true, referencesProvider: true, @@ -192,7 +192,7 @@ connection.onCompletion((textDocumentPosition, token) => { cssLS.setCompletionParticipants([getPathCompletionParticipant(document, workspaceFolders, pathCompletionList)]); const result = cssLS.doComplete(document, textDocumentPosition.position, stylesheets.get(document))!; /* TODO: remove ! once LS has null annotations */ return { - isIncomplete: result.isIncomplete, + isIncomplete: pathCompletionList.isIncomplete, items: [...pathCompletionList.items, ...result.items] }; }, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`, token); diff --git a/extensions/css-language-features/server/src/pathCompletion.ts b/extensions/css-language-features/server/src/pathCompletion.ts index 9bf9df83e5e73..4859ae5aab7d4 100644 --- a/extensions/css-language-features/server/src/pathCompletion.ts +++ b/extensions/css-language-features/server/src/pathCompletion.ts @@ -21,18 +21,29 @@ export function getPathCompletionParticipant( ): ICompletionParticipant { return { onURILiteralValue: ({ position, range, uriValue }) => { + const isValueQuoted = startsWith(uriValue, `'`) || startsWith(uriValue, `"`); const fullValue = stripQuotes(uriValue); + const valueBeforeCursor = isValueQuoted + ? fullValue.slice(0, position.character - (range.start.character + 1)) + : fullValue.slice(0, position.character - range.start.character); - if (shouldDoPathCompletion(fullValue)) { - if (!workspaceFolders || workspaceFolders.length === 0) { - return; - } - const workspaceRoot = resolveWorkspaceRoot(document, workspaceFolders); + if (fullValue === '.' || fullValue === '..') { + result.isIncomplete = true; + return; + } - const paths = providePaths(fullValue, URI.parse(document.uri).fsPath, workspaceRoot); - result.items = [...paths.map(p => pathToSuggestion(p, fullValue, fullValue, range)), ...result.items]; + if (!workspaceFolders || workspaceFolders.length === 0) { + return; } + const workspaceRoot = resolveWorkspaceRoot(document, workspaceFolders); + const paths = providePaths(valueBeforeCursor, URI.parse(document.uri).fsPath, workspaceRoot); + + const fullValueRange = isValueQuoted ? shiftRange(range, 1, -1) : range; + const replaceRange = pathToReplaceRange(valueBeforeCursor, fullValue, fullValueRange); + const suggestions = paths.map(p => pathToSuggestion(p, replaceRange)); + result.items = [...suggestions, ...result.items]; } + }; } @@ -44,13 +55,6 @@ function stripQuotes(fullValue: string) { } } -function shouldDoPathCompletion(fullValue: string) { - if (fullValue === '.') { - return false; - } - return true; -} - /** * Get a list of path suggestions. Folder suggestions are suffixed with a slash. */ @@ -85,29 +89,33 @@ const isDir = (p: string) => { } }; -function pathToSuggestion(p: string, valueBeforeCursor: string, fullValue: string, range: Range): CompletionItem { - const isDir = p[p.length - 1] === '/'; - +function pathToReplaceRange(valueBeforeCursor: string, fullValue: string, fullValueRange: Range) { let replaceRange: Range; const lastIndexOfSlash = valueBeforeCursor.lastIndexOf('/'); if (lastIndexOfSlash === -1) { - replaceRange = shiftRange(range, 1, -1); + replaceRange = fullValueRange; } else { // For cases where cursor is in the middle of attribute value, like