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) {