update cmd line

This commit is contained in:
asep komarudin 2023-03-03 07:09:50 +07:00
parent 67a507d530
commit 8c55f6b749
214 changed files with 48553 additions and 48489 deletions

View file

@ -0,0 +1,6 @@
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
[{
"name": "definitelytyped",
"repositoryURL": "https://github.com/DefinitelyTyped/DefinitelyTyped",
"license": "MIT"
}]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,300 @@
{
"name": "vscode-html-languageserver",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "vscode-html-languageserver",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"typescript": "^2.7.1",
"vscode-css-languageservice": "^4.0.2",
"vscode-emmet-helper": "^1.2.15",
"vscode-html-languageservice": "^3.0.2",
"vscode-languageserver": "^4.0.0-next.4",
"vscode-languageserver-types": "^3.14.0",
"vscode-nls": "^4.1.1",
"vscode-uri": "^1.0.6"
},
"devDependencies": {
"@types/mocha": "2.2.33",
"@types/node": "7.0.43"
},
"engines": {
"node": "*"
}
},
"node_modules/@emmetio/extract-abbreviation": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@emmetio/extract-abbreviation/-/extract-abbreviation-0.1.6.tgz",
"integrity": "sha512-Ce3xE2JvTSEbASFbRbA1gAIcMcZWdS2yUYRaQbeM0nbOzaZrUYfa3ePtcriYRZOZmr+CkKA+zbjhvTpIOAYVcw=="
},
"node_modules/@types/mocha": {
"version": "2.2.33",
"resolved": "http://registry.npm.taobao.org/@types/mocha/download/@types/mocha-2.2.33.tgz",
"integrity": "sha1-15oAYewnA3n02eIl9AlvtDZmne8=",
"dev": true
},
"node_modules/@types/node": {
"version": "7.0.43",
"resolved": "http://registry.npm.taobao.org/@types/node/download/@types/node-7.0.43.tgz",
"integrity": "sha1-oYfghJWgdfIAypRgeckU4aX+liw=",
"dev": true
},
"node_modules/jsonc-parser": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-1.0.3.tgz",
"integrity": "sha512-hk/69oAeaIzchq/v3lS50PXuzn5O2ynldopMC+SWBql7J2WtdptfB9dy8Y7+Og5rPkTCpn83zTiO8FMcqlXJ/g=="
},
"node_modules/typescript": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.1.tgz",
"integrity": "sha512-bqB1yS6o9TNA9ZC/MJxM0FZzPnZdtHj0xWK/IZ5khzVqdpGul/R/EIiHRgFXlwTD7PSIaYVnGKq1QgMCu2mnqw==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/vscode-css-languageservice": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-4.0.2.tgz",
"integrity": "sha512-pTnfXbsME3pl+yDfhUp/mtvPyIJk0Le4zqJxDn56s9GY9LqY0RmkSEh0oHH6D0HXR3Ni6wKosIaqu8a2G0+jdw==",
"dependencies": {
"vscode-languageserver-types": "^3.15.0-next.2",
"vscode-nls": "^4.1.1"
}
},
"node_modules/vscode-css-languageservice/node_modules/vscode-languageserver-types": {
"version": "3.15.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz",
"integrity": "sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ=="
},
"node_modules/vscode-css-languageservice/node_modules/vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
},
"node_modules/vscode-emmet-helper": {
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.2.15.tgz",
"integrity": "sha512-JplvmMMWSvm/6/dZezix2ADPM49u6YahPYjs/QToohUpomW/2Eb27ecCrkCyOGBPfKLKGiOPHCssss8TSDA9ag==",
"deprecated": "This package has been renamed to @vscode/emmet-helper, please update to the new name",
"dependencies": {
"@emmetio/extract-abbreviation": "0.1.6",
"jsonc-parser": "^1.0.0",
"vscode-languageserver-types": "^3.6.0-next.1"
}
},
"node_modules/vscode-html-languageservice": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-3.0.2.tgz",
"integrity": "sha512-MP9al7nk1SqQwW4GdDy6Ec3UU1GKy0Wf4pzo3nQ5lgdScb2pajV7iyXZIGJk7jQbifkZWnG0jB7CKecTNFynJw==",
"dependencies": {
"vscode-languageserver-types": "^3.15.0-next.2",
"vscode-nls": "^4.1.1",
"vscode-uri": "^2.0.1"
}
},
"node_modules/vscode-html-languageservice/node_modules/vscode-languageserver-types": {
"version": "3.15.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz",
"integrity": "sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ=="
},
"node_modules/vscode-html-languageservice/node_modules/vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
},
"node_modules/vscode-html-languageservice/node_modules/vscode-uri": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.0.3.tgz",
"integrity": "sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw=="
},
"node_modules/vscode-jsonrpc": {
"version": "3.6.0-next.1",
"resolved": "http://registry.npm.taobao.org/vscode-jsonrpc/download/vscode-jsonrpc-3.6.0-next.1.tgz",
"integrity": "sha1-PLRj3/5YQtauwWcYypJScIzWqr4=",
"engines": {
"node": ">=4.0.0 || >=6.0.0"
}
},
"node_modules/vscode-languageserver": {
"version": "4.0.0-next.4",
"resolved": "http://registry.npm.taobao.org/vscode-languageserver/download/vscode-languageserver-4.0.0-next.4.tgz",
"integrity": "sha1-FiRAsVvtqrB+FnbwRuTZuFeLPZI=",
"dependencies": {
"vscode-languageserver-protocol": "^3.6.0-next.5",
"vscode-uri": "^1.0.1"
},
"bin": {
"installServerIntoExtension": "bin/installServerIntoExtension"
}
},
"node_modules/vscode-languageserver-protocol": {
"version": "3.6.0-next.5",
"resolved": "http://registry.npm.taobao.org/vscode-languageserver-protocol/download/vscode-languageserver-protocol-3.6.0-next.5.tgz",
"integrity": "sha1-7S7C23WYJvdTwKE5d9+yvtxNMbM=",
"dependencies": {
"vscode-jsonrpc": "^3.6.0-next.1",
"vscode-languageserver-types": "^3.6.0-next.1"
}
},
"node_modules/vscode-languageserver-types": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
"integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A=="
},
"node_modules/vscode-languageserver/node_modules/vscode-uri": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz",
"integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ=="
},
"node_modules/vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
},
"node_modules/vscode-uri": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz",
"integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ=="
}
},
"dependencies": {
"@emmetio/extract-abbreviation": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@emmetio/extract-abbreviation/-/extract-abbreviation-0.1.6.tgz",
"integrity": "sha512-Ce3xE2JvTSEbASFbRbA1gAIcMcZWdS2yUYRaQbeM0nbOzaZrUYfa3ePtcriYRZOZmr+CkKA+zbjhvTpIOAYVcw=="
},
"@types/mocha": {
"version": "2.2.33",
"resolved": "http://registry.npm.taobao.org/@types/mocha/download/@types/mocha-2.2.33.tgz",
"integrity": "sha1-15oAYewnA3n02eIl9AlvtDZmne8=",
"dev": true
},
"@types/node": {
"version": "7.0.43",
"resolved": "http://registry.npm.taobao.org/@types/node/download/@types/node-7.0.43.tgz",
"integrity": "sha1-oYfghJWgdfIAypRgeckU4aX+liw=",
"dev": true
},
"jsonc-parser": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-1.0.3.tgz",
"integrity": "sha512-hk/69oAeaIzchq/v3lS50PXuzn5O2ynldopMC+SWBql7J2WtdptfB9dy8Y7+Og5rPkTCpn83zTiO8FMcqlXJ/g=="
},
"typescript": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.1.tgz",
"integrity": "sha512-bqB1yS6o9TNA9ZC/MJxM0FZzPnZdtHj0xWK/IZ5khzVqdpGul/R/EIiHRgFXlwTD7PSIaYVnGKq1QgMCu2mnqw=="
},
"vscode-css-languageservice": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-4.0.2.tgz",
"integrity": "sha512-pTnfXbsME3pl+yDfhUp/mtvPyIJk0Le4zqJxDn56s9GY9LqY0RmkSEh0oHH6D0HXR3Ni6wKosIaqu8a2G0+jdw==",
"requires": {
"vscode-languageserver-types": "^3.15.0-next.2",
"vscode-nls": "^4.1.1"
},
"dependencies": {
"vscode-languageserver-types": {
"version": "3.15.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz",
"integrity": "sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ=="
},
"vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
}
}
},
"vscode-emmet-helper": {
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.2.15.tgz",
"integrity": "sha512-JplvmMMWSvm/6/dZezix2ADPM49u6YahPYjs/QToohUpomW/2Eb27ecCrkCyOGBPfKLKGiOPHCssss8TSDA9ag==",
"requires": {
"@emmetio/extract-abbreviation": "0.1.6",
"jsonc-parser": "^1.0.0",
"vscode-languageserver-types": "^3.6.0-next.1"
}
},
"vscode-html-languageservice": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-3.0.2.tgz",
"integrity": "sha512-MP9al7nk1SqQwW4GdDy6Ec3UU1GKy0Wf4pzo3nQ5lgdScb2pajV7iyXZIGJk7jQbifkZWnG0jB7CKecTNFynJw==",
"requires": {
"vscode-languageserver-types": "^3.15.0-next.2",
"vscode-nls": "^4.1.1",
"vscode-uri": "^2.0.1"
},
"dependencies": {
"vscode-languageserver-types": {
"version": "3.15.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz",
"integrity": "sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ=="
},
"vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
},
"vscode-uri": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.0.3.tgz",
"integrity": "sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw=="
}
}
},
"vscode-jsonrpc": {
"version": "3.6.0-next.1",
"resolved": "http://registry.npm.taobao.org/vscode-jsonrpc/download/vscode-jsonrpc-3.6.0-next.1.tgz",
"integrity": "sha1-PLRj3/5YQtauwWcYypJScIzWqr4="
},
"vscode-languageserver": {
"version": "4.0.0-next.4",
"resolved": "http://registry.npm.taobao.org/vscode-languageserver/download/vscode-languageserver-4.0.0-next.4.tgz",
"integrity": "sha1-FiRAsVvtqrB+FnbwRuTZuFeLPZI=",
"requires": {
"vscode-languageserver-protocol": "^3.6.0-next.5",
"vscode-uri": "^1.0.1"
},
"dependencies": {
"vscode-uri": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz",
"integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ=="
}
}
},
"vscode-languageserver-protocol": {
"version": "3.6.0-next.5",
"resolved": "http://registry.npm.taobao.org/vscode-languageserver-protocol/download/vscode-languageserver-protocol-3.6.0-next.5.tgz",
"integrity": "sha1-7S7C23WYJvdTwKE5d9+yvtxNMbM=",
"requires": {
"vscode-jsonrpc": "^3.6.0-next.1",
"vscode-languageserver-types": "^3.6.0-next.1"
}
},
"vscode-languageserver-types": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
"integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A=="
},
"vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
},
"vscode-uri": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz",
"integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ=="
}
}
}

View file

@ -0,0 +1,32 @@
{
"name": "vscode-html-languageserver",
"description": "HTML language server",
"version": "1.0.0",
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
"node": "*"
},
"dependencies": {
"typescript": "^2.7.1",
"vscode-css-languageservice": "^4.0.2",
"vscode-html-languageservice": "^3.0.2",
"vscode-emmet-helper": "^1.2.15",
"vscode-languageserver": "^4.0.0-next.4",
"vscode-languageserver-types": "^3.14.0",
"vscode-nls": "^4.1.1",
"vscode-uri": "^1.0.6"
},
"devDependencies": {
"@types/mocha": "2.2.33",
"@types/node": "7.0.43"
},
"scripts": {
"compile": "gulp compile-extension:html-server",
"watch": "gulp watch-extension:html-server",
"install-service-next": "yarn add vscode-css-languageservice@next && yarn add vscode-html-languageservice@next",
"install-service-local": "npm install ../../../../vscode-css-languageservice -f && npm install ../../../../vscode-html-languageservice -f",
"install-server-next": "yarn add vscode-languageserver@next",
"install-server-local": "npm install ../../../../vscode-languageserver-node/server -f"
}
}

View file

@ -0,0 +1,452 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType, DocumentRangeFormattingRequest, Disposable, DocumentSelector, TextDocumentPositionParams, ServerCapabilities, Position, CompletionTriggerKind } from 'vscode-languageserver';
import { TextDocument, Diagnostic, DocumentLink, SymbolInformation, CompletionList } from 'vscode-languageserver-types';
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 { getDocumentContext } from './utils/documentContext';
import uri from 'vscode-uri';
import { formatError, runSafe } from './utils/errors';
import { doComplete as emmetDoComplete, updateExtensionsPath as updateEmmetExtensionsPath, getEmmetCompletionParticipants } from 'vscode-emmet-helper';
namespace TagCloseRequest {
export const type: RequestType<TextDocumentPositionParams, string | null, any, any> = new RequestType('html/tag');
}
// Create a connection for the server
let connection: IConnection = createConnection();
console.log = connection.console.log.bind(connection.console);
console.error = connection.console.error.bind(connection.console);
process.on('unhandledRejection', (e: any) => {
connection.console.error(formatError(`Unhandled exception`, e));
});
// Create a simple text document manager. The text document manager
// supports full document sync only
let documents: TextDocuments = new TextDocuments();
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
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<Settings> } = {};
// remove document settings on close
documents.onDidClose(e => {
delete documentSettings[e.document.uri];
});
function getDocumentSettings(textDocument: TextDocument, needsDocumentSettings: () => boolean): Thenable<Settings | undefined> {
if (scopedSettingsSupport && needsDocumentSettings()) {
let promise = documentSettings[textDocument.uri];
if (!promise) {
let scopeUri = textDocument.uri;
let configRequestParam: ConfigurationParams = { items: [{ scopeUri, section: 'css' }, { scopeUri, section: 'html' }, { scopeUri, section: 'javascript' }] };
promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => ({ css: s[0], html: s[1], javascript: s[2] }));
documentSettings[textDocument.uri] = promise;
}
return promise;
}
return Promise.resolve(void 0);
}
let emmetSettings = {};
let currentEmmetExtensionsPath: string;
const emmetTriggerCharacters = ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
// After the server has started the client sends an initilize request. The server receives
// in the passed params the rootPath of the workspace plus the client capabilites
connection.onInitialize((params: InitializeParams): InitializeResult => {
let initializationOptions = params.initializationOptions;
workspaceFolders = (<any>params).workspaceFolders;
if (!Array.isArray(workspaceFolders)) {
workspaceFolders = [];
if (params.rootPath) {
workspaceFolders.push({ name: '', uri: uri.file(params.rootPath).toString() });
}
}
languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true });
documents.onDidClose(e => {
languageModes.onDocumentRemoved(e.document);
});
connection.onShutdown(() => {
languageModes.dispose();
});
function hasClientCapability(...keys: string[]) {
let c = <any>params.capabilities;
for (let i = 0; c && i < keys.length; i++) {
c = c[keys[i]];
}
return !!c;
}
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,
completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: [...emmetTriggerCharacters, '.', ':', '<', '"', '=', '/'] } : undefined,
hoverProvider: true,
documentHighlightProvider: true,
documentRangeFormattingProvider: false,
documentSymbolProvider: true,
definitionProvider: true,
signatureHelpProvider: { triggerCharacters: ['('] },
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<Disposable> | null = null;
// The settings have changed. Is send on server activation as well.
connection.onDidChangeConfiguration((change) => {
globalSettings = change.settings;
documentSettings = {}; // reset all document settings
languageModes.getAllModes().forEach(m => {
if (m.configure) {
m.configure(change.settings);
}
});
documents.all().forEach(triggerValidation);
// dynamically enable & disable the formatter
if (clientDynamicRegisterSupport) {
let enableFormatter = globalSettings && globalSettings.html && globalSettings.html.format && globalSettings.html.format.enable;
if (enableFormatter) {
if (!formatterRegistration) {
let documentSelector: DocumentSelector = [{ language: 'html' }, { language: 'handlebars' }]; // don't register razor, the formatter does more harm than good
formatterRegistration = connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector });
}
} else if (formatterRegistration) {
formatterRegistration.then(r => r.dispose());
formatterRegistration = null;
}
}
emmetSettings = globalSettings.emmet;
if (currentEmmetExtensionsPath !== emmetSettings['extensionsPath']) {
currentEmmetExtensionsPath = emmetSettings['extensionsPath'];
const workspaceUri = (workspaceFolders && workspaceFolders.length === 1) ? uri.parse(workspaceFolders[0].uri) : null;
updateEmmetExtensionsPath(currentEmmetExtensionsPath, workspaceUri ? workspaceUri.fsPath : null);
}
});
let pendingValidationRequests: { [uri: string]: NodeJS.Timer } = {};
const validationDelayMs = 500;
// The content of a text document has changed. This event is emitted
// when the text document first opened or when its content has changed.
documents.onDidChangeContent(change => {
triggerValidation(change.document);
});
// a document has closed: clear all diagnostics
documents.onDidClose(event => {
cleanPendingValidation(event.document);
connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] });
});
function cleanPendingValidation(textDocument: TextDocument): void {
let request = pendingValidationRequests[textDocument.uri];
if (request) {
clearTimeout(request);
delete pendingValidationRequests[textDocument.uri];
}
}
function triggerValidation(textDocument: TextDocument): void {
cleanPendingValidation(textDocument);
pendingValidationRequests[textDocument.uri] = setTimeout(() => {
delete pendingValidationRequests[textDocument.uri];
validateTextDocument(textDocument);
}, validationDelayMs);
}
function isValidationEnabled(languageId: string, settings: Settings = globalSettings) {
let validationSettings = settings && settings.html && settings.html.validate;
if (validationSettings) {
return languageId === 'css' && validationSettings.styles !== false || languageId === 'javascript' && validationSettings.scripts !== false;
}
return true;
}
async function validateTextDocument(textDocument: TextDocument) {
try {
let diagnostics: Diagnostic[] = [];
if (textDocument.languageId === 'html') {
let modes = languageModes.getAllModesInDocument(textDocument);
let settings = await getDocumentSettings(textDocument, () => modes.some(m => !!m.doValidation));
modes.forEach(mode => {
if (mode.doValidation && isValidationEnabled(mode.getId(), settings)) {
pushAll(diagnostics, mode.doValidation(textDocument, settings));
}
});
}
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
} catch (e) {
connection.console.error(formatError(`Error while validating ${textDocument.uri}`, e));
}
}
let cachedCompletionList: CompletionList;
const hexColorRegex = /^#[\d,a-f,A-F]{1,6}$/;
connection.onCompletion(async textDocumentPosition => {
return runSafe(async () => {
let document = documents.get(textDocumentPosition.textDocument.uri);
let mode = languageModes.getModeAtPosition(document, textDocumentPosition.position);
if (!mode || !mode.doComplete) {
return { isIncomplete: true, items: [] };
}
if (cachedCompletionList
&& !cachedCompletionList.isIncomplete
&& (mode.getId() === 'html' || mode.getId() === 'css')
&& textDocumentPosition.context
&& textDocumentPosition.context.triggerKind === CompletionTriggerKind.TriggerForIncompleteCompletions
) {
let result: CompletionList = emmetDoComplete(document, textDocumentPosition.position, mode.getId(), emmetSettings);
if (result && result.items) {
result.items.push(...cachedCompletionList.items);
} else {
result = cachedCompletionList;
cachedCompletionList = null;
}
return result;
}
if (mode.getId() !== 'html') {
connection.telemetry.logEvent({ key: 'html.embbedded.complete', value: { languageId: mode.getId() } });
}
cachedCompletionList = null;
let emmetCompletionList: CompletionList = {
isIncomplete: true,
items: undefined
};
if (mode.setCompletionParticipants) {
const emmetCompletionParticipant = getEmmetCompletionParticipants(document, textDocumentPosition.position, mode.getId(), emmetSettings, emmetCompletionList);
mode.setCompletionParticipants([emmetCompletionParticipant]);
}
let settings = await getDocumentSettings(document, () => mode.doComplete.length > 2);
let result = mode.doComplete(document, textDocumentPosition.position, settings);
if (emmetCompletionList && emmetCompletionList.items) {
cachedCompletionList = result;
if (emmetCompletionList.items.length && hexColorRegex.test(emmetCompletionList.items[0].label) && result.items.some(x => x.label === emmetCompletionList.items[0].label)) {
emmetCompletionList.items.shift();
}
return { isIncomplete: true, items: [...emmetCompletionList.items, ...result.items] };
}
return result;
}, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`);
});
connection.onCompletionResolve(item => {
return runSafe(() => {
let data = item.data;
if (data && data.languageId && data.uri) {
let mode = languageModes.getMode(data.languageId);
let document = documents.get(data.uri);
if (mode && mode.doResolve && document) {
return mode.doResolve(document, item);
}
}
return item;
}, null, `Error while resolving completion proposal`);
});
connection.onHover(textDocumentPosition => {
return runSafe(() => {
let document = documents.get(textDocumentPosition.textDocument.uri);
let mode = languageModes.getModeAtPosition(document, textDocumentPosition.position);
if (mode && mode.doHover) {
return mode.doHover(document, textDocumentPosition.position);
}
return null;
}, null, `Error while computing hover for ${textDocumentPosition.textDocument.uri}`);
});
connection.onDocumentHighlight(documentHighlightParams => {
return runSafe(() => {
let document = documents.get(documentHighlightParams.textDocument.uri);
let mode = languageModes.getModeAtPosition(document, documentHighlightParams.position);
if (mode && mode.findDocumentHighlight) {
return mode.findDocumentHighlight(document, documentHighlightParams.position);
}
return [];
}, [], `Error while computing document highlights for ${documentHighlightParams.textDocument.uri}`);
});
connection.onDefinition(definitionParams => {
return runSafe(() => {
let document = documents.get(definitionParams.textDocument.uri);
let mode = languageModes.getModeAtPosition(document, definitionParams.position);
if (mode && mode.findDefinition) {
return mode.findDefinition(document, definitionParams.position);
}
return [];
}, null, `Error while computing definitions for ${definitionParams.textDocument.uri}`);
});
connection.onReferences(referenceParams => {
return runSafe(() => {
let document = documents.get(referenceParams.textDocument.uri);
let mode = languageModes.getModeAtPosition(document, referenceParams.position);
if (mode && mode.findReferences) {
return mode.findReferences(document, referenceParams.position);
}
return [];
}, [], `Error while computing references for ${referenceParams.textDocument.uri}`);
});
connection.onSignatureHelp(signatureHelpParms => {
return runSafe(() => {
let document = documents.get(signatureHelpParms.textDocument.uri);
let mode = languageModes.getModeAtPosition(document, signatureHelpParms.position);
if (mode && mode.doSignatureHelp) {
return mode.doSignatureHelp(document, signatureHelpParms.position);
}
return null;
}, null, `Error while computing signature help for ${signatureHelpParms.textDocument.uri}`);
});
connection.onDocumentRangeFormatting(async formatParams => {
return runSafe(async () => {
let document = documents.get(formatParams.textDocument.uri);
let settings = await getDocumentSettings(document, () => true);
if (!settings) {
settings = globalSettings;
}
let unformattedTags: string = settings && settings.html && settings.html.format && settings.html.format.unformatted || '';
let enabledModes = { css: !unformattedTags.match(/\bstyle\b/), javascript: !unformattedTags.match(/\bscript\b/) };
return format(languageModes, document, formatParams.range, formatParams.options, settings, enabledModes);
}, [], `Error while formatting range for ${formatParams.textDocument.uri}`);
});
connection.onDocumentLinks(documentLinkParam => {
return runSafe(() => {
let document = documents.get(documentLinkParam.textDocument.uri);
let links: DocumentLink[] = [];
if (document) {
let documentContext = getDocumentContext(document.uri, workspaceFolders);
languageModes.getAllModesInDocument(document).forEach(m => {
if (m.findDocumentLinks) {
pushAll(links, m.findDocumentLinks(document, documentContext));
}
});
}
return links;
}, [], `Error while document links for ${documentLinkParam.textDocument.uri}`);
});
connection.onDocumentSymbol(documentSymbolParms => {
return runSafe(() => {
let document = documents.get(documentSymbolParms.textDocument.uri);
let symbols: SymbolInformation[] = [];
languageModes.getAllModesInDocument(document).forEach(m => {
if (m.findDocumentSymbols) {
pushAll(symbols, m.findDocumentSymbols(document));
}
});
return symbols;
}, [], `Error while computing document symbols for ${documentSymbolParms.textDocument.uri}`);
});
connection.onRequest(DocumentColorRequest.type, params => {
return runSafe(() => {
let infos: ColorInformation[] = [];
let document = documents.get(params.textDocument.uri);
if (document) {
languageModes.getAllModesInDocument(document).forEach(m => {
if (m.findDocumentColors) {
pushAll(infos, m.findDocumentColors(document));
}
});
}
return infos;
}, [], `Error while computing document colors for ${params.textDocument.uri}`);
});
connection.onRequest(ColorPresentationRequest.type, params => {
return runSafe(() => {
let document = documents.get(params.textDocument.uri);
if (document) {
let mode = languageModes.getModeAtPosition(document, params.range.start);
if (mode && mode.getColorPresentations) {
return mode.getColorPresentations(document, params.color, params.range);
}
}
return [];
}, [], `Error while computing color presentations for ${params.textDocument.uri}`);
});
connection.onRequest(TagCloseRequest.type, params => {
return runSafe(() => {
let document = documents.get(params.textDocument.uri);
if (document) {
let pos = params.position;
if (pos.character > 0) {
let mode = languageModes.getModeAtPosition(document, Position.create(pos.line, pos.character - 1));
if (mode && mode.doAutoClose) {
return mode.doAutoClose(document, pos);
}
}
}
return null;
}, null, `Error while computing tag close actions for ${params.textDocument.uri}`);
});
// Listen on the connection
connection.listen();

View file

@ -0,0 +1,83 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TextDocument } from 'vscode-languageserver';
export interface LanguageModelCache<T> {
get(document: TextDocument): T;
onDocumentRemoved(document: TextDocument): void;
dispose(): void;
}
export function getLanguageModelCache<T>(maxEntries: number, cleanupIntervalTimeInSec: number, parse: (document: TextDocument) => T): LanguageModelCache<T> {
let languageModels: { [uri: string]: { version: number, languageId: string, cTime: number, languageModel: T } } = {};
let nModels = 0;
let cleanupInterval: NodeJS.Timer | undefined = void 0;
if (cleanupIntervalTimeInSec > 0) {
cleanupInterval = setInterval(() => {
let cutoffTime = Date.now() - cleanupIntervalTimeInSec * 1000;
let uris = Object.keys(languageModels);
for (let uri of uris) {
let languageModelInfo = languageModels[uri];
if (languageModelInfo.cTime < cutoffTime) {
delete languageModels[uri];
nModels--;
}
}
}, cleanupIntervalTimeInSec * 1000);
}
return {
get(document: TextDocument): T {
let version = document.version;
let languageId = document.languageId;
let languageModelInfo = languageModels[document.uri];
if (languageModelInfo && languageModelInfo.version === version && languageModelInfo.languageId === languageId) {
languageModelInfo.cTime = Date.now();
return languageModelInfo.languageModel;
}
let languageModel = parse(document);
languageModels[document.uri] = { languageModel, version, languageId, cTime: Date.now() };
if (!languageModelInfo) {
nModels++;
}
if (nModels === maxEntries) {
let oldestTime = Number.MAX_VALUE;
let oldestUri = null;
for (let uri in languageModels) {
let languageModelInfo = languageModels[uri];
if (languageModelInfo.cTime < oldestTime) {
oldestUri = uri;
oldestTime = languageModelInfo.cTime;
}
}
if (oldestUri) {
delete languageModels[oldestUri];
nModels--;
}
}
return languageModel;
},
onDocumentRemoved(document: TextDocument) {
let uri = document.uri;
if (languageModels[uri]) {
delete languageModels[uri];
nModels--;
}
},
dispose() {
if (typeof cleanupInterval !== 'undefined') {
clearInterval(cleanupInterval);
cleanupInterval = void 0;
languageModels = {};
nModels = 0;
}
}
};
}

View file

@ -0,0 +1,74 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
import { TextDocument, Position, Range } from 'vscode-languageserver-types';
import { getCSSLanguageService, Stylesheet, ICompletionParticipant } from 'vscode-css-languageservice';
import { LanguageMode, Settings } from './languageModes';
import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport';
import { Color } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
export function getCSSMode(documentRegions: LanguageModelCache<HTMLDocumentRegions>): LanguageMode {
let cssLanguageService = getCSSLanguageService();
let embeddedCSSDocuments = getLanguageModelCache<TextDocument>(10, 60, document => documentRegions.get(document).getEmbeddedDocument('css'));
let cssStylesheets = getLanguageModelCache<Stylesheet>(10, 60, document => cssLanguageService.parseStylesheet(document));
return {
getId() {
return 'css';
},
configure(options: any) {
cssLanguageService.configure(options && options.css);
},
doValidation(document: TextDocument, settings?: Settings) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.doValidation(embedded, cssStylesheets.get(embedded), settings && settings.css);
},
doComplete(document: TextDocument, position: Position) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.doComplete(embedded, position, cssStylesheets.get(embedded));
},
setCompletionParticipants(registeredCompletionParticipants: ICompletionParticipant[]) {
cssLanguageService.setCompletionParticipants(registeredCompletionParticipants);
},
doHover(document: TextDocument, position: Position) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.doHover(embedded, position, cssStylesheets.get(embedded));
},
findDocumentHighlight(document: TextDocument, position: Position) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.findDocumentHighlights(embedded, position, cssStylesheets.get(embedded));
},
findDocumentSymbols(document: TextDocument) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.findDocumentSymbols(embedded, cssStylesheets.get(embedded)).filter(s => s.name !== CSS_STYLE_RULE);
},
findDefinition(document: TextDocument, position: Position) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.findDefinition(embedded, position, cssStylesheets.get(embedded));
},
findReferences(document: TextDocument, position: Position) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.findReferences(embedded, position, cssStylesheets.get(embedded));
},
findDocumentColors(document: TextDocument) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.findDocumentColors(embedded, cssStylesheets.get(embedded));
},
getColorPresentations(document: TextDocument, color: Color, range: Range) {
let embedded = embeddedCSSDocuments.get(document);
return cssLanguageService.getColorPresentations(embedded, cssStylesheets.get(embedded), color, range);
},
onDocumentRemoved(document: TextDocument) {
embeddedCSSDocuments.onDocumentRemoved(document);
cssStylesheets.onDocumentRemoved(document);
},
dispose() {
embeddedCSSDocuments.dispose();
cssStylesheets.dispose();
}
};
}

View file

@ -0,0 +1,233 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TextDocument, Position, LanguageService, TokenType, Range } from 'vscode-html-languageservice';
export interface LanguageRange extends Range {
languageId: string | undefined;
attributeValue?: boolean;
}
export interface HTMLDocumentRegions {
getEmbeddedDocument(languageId: string, ignoreAttributeValues?: boolean): TextDocument;
getLanguageRanges(range: Range): LanguageRange[];
getLanguageAtPosition(position: Position): string | undefined;
getLanguagesInDocument(): string[];
getImportedScripts(): string[];
}
export var CSS_STYLE_RULE = '__';
interface EmbeddedRegion { languageId: string | undefined; start: number; end: number; attributeValue?: boolean; }
export function getDocumentRegions(languageService: LanguageService, document: TextDocument): HTMLDocumentRegions {
let regions: EmbeddedRegion[] = [];
let scanner = languageService.createScanner(document.getText());
let lastTagName: string = '';
let lastAttributeName: string | null = null;
let languageIdFromType: string | undefined = undefined;
let importedScripts: string[] = [];
let token = scanner.scan();
while (token !== TokenType.EOS) {
switch (token) {
case TokenType.StartTag:
lastTagName = scanner.getTokenText();
lastAttributeName = null;
languageIdFromType = 'javascript';
break;
case TokenType.Styles:
regions.push({ languageId: 'css', start: scanner.getTokenOffset(), end: scanner.getTokenEnd() });
break;
case TokenType.Script:
regions.push({ languageId: languageIdFromType, start: scanner.getTokenOffset(), end: scanner.getTokenEnd() });
break;
case TokenType.AttributeName:
lastAttributeName = scanner.getTokenText();
break;
case TokenType.AttributeValue:
if (lastAttributeName === 'src' && lastTagName.toLowerCase() === 'script') {
let value = scanner.getTokenText();
if (value[0] === '\'' || value[0] === '"') {
value = value.substr(1, value.length - 1);
}
importedScripts.push(value);
} else if (lastAttributeName === 'type' && lastTagName.toLowerCase() === 'script') {
if (/["'](module|(text|application)\/(java|ecma)script)["']/.test(scanner.getTokenText())) {
languageIdFromType = 'javascript';
} else {
languageIdFromType = void 0;
}
} else {
let attributeLanguageId = getAttributeLanguage(lastAttributeName!);
if (attributeLanguageId) {
let start = scanner.getTokenOffset();
let end = scanner.getTokenEnd();
let firstChar = document.getText()[start];
if (firstChar === '\'' || firstChar === '"') {
start++;
end--;
}
regions.push({ languageId: attributeLanguageId, start, end, attributeValue: true });
}
}
lastAttributeName = null;
break;
}
token = scanner.scan();
}
return {
getLanguageRanges: (range: Range) => getLanguageRanges(document, regions, range),
getEmbeddedDocument: (languageId: string, ignoreAttributeValues: boolean) => getEmbeddedDocument(document, regions, languageId, ignoreAttributeValues),
getLanguageAtPosition: (position: Position) => getLanguageAtPosition(document, regions, position),
getLanguagesInDocument: () => getLanguagesInDocument(document, regions),
getImportedScripts: () => importedScripts
};
}
function getLanguageRanges(document: TextDocument, regions: EmbeddedRegion[], range: Range): LanguageRange[] {
let result: LanguageRange[] = [];
let currentPos = range ? range.start : Position.create(0, 0);
let currentOffset = range ? document.offsetAt(range.start) : 0;
let endOffset = range ? document.offsetAt(range.end) : document.getText().length;
for (let region of regions) {
if (region.end > currentOffset && region.start < endOffset) {
let start = Math.max(region.start, currentOffset);
let startPos = document.positionAt(start);
if (currentOffset < region.start) {
result.push({
start: currentPos,
end: startPos,
languageId: 'html'
});
}
let end = Math.min(region.end, endOffset);
let endPos = document.positionAt(end);
if (end > region.start) {
result.push({
start: startPos,
end: endPos,
languageId: region.languageId,
attributeValue: region.attributeValue
});
}
currentOffset = end;
currentPos = endPos;
}
}
if (currentOffset < endOffset) {
let endPos = range ? range.end : document.positionAt(endOffset);
result.push({
start: currentPos,
end: endPos,
languageId: 'html'
});
}
return result;
}
function getLanguagesInDocument(document: TextDocument, regions: EmbeddedRegion[]): string[] {
let result = [];
for (let region of regions) {
if (region.languageId && result.indexOf(region.languageId) === -1) {
result.push(region.languageId);
if (result.length === 3) {
return result;
}
}
}
result.push('html');
return result;
}
function getLanguageAtPosition(document: TextDocument, regions: EmbeddedRegion[], position: Position): string | undefined {
let offset = document.offsetAt(position);
for (let region of regions) {
if (region.start <= offset) {
if (offset <= region.end) {
return region.languageId;
}
} else {
break;
}
}
return 'html';
}
function getEmbeddedDocument(document: TextDocument, contents: EmbeddedRegion[], languageId: string, ignoreAttributeValues: boolean): TextDocument {
let currentPos = 0;
let oldContent = document.getText();
let result = '';
let lastSuffix = '';
for (let c of contents) {
if (c.languageId === languageId && (!ignoreAttributeValues || !c.attributeValue)) {
result = substituteWithWhitespace(result, currentPos, c.start, oldContent, lastSuffix, getPrefix(c));
result += oldContent.substring(c.start, c.end);
currentPos = c.end;
lastSuffix = getSuffix(c);
}
}
result = substituteWithWhitespace(result, currentPos, oldContent.length, oldContent, lastSuffix, '');
return TextDocument.create(document.uri, languageId, document.version, result);
}
function getPrefix(c: EmbeddedRegion) {
if (c.attributeValue) {
switch (c.languageId) {
case 'css': return CSS_STYLE_RULE + '{';
}
}
return '';
}
function getSuffix(c: EmbeddedRegion) {
if (c.attributeValue) {
switch (c.languageId) {
case 'css': return '}';
case 'javascript': return ';';
}
}
return '';
}
function substituteWithWhitespace(result: string, start: number, end: number, oldContent: string, before: string, after: string) {
let accumulatedWS = 0;
result += before;
for (let i = start + before.length; i < end; i++) {
let ch = oldContent[i];
if (ch === '\n' || ch === '\r') {
// only write new lines, skip the whitespace
accumulatedWS = 0;
result += ch;
} else {
accumulatedWS++;
}
}
result = append(result, ' ', accumulatedWS - after.length);
result += after;
return result;
}
function append(result: string, str: string, n: number): string {
while (n > 0) {
if (n & 1) {
result += str;
}
n >>= 1;
str += str;
}
return result;
}
function getAttributeLanguage(attributeName: string): string | null {
let match = attributeName.match(/^(style)$|^(on\w+)$/i);
if (!match) {
return null;
}
return match[1] ? 'css' : 'javascript';
}

View file

@ -0,0 +1,95 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { applyEdits } from '../utils/edits';
import { TextDocument, Range, TextEdit, FormattingOptions, Position } from 'vscode-languageserver-types';
import { LanguageModes, Settings, LanguageModeRange } from './languageModes';
import { pushAll } from '../utils/arrays';
import { isEOL } from '../utils/strings';
export function format(languageModes: LanguageModes, document: TextDocument, formatRange: Range, formattingOptions: FormattingOptions, settings: Settings | undefined, enabledModes: { [mode: string]: boolean }) {
let result: TextEdit[] = [];
let endPos = formatRange.end;
let endOffset = document.offsetAt(endPos);
let content = document.getText();
if (endPos.character === 0 && endPos.line > 0 && endOffset !== content.length) {
// if selection ends after a new line, exclude that new line
let prevLineStart = document.offsetAt(Position.create(endPos.line - 1, 0));
while (isEOL(content, endOffset - 1) && endOffset > prevLineStart) {
endOffset--;
}
formatRange = Range.create(formatRange.start, document.positionAt(endOffset));
}
// run the html formatter on the full range and pass the result content to the embedded formatters.
// from the final content create a single edit
// advantages of this approach are
// - correct indents in the html document
// - correct initial indent for embedded formatters
// - no worrying of overlapping edits
// make sure we start in html
let allRanges = languageModes.getModesInRange(document, formatRange);
let i = 0;
let startPos = formatRange.start;
let isHTML = (range: LanguageModeRange) => range.mode && range.mode.getId() === 'html';
while (i < allRanges.length && !isHTML(allRanges[i])) {
let range = allRanges[i];
if (!range.attributeValue && range.mode && range.mode.format) {
let edits = range.mode.format(document, Range.create(startPos, range.end), formattingOptions, settings);
pushAll(result, edits);
}
startPos = range.end;
i++;
}
if (i === allRanges.length) {
return result;
}
// modify the range
formatRange = Range.create(startPos, formatRange.end);
// perform a html format and apply changes to a new document
let htmlMode = languageModes.getMode('html')!;
let htmlEdits = htmlMode.format!(document, formatRange, formattingOptions, settings);
let htmlFormattedContent = applyEdits(document, htmlEdits);
let newDocument = TextDocument.create(document.uri + '.tmp', document.languageId, document.version, htmlFormattedContent);
try {
// run embedded formatters on html formatted content: - formatters see correct initial indent
let afterFormatRangeLength = document.getText().length - document.offsetAt(formatRange.end); // length of unchanged content after replace range
let newFormatRange = Range.create(formatRange.start, newDocument.positionAt(htmlFormattedContent.length - afterFormatRangeLength));
let embeddedRanges = languageModes.getModesInRange(newDocument, newFormatRange);
let embeddedEdits: TextEdit[] = [];
for (let r of embeddedRanges) {
let mode = r.mode;
if (mode && mode.format && enabledModes[mode.getId()] && !r.attributeValue) {
let edits = mode.format(newDocument, r, formattingOptions, settings);
for (let edit of edits) {
embeddedEdits.push(edit);
}
}
}
if (embeddedEdits.length === 0) {
pushAll(result, htmlEdits);
return result;
}
// apply all embedded format edits and create a single edit for all changes
let resultContent = applyEdits(newDocument, embeddedEdits);
let resultReplaceText = resultContent.substring(document.offsetAt(formatRange.start), resultContent.length - afterFormatRangeLength);
result.push(TextEdit.replace(formatRange, resultReplaceText));
return result;
} finally {
languageModes.onDocumentRemoved(newDocument);
}
}

View file

@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { getLanguageModelCache } from '../languageModelCache';
import { LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions, HTMLFormatConfiguration, TokenType } from 'vscode-html-languageservice';
import { TextDocument, Position, Range } from 'vscode-languageserver-types';
import { LanguageMode, Settings } from './languageModes';
export function getHTMLMode(htmlLanguageService: HTMLLanguageService): LanguageMode {
let globalSettings: Settings = {};
let htmlDocuments = getLanguageModelCache<HTMLDocument>(10, 60, document => htmlLanguageService.parseHTMLDocument(document));
let completionParticipants = [];
return {
getId() {
return 'html';
},
configure(options: any) {
globalSettings = options;
},
doComplete(document: TextDocument, position: Position, settings: Settings = globalSettings) {
let options = settings && settings.html && settings.html.suggest;
let doAutoComplete = settings && settings.html && settings.html.autoClosingTags;
if (doAutoComplete) {
options.hideAutoCompleteProposals = true;
}
const htmlDocument = htmlDocuments.get(document);
const offset = document.offsetAt(position);
const node = htmlDocument.findNodeBefore(offset);
const scanner = htmlLanguageService.createScanner(document.getText(), node.start);
let token = scanner.scan();
while (token !== TokenType.EOS && scanner.getTokenOffset() <= offset) {
if (token === TokenType.Content && offset <= scanner.getTokenEnd()) {
completionParticipants.forEach(participant => { if (participant.onHtmlContent) { participant.onHtmlContent(); } });
break;
}
token = scanner.scan();
}
return htmlLanguageService.doComplete(document, position, htmlDocument, options);
},
setCompletionParticipants(registeredCompletionParticipants: any[]) {
completionParticipants = registeredCompletionParticipants;
},
doHover(document: TextDocument, position: Position) {
return htmlLanguageService.doHover(document, position, htmlDocuments.get(document));
},
findDocumentHighlight(document: TextDocument, position: Position) {
return htmlLanguageService.findDocumentHighlights(document, position, htmlDocuments.get(document));
},
findDocumentLinks(document: TextDocument, documentContext: DocumentContext) {
return htmlLanguageService.findDocumentLinks(document, documentContext);
},
findDocumentSymbols(document: TextDocument) {
return htmlLanguageService.findDocumentSymbols(document, htmlDocuments.get(document));
},
format(document: TextDocument, range: Range, formatParams: FormattingOptions, settings: Settings = globalSettings) {
let formatSettings: HTMLFormatConfiguration = settings && settings.html && settings.html.format;
if (formatSettings) {
formatSettings = merge(formatSettings, {});
} else {
formatSettings = {};
}
if (formatSettings.contentUnformatted) {
formatSettings.contentUnformatted = formatSettings.contentUnformatted + ',script';
} else {
formatSettings.contentUnformatted = 'script';
}
formatSettings = merge(formatParams, formatSettings);
return htmlLanguageService.format(document, range, formatSettings);
},
doAutoClose(document: TextDocument, position: Position) {
let offset = document.offsetAt(position);
let text = document.getText();
if (offset > 0 && text.charAt(offset - 1).match(/[>\/]/g)) {
return htmlLanguageService.doTagComplete(document, position, htmlDocuments.get(document));
}
return null;
},
onDocumentRemoved(document: TextDocument) {
htmlDocuments.onDocumentRemoved(document);
},
dispose() {
htmlDocuments.dispose();
}
};
}
function merge(src: any, dst: any): any {
for (var key in src) {
if (src.hasOwnProperty(key)) {
dst[key] = src[key];
}
}
return dst;
}

View file

@ -0,0 +1,411 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
import { SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation, Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, MarkedString, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions } from 'vscode-languageserver-types';
import { LanguageMode, Settings } from './languageModes';
import { getWordAtText, startsWith, isWhitespaceOnly, repeat } from '../utils/strings';
import { HTMLDocumentRegions } from './embeddedSupport';
import * as ts from 'typescript';
import { join } from 'path';
const FILE_NAME = 'vscode://javascript/1'; // the same 'file' is used for all contents
const JQUERY_D_TS = join(__dirname, '../../lib/jquery.d.ts');
const JS_WORD_REGEX = /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g;
export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocumentRegions>): LanguageMode {
let jsDocuments = getLanguageModelCache<TextDocument>(10, 60, document => documentRegions.get(document).getEmbeddedDocument('javascript'));
let compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es6.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic };
let currentTextDocument: TextDocument;
let scriptFileVersion: number = 0;
function updateCurrentTextDocument(doc: TextDocument) {
if (!currentTextDocument || doc.uri !== currentTextDocument.uri || doc.version !== currentTextDocument.version) {
currentTextDocument = jsDocuments.get(doc);
scriptFileVersion++;
}
}
const host: ts.LanguageServiceHost = {
getCompilationSettings: () => compilerOptions,
getScriptFileNames: () => [FILE_NAME, JQUERY_D_TS],
getScriptKind: () => ts.ScriptKind.JS,
getScriptVersion: (fileName: string) => {
if (fileName === FILE_NAME) {
return String(scriptFileVersion);
}
return '1'; // default lib an jquery.d.ts are static
},
getScriptSnapshot: (fileName: string) => {
let text = '';
if (startsWith(fileName, 'vscode:')) {
if (fileName === FILE_NAME) {
text = currentTextDocument.getText();
}
} else {
text = ts.sys.readFile(fileName) || '';
}
return {
getText: (start, end) => text.substring(start, end),
getLength: () => text.length,
getChangeRange: () => void 0
};
},
getCurrentDirectory: () => '',
getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options)
};
let jsLanguageService = ts.createLanguageService(host);
let globalSettings: Settings = {};
return {
getId() {
return 'javascript';
},
configure(options: any) {
globalSettings = options;
},
doValidation(document: TextDocument): Diagnostic[] {
updateCurrentTextDocument(document);
const syntaxDiagnostics = jsLanguageService.getSyntacticDiagnostics(FILE_NAME);
const semanticDiagnostics = jsLanguageService.getSemanticDiagnostics(FILE_NAME);
return syntaxDiagnostics.concat(semanticDiagnostics).map((diag: ts.Diagnostic): Diagnostic => {
return {
range: convertRange(currentTextDocument, diag),
severity: DiagnosticSeverity.Error,
source: 'js',
message: ts.flattenDiagnosticMessageText(diag.messageText, '\n')
};
});
},
doComplete(document: TextDocument, position: Position): CompletionList {
updateCurrentTextDocument(document);
let offset = currentTextDocument.offsetAt(position);
let completions = jsLanguageService.getCompletionsAtPosition(FILE_NAME, offset, { includeExternalModuleExports: false, includeInsertTextCompletions: false });
if (!completions) {
return { isIncomplete: false, items: [] };
}
let replaceRange = convertRange(currentTextDocument, getWordAtText(currentTextDocument.getText(), offset, JS_WORD_REGEX));
return {
isIncomplete: false,
items: completions.entries.map(entry => {
return {
uri: document.uri,
position: position,
label: entry.name,
sortText: entry.sortText,
kind: convertKind(entry.kind),
textEdit: TextEdit.replace(replaceRange, entry.name),
data: { // data used for resolving item details (see 'doResolve')
languageId: 'javascript',
uri: document.uri,
offset: offset
}
};
})
};
},
doResolve(document: TextDocument, item: CompletionItem): CompletionItem {
updateCurrentTextDocument(document);
let details = jsLanguageService.getCompletionEntryDetails(FILE_NAME, item.data.offset, item.label, undefined, undefined);
if (details) {
item.detail = ts.displayPartsToString(details.displayParts);
item.documentation = ts.displayPartsToString(details.documentation);
delete item.data;
}
return item;
},
doHover(document: TextDocument, position: Position): Hover | null {
updateCurrentTextDocument(document);
let info = jsLanguageService.getQuickInfoAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
if (info) {
let contents = ts.displayPartsToString(info.displayParts);
return {
range: convertRange(currentTextDocument, info.textSpan),
contents: MarkedString.fromPlainText(contents)
};
}
return null;
},
doSignatureHelp(document: TextDocument, position: Position): SignatureHelp | null {
updateCurrentTextDocument(document);
let signHelp = jsLanguageService.getSignatureHelpItems(FILE_NAME, currentTextDocument.offsetAt(position));
if (signHelp) {
let ret: SignatureHelp = {
activeSignature: signHelp.selectedItemIndex,
activeParameter: signHelp.argumentIndex,
signatures: []
};
signHelp.items.forEach(item => {
let signature: SignatureInformation = {
label: '',
documentation: undefined,
parameters: []
};
signature.label += ts.displayPartsToString(item.prefixDisplayParts);
item.parameters.forEach((p, i, a) => {
let label = ts.displayPartsToString(p.displayParts);
let parameter: ParameterInformation = {
label: label,
documentation: ts.displayPartsToString(p.documentation)
};
signature.label += label;
signature.parameters!.push(parameter);
if (i < a.length - 1) {
signature.label += ts.displayPartsToString(item.separatorDisplayParts);
}
});
signature.label += ts.displayPartsToString(item.suffixDisplayParts);
ret.signatures.push(signature);
});
return ret;
}
return null;
},
findDocumentHighlight(document: TextDocument, position: Position): DocumentHighlight[] {
updateCurrentTextDocument(document);
let occurrences = jsLanguageService.getOccurrencesAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
if (occurrences) {
return occurrences.map(entry => {
return {
range: convertRange(currentTextDocument, entry.textSpan),
kind: <DocumentHighlightKind>(entry.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Text)
};
});
}
return [];
},
findDocumentSymbols(document: TextDocument): SymbolInformation[] {
updateCurrentTextDocument(document);
let items = jsLanguageService.getNavigationBarItems(FILE_NAME);
if (items) {
let result: SymbolInformation[] = [];
let existing = Object.create(null);
let collectSymbols = (item: ts.NavigationBarItem, containerLabel?: string) => {
let sig = item.text + item.kind + item.spans[0].start;
if (item.kind !== 'script' && !existing[sig]) {
let symbol: SymbolInformation = {
name: item.text,
kind: convertSymbolKind(item.kind),
location: {
uri: document.uri,
range: convertRange(currentTextDocument, item.spans[0])
},
containerName: containerLabel
};
existing[sig] = true;
result.push(symbol);
containerLabel = item.text;
}
if (item.childItems && item.childItems.length > 0) {
for (let child of item.childItems) {
collectSymbols(child, containerLabel);
}
}
};
items.forEach(item => collectSymbols(item));
return result;
}
return [];
},
findDefinition(document: TextDocument, position: Position): Definition | null {
updateCurrentTextDocument(document);
let definition = jsLanguageService.getDefinitionAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
if (definition) {
return definition.filter(d => d.fileName === FILE_NAME).map(d => {
return {
uri: document.uri,
range: convertRange(currentTextDocument, d.textSpan)
};
});
}
return null;
},
findReferences(document: TextDocument, position: Position): Location[] {
updateCurrentTextDocument(document);
let references = jsLanguageService.getReferencesAtPosition(FILE_NAME, currentTextDocument.offsetAt(position));
if (references) {
return references.filter(d => d.fileName === FILE_NAME).map(d => {
return {
uri: document.uri,
range: convertRange(currentTextDocument, d.textSpan)
};
});
}
return [];
},
format(document: TextDocument, range: Range, formatParams: FormattingOptions, settings: Settings = globalSettings): TextEdit[] {
currentTextDocument = documentRegions.get(document).getEmbeddedDocument('javascript', true);
scriptFileVersion++;
let formatterSettings = settings && settings.javascript && settings.javascript.format;
let initialIndentLevel = computeInitialIndent(document, range, formatParams);
let formatSettings = convertOptions(formatParams, formatterSettings, initialIndentLevel + 1);
let start = currentTextDocument.offsetAt(range.start);
let end = currentTextDocument.offsetAt(range.end);
let lastLineRange = null;
if (range.end.line > range.start.line && (range.end.character === 0 || isWhitespaceOnly(currentTextDocument.getText().substr(end - range.end.character, range.end.character)))) {
end -= range.end.character;
lastLineRange = Range.create(Position.create(range.end.line, 0), range.end);
}
let edits = jsLanguageService.getFormattingEditsForRange(FILE_NAME, start, end, formatSettings);
if (edits) {
let result = [];
for (let edit of edits) {
if (edit.span.start >= start && edit.span.start + edit.span.length <= end) {
result.push({
range: convertRange(currentTextDocument, edit.span),
newText: edit.newText
});
}
}
if (lastLineRange) {
result.push({
range: lastLineRange,
newText: generateIndent(initialIndentLevel, formatParams)
});
}
return result;
}
return [];
},
onDocumentRemoved(document: TextDocument) {
jsDocuments.onDocumentRemoved(document);
},
dispose() {
jsLanguageService.dispose();
jsDocuments.dispose();
}
};
}
function convertRange(document: TextDocument, span: { start: number | undefined, length: number | undefined }): Range {
if (typeof span.start === 'undefined') {
const pos = document.positionAt(0);
return Range.create(pos, pos);
}
const startPosition = document.positionAt(span.start);
const endPosition = document.positionAt(span.start + (span.length || 0));
return Range.create(startPosition, endPosition);
}
function convertKind(kind: string): CompletionItemKind {
switch (kind) {
case 'primitive type':
case 'keyword':
return CompletionItemKind.Keyword;
case 'var':
case 'local var':
return CompletionItemKind.Variable;
case 'property':
case 'getter':
case 'setter':
return CompletionItemKind.Field;
case 'function':
case 'method':
case 'construct':
case 'call':
case 'index':
return CompletionItemKind.Function;
case 'enum':
return CompletionItemKind.Enum;
case 'module':
return CompletionItemKind.Module;
case 'class':
return CompletionItemKind.Class;
case 'interface':
return CompletionItemKind.Interface;
case 'warning':
return CompletionItemKind.File;
}
return CompletionItemKind.Property;
}
function convertSymbolKind(kind: string): SymbolKind {
switch (kind) {
case 'var':
case 'local var':
case 'const':
return SymbolKind.Variable;
case 'function':
case 'local function':
return SymbolKind.Function;
case 'enum':
return SymbolKind.Enum;
case 'module':
return SymbolKind.Module;
case 'class':
return SymbolKind.Class;
case 'interface':
return SymbolKind.Interface;
case 'method':
return SymbolKind.Method;
case 'property':
case 'getter':
case 'setter':
return SymbolKind.Property;
}
return SymbolKind.Variable;
}
function convertOptions(options: FormattingOptions, formatSettings: any, initialIndentLevel: number): ts.FormatCodeOptions {
return {
ConvertTabsToSpaces: options.insertSpaces,
TabSize: options.tabSize,
IndentSize: options.tabSize,
IndentStyle: ts.IndentStyle.Smart,
NewLineCharacter: '\n',
BaseIndentSize: options.tabSize * initialIndentLevel,
InsertSpaceAfterCommaDelimiter: Boolean(!formatSettings || formatSettings.insertSpaceAfterCommaDelimiter),
InsertSpaceAfterSemicolonInForStatements: Boolean(!formatSettings || formatSettings.insertSpaceAfterSemicolonInForStatements),
InsertSpaceBeforeAndAfterBinaryOperators: Boolean(!formatSettings || formatSettings.insertSpaceBeforeAndAfterBinaryOperators),
InsertSpaceAfterKeywordsInControlFlowStatements: Boolean(!formatSettings || formatSettings.insertSpaceAfterKeywordsInControlFlowStatements),
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: Boolean(!formatSettings || formatSettings.insertSpaceAfterFunctionKeywordForAnonymousFunctions),
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: Boolean(formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis),
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: Boolean(formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets),
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: Boolean(formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces),
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: Boolean(formatSettings && formatSettings.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces),
PlaceOpenBraceOnNewLineForControlBlocks: Boolean(formatSettings && formatSettings.placeOpenBraceOnNewLineForFunctions),
PlaceOpenBraceOnNewLineForFunctions: Boolean(formatSettings && formatSettings.placeOpenBraceOnNewLineForControlBlocks)
};
}
function computeInitialIndent(document: TextDocument, range: Range, options: FormattingOptions) {
let lineStart = document.offsetAt(Position.create(range.start.line, 0));
let content = document.getText();
let i = lineStart;
let nChars = 0;
let tabSize = options.tabSize || 4;
while (i < content.length) {
let ch = content.charAt(i);
if (ch === ' ') {
nChars++;
} else if (ch === '\t') {
nChars += tabSize;
} else {
break;
}
i++;
}
return Math.floor(nChars / tabSize);
}
function generateIndent(level: number, options: FormattingOptions) {
if (options.insertSpaces) {
return repeat(' ', level * options.tabSize);
} else {
return repeat('\t', level);
}
}

View file

@ -0,0 +1,143 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { getLanguageService as getHTMLLanguageService, DocumentContext } from 'vscode-html-languageservice';
import {
CompletionItem, Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range,
Hover, DocumentHighlight, CompletionList, Position, FormattingOptions, SymbolInformation
} from 'vscode-languageserver-types';
import { ColorInformation, ColorPresentation, Color } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache';
import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport';
import { getCSSMode } from './cssMode';
import { getJavascriptMode } from './javascriptMode';
import { getHTMLMode } from './htmlMode';
export { ColorInformation, ColorPresentation, Color };
export interface Settings {
css?: any;
html?: any;
javascript?: any;
emmet?: { [key: string]: any };
}
export interface SettingProvider {
getDocumentSettings(textDocument: TextDocument): Thenable<Settings>;
}
export interface LanguageMode {
getId(): string;
configure?: (options: Settings) => void;
doValidation?: (document: TextDocument, settings?: Settings) => Diagnostic[];
doComplete?: (document: TextDocument, position: Position, settings?: Settings) => CompletionList | null;
setCompletionParticipants?: (registeredCompletionParticipants: any[]) => void;
doResolve?: (document: TextDocument, item: CompletionItem) => CompletionItem | null;
doHover?: (document: TextDocument, position: Position) => Hover | null;
doSignatureHelp?: (document: TextDocument, position: Position) => SignatureHelp | null;
findDocumentHighlight?: (document: TextDocument, position: Position) => DocumentHighlight[];
findDocumentSymbols?: (document: TextDocument) => SymbolInformation[];
findDocumentLinks?: (document: TextDocument, documentContext: DocumentContext) => DocumentLink[];
findDefinition?: (document: TextDocument, position: Position) => Definition | null;
findReferences?: (document: TextDocument, position: Position) => Location[];
format?: (document: TextDocument, range: Range, options: FormattingOptions, settings?: Settings) => TextEdit[];
findDocumentColors?: (document: TextDocument) => ColorInformation[];
getColorPresentations?: (document: TextDocument, color: Color, range: Range) => ColorPresentation[];
doAutoClose?: (document: TextDocument, position: Position) => string | null;
onDocumentRemoved(document: TextDocument): void;
dispose(): void;
}
export interface LanguageModes {
getModeAtPosition(document: TextDocument, position: Position): LanguageMode | undefined;
getModesInRange(document: TextDocument, range: Range): LanguageModeRange[];
getAllModes(): LanguageMode[];
getAllModesInDocument(document: TextDocument): LanguageMode[];
getMode(languageId: string): LanguageMode | undefined;
onDocumentRemoved(document: TextDocument): void;
dispose(): void;
}
export interface LanguageModeRange extends Range {
mode: LanguageMode | undefined;
attributeValue?: boolean;
}
export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }): LanguageModes {
var htmlLanguageService = getHTMLLanguageService();
let documentRegions = getLanguageModelCache<HTMLDocumentRegions>(10, 60, document => getDocumentRegions(htmlLanguageService, document));
let modelCaches: LanguageModelCache<any>[] = [];
modelCaches.push(documentRegions);
let modes = Object.create(null);
modes['html'] = getHTMLMode(htmlLanguageService);
if (supportedLanguages['css']) {
modes['css'] = getCSSMode(documentRegions);
}
if (supportedLanguages['javascript']) {
modes['javascript'] = getJavascriptMode(documentRegions);
}
return {
getModeAtPosition(document: TextDocument, position: Position): LanguageMode | undefined {
let languageId = documentRegions.get(document).getLanguageAtPosition(position);
if (languageId) {
return modes[languageId];
}
return void 0;
},
getModesInRange(document: TextDocument, range: Range): LanguageModeRange[] {
return documentRegions.get(document).getLanguageRanges(range).map(r => {
return <LanguageModeRange>{
start: r.start,
end: r.end,
mode: r.languageId && modes[r.languageId],
attributeValue: r.attributeValue
};
});
},
getAllModesInDocument(document: TextDocument): LanguageMode[] {
let result = [];
for (let languageId of documentRegions.get(document).getLanguagesInDocument()) {
let mode = modes[languageId];
if (mode) {
result.push(mode);
}
}
return result;
},
getAllModes(): LanguageMode[] {
let result = [];
for (let languageId in modes) {
let mode = modes[languageId];
if (mode) {
result.push(mode);
}
}
return result;
},
getMode(languageId: string): LanguageMode {
return modes[languageId];
},
onDocumentRemoved(document: TextDocument) {
modelCaches.forEach(mc => mc.onDocumentRemoved(document));
for (let mode in modes) {
modes[mode].onDocumentRemoved(document);
}
},
dispose(): void {
modelCaches.forEach(mc => mc.dispose());
modelCaches = [];
for (let mode in modes) {
modes[mode].dispose();
}
modes = {};
}
};
}

View file

@ -0,0 +1,13 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export function pushAll<T>(to: T[], from: T[]) {
if (from) {
for (var i = 0; i < from.length; i++) {
to.push(from[i]);
}
}
}

View file

@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { DocumentContext } from 'vscode-html-languageservice';
import { endsWith, startsWith } from '../utils/strings';
import * as url from 'url';
import { WorkspaceFolder } from 'vscode-languageserver-protocol/lib/protocol.workspaceFolders.proposed';
export function getDocumentContext(documentUri: string, workspaceFolders: WorkspaceFolder[]): DocumentContext {
function getRootFolder(): string | undefined {
for (let folder of workspaceFolders) {
let folderURI = folder.uri;
if (!endsWith(folderURI, '/')) {
folderURI = folderURI + '/';
}
if (startsWith(documentUri, folderURI)) {
return folderURI;
}
}
return void 0;
}
return {
resolveReference: (ref, base = documentUri) => {
if (ref[0] === '/') { // resolve absolute path against the current workspace folder
if (startsWith(base, 'file://')) {
let folderUri = getRootFolder();
if (folderUri) {
return folderUri + ref.substr(1);
}
}
}
return url.resolve(base, ref);
},
};
}

View file

@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TextDocument, TextEdit, Position } from 'vscode-languageserver-types';
export function applyEdits(document: TextDocument, edits: TextEdit[]): string {
let text = document.getText();
let sortedEdits = edits.sort((a, b) => {
let startDiff = comparePositions(a.range.start, b.range.start);
if (startDiff === 0) {
return comparePositions(a.range.end, b.range.end);
}
return startDiff;
});
sortedEdits.forEach(e => {
let startOffset = document.offsetAt(e.range.start);
let endOffset = document.offsetAt(e.range.end);
text = text.substring(0, startOffset) + e.newText + text.substring(endOffset, text.length);
});
return text;
}
function comparePositions(p1: Position, p2: Position) {
let diff = p2.line - p1.line;
if (diff === 0) {
return p2.character - p1.character;
}
return diff;
}

View file

@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export function formatError(message: string, err: any): string {
if (err instanceof Error) {
let error = <Error>err;
return `${message}: ${error.message}\n${error.stack}`;
} else if (typeof err === 'string') {
return `${message}: ${err}`;
} else if (err) {
return `${message}: ${err.toString()}`;
}
return message;
}
export function runSafe<T>(func: () => Thenable<T> | T, errorVal: T, errorMessage: string): Thenable<T> | T {
try {
let t = func();
if (t instanceof Promise) {
return t.then(void 0, e => {
console.error(formatError(errorMessage, e));
return errorVal;
});
}
return t;
} catch (e) {
console.error(formatError(errorMessage, e));
return errorVal;
}
}

View file

@ -0,0 +1,79 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export function getWordAtText(text: string, offset: number, wordDefinition: RegExp): { start: number, length: number } {
let lineStart = offset;
while (lineStart > 0 && !isNewlineCharacter(text.charCodeAt(lineStart - 1))) {
lineStart--;
}
let offsetInLine = offset - lineStart;
let lineText = text.substr(lineStart);
// make a copy of the regex as to not keep the state
let flags = wordDefinition.ignoreCase ? 'gi' : 'g';
wordDefinition = new RegExp(wordDefinition.source, flags);
let match = wordDefinition.exec(lineText);
while (match && match.index + match[0].length < offsetInLine) {
match = wordDefinition.exec(lineText);
}
if (match && match.index <= offsetInLine) {
return { start: match.index + lineStart, length: match[0].length };
}
return { start: offset, length: 0 };
}
export function startsWith(haystack: string, needle: string): boolean {
if (haystack.length < needle.length) {
return false;
}
for (let i = 0; i < needle.length; i++) {
if (haystack[i] !== needle[i]) {
return false;
}
}
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) {
if ((count & 1) === 1) {
s += value;
}
value += value;
count = count >>> 1;
}
return s;
}
export function isWhitespaceOnly(str: string) {
return /^\s*$/.test(str);
}
export function isEOL(content: string, offset: number) {
return isNewlineCharacter(content.charCodeAt(offset));
}
const CR = '\r'.charCodeAt(0);
const NL = '\n'.charCodeAt(0);
export function isNewlineCharacter(charCode: number) {
return charCode === CR || charCode === NL;
}

View file

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"noUnusedLocals": true,
"lib": [
"es5", "es2015.promise"
]
},
"exclude": [
"**/jquery.d.ts"
]
}