diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 77121fbb89b..f8e3ffd5921 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -12,7 +12,6 @@ import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; import { DocumentColorRequest, DocumentColorParams, ColorPresentationRequest, ColorPresentationParams } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import * as nls from 'vscode-nls'; @@ -65,7 +64,7 @@ export function activate(context: ExtensionContext) { // Create the language client and start the client. let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions); - client.registerFeature(new ConfigurationFeature(client)); + client.registerProposedFeatures(); let disposable = client.start(); toDispose.push(disposable); diff --git a/extensions/html/server/src/htmlServerMain.ts b/extensions/html/server/src/htmlServerMain.ts index 6687ddad854..1719e612d2a 100644 --- a/extensions/html/server/src/htmlServerMain.ts +++ b/extensions/html/server/src/htmlServerMain.ts @@ -11,9 +11,11 @@ import { getLanguageModes, LanguageModes, Settings } from './modes/languageModes import { ConfigurationRequest, ConfigurationParams } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorInformation, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { DidChangeWorkspaceFoldersNotification, WorkspaceFolder } from 'vscode-languageserver-protocol/lib/protocol.workspaceFolders.proposed'; import { format } from './modes/formatting'; import { pushAll } from './utils/arrays'; +import { endsWith, startsWith } from './utils/strings'; import * as url from 'url'; import * as path from 'path'; @@ -40,11 +42,14 @@ let documents: TextDocuments = new TextDocuments(); documents.listen(connection); let workspacePath: string | undefined | null; +let workspaceFolders: WorkspaceFolder[] | undefined; + var languageModes: LanguageModes; let clientSnippetSupport = false; let clientDynamicRegisterSupport = false; let scopedSettingsSupport = false; +let workspaceFoldersSupport = false; var globalSettings: Settings = {}; let documentSettings: { [key: string]: Thenable } = {}; @@ -73,6 +78,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { let initializationOptions = params.initializationOptions; workspacePath = params.rootPath; + workspaceFolders = (params).workspaceFolders; languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }); documents.onDidClose(e => { @@ -93,6 +99,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { clientSnippetSupport = hasClientCapability('textDocument', 'completion', 'completionItem', 'snippetSupport'); clientDynamicRegisterSupport = hasClientCapability('workspace', 'symbol', 'dynamicRegistration'); scopedSettingsSupport = hasClientCapability('workspace', 'configuration'); + workspaceFoldersSupport = hasClientCapability('workspace', 'workspaceFolders'); let capabilities: ServerCapabilities & CPServerCapabilities = { // Tell the client that the server works in FULL text document sync mode textDocumentSync: documents.syncKind, @@ -107,10 +114,29 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { referencesProvider: true, colorProvider: true }; - return { capabilities }; }); +connection.onInitialized((p) => { + if (workspaceFoldersSupport) { + connection.client.register(DidChangeWorkspaceFoldersNotification.type); + + connection.onNotification(DidChangeWorkspaceFoldersNotification.type, e => { + let toAdd = e.event.added; + let toRemove = e.event.removed; + let updatedFolders = []; + if (workspaceFolders) { + for (let folder of workspaceFolders) { + if (!toRemove.some(r => r.uri === folder.uri) && !toAdd.some(r => r.uri === folder.uri)) { + updatedFolders.push(folder); + } + } + } + workspaceFolders = updatedFolders.concat(toAdd); + }); + } +}); + let formatterRegistration: Thenable | null = null; // The settings have changed. Is send on server activation as well. @@ -284,8 +310,11 @@ connection.onDocumentLinks(documentLinkParam => { if (base) { ref = url.resolve(base, ref); } - if (workspacePath && ref[0] === '/') { - return uri.file(path.join(workspacePath, ref)).toString(); + if (ref[0] === '/') { + let root = getRootFolder(document.uri); + if (root) { + return uri.file(path.join(root, ref)).toString(); + } } return url.resolve(document.uri, ref); }, @@ -300,6 +329,22 @@ connection.onDocumentLinks(documentLinkParam => { return links; }); +function getRootFolder(docUri: string): string | undefined | null { + if (workspaceFolders) { + for (let folder of workspaceFolders) { + let folderURI = folder.uri; + if (!endsWith(folderURI, '/')) { + folderURI = folderURI + '/'; + } + if (startsWith(docUri, folderURI)) { + return folderURI; + } + } + return void 0; + } + return workspacePath; +} + connection.onDocumentSymbol(documentSymbolParms => { let document = documents.get(documentSymbolParms.textDocument.uri); let symbols: SymbolInformation[] = []; diff --git a/extensions/html/server/src/utils/strings.ts b/extensions/html/server/src/utils/strings.ts index 75404682387..1d99cddd56b 100644 --- a/extensions/html/server/src/utils/strings.ts +++ b/extensions/html/server/src/utils/strings.ts @@ -41,6 +41,17 @@ export function startsWith(haystack: string, needle: string): boolean { return true; } +export function endsWith(haystack: string, needle: string): boolean { + let diff = haystack.length - needle.length; + if (diff > 0) { + return haystack.indexOf(needle, diff) === diff; + } else if (diff === 0) { + return haystack === needle; + } else { + return false; + } +} + export function repeat(value: string, count: number) { var s = ''; while (count > 0) {