diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 3e0d46296946e151031f57274fe979dbfb8dcf9e..afbe0a8b7d4aca9283ea374acf9f69f1da382336 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -30,7 +30,7 @@ var editorEntryPoints = [ prepend: [ 'vs/loader.js' ], append: [ 'vs/base/worker/workerMain' ], dest: 'vs/base/worker/workerMain.js' - }, + } ]; var editorResources = [ diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 95c57d895132852d5c656082c8baeb8cc50f8dd7..fc7d78fcf341a94c4df5bf1efb085c2211db036e 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -48,9 +48,6 @@ const indentationFilter = [ '!**/package.json', '!**/npm-shrinkwrap.json', '!**/octicons/**', - '!**/vs/languages/sass/test/common/example.scss', - '!**/vs/languages/less/common/parser/less.grammar.txt', - '!**/vs/languages/css/common/buildscripts/css-schema.xml', '!**/vs/base/common/marked/raw.marked.js', '!**/vs/base/common/winjs.base.raw.js', '!**/vs/base/node/terminateProcess.sh', @@ -90,7 +87,6 @@ const tslintFilter = [ '!src/vs/base/**/*.test.ts', '!extensions/typescript/test/colorize-fixtures/**', '!extensions/vscode-api-tests/testWorkspace/**', - '!src/vs/languages/**/*.test.ts', '!src/vs/workbench/**/*.test.ts', '!extensions/**/*.test.ts' ]; diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 626358bbce4a9fe4d6e0faabd34d7d67cdbe426e..920b7149f38af98a05546c2edd12b67a6b702bac 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -46,8 +46,6 @@ const builtInExtensions = [ const vscodeEntryPoints = _.flatten([ buildfile.entrypoint('vs/workbench/workbench.main'), buildfile.base, - buildfile.editor, - buildfile.languages, buildfile.workbench, buildfile.code ]); @@ -60,8 +58,6 @@ const vscodeResources = [ 'out-build/paths.js', 'out-build/vs/**/*.{svg,png,cur}', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh}', - 'out-build/vs/base/worker/workerMainCompatibility.html', - 'out-build/vs/base/worker/workerMain.{js,js.map}', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/electron-browser/bootstrap/**', diff --git a/build/monaco/package.json b/build/monaco/package.json index e9b918f69833d1b38d36130f044a948940a0631b..2d5c119e81b1c89c6d6444192e6e4676e067f437 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.7.1", + "version": "0.7.3", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", diff --git a/src/buildfile.js b/src/buildfile.js index ac1cb4b69efc24d1a575567277c99ce271a147af..58a2532f458a66899bc287b46e21b7b898e0ce1d 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -3,9 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -exports.base = require('./vs/base/buildfile').collectModules(); -exports.editor = require('./vs/editor/buildfile').collectModules(); -exports.languages = require('./vs/languages/buildfile').collectModules(); +exports.base = [{ + name: 'vs/base/common/worker/simpleWorker', + include: [ 'vs/editor/common/services/editorSimpleWorker' ], + prepend: [ 'vs/loader.js' ], + append: [ 'vs/base/worker/workerMain' ], + dest: 'vs/base/worker/workerMain.js' +}]; exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.main']); exports.code = require('./vs/code/buildfile').collectModules(); diff --git a/src/vs/base/buildfile.js b/src/vs/base/buildfile.js deleted file mode 100644 index 30b5bf9483695ec20bbe55395b80ecfba08e6445..0000000000000000000000000000000000000000 --- a/src/vs/base/buildfile.js +++ /dev/null @@ -1,18 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -exports.collectModules = function() { - return [{ - name: 'vs/base/common/worker/workerServer', - include: [ 'vs/editor/common/worker/editorWorkerServer' ], - exclude: [ 'vs/css', 'vs/nls' ] - }, { - name: 'vs/base/common/worker/simpleWorker', - include: [ 'vs/editor/common/services/editorSimpleWorker' ], - exclude: [ 'vs/css', 'vs/nls' ] - }]; -}; diff --git a/src/vs/base/common/comparers.ts b/src/vs/base/common/comparers.ts index 7d29ba9a8b0f07ebe1a37d1dbf9fa30734c1583a..a90bc8f98a51140a47ac7e7b51cd73e18de28afc 100644 --- a/src/vs/base/common/comparers.ts +++ b/src/vs/base/common/comparers.ts @@ -7,22 +7,26 @@ import scorer = require('vs/base/common/scorer'); import strings = require('vs/base/common/strings'); -const FileNameMatch = /^(.*)\.([^.]*)|([^.]+)$/; +const FileNameMatch = /^([^.]*)(\.(.*))?$/; export function compareFileNames(one: string, other: string): number { let oneMatch = FileNameMatch.exec(one.toLowerCase()); let otherMatch = FileNameMatch.exec(other.toLowerCase()); - let oneName = oneMatch[1] || oneMatch[3] || ''; - let oneExtension = oneMatch[2] || ''; + let oneName = oneMatch[1] || ''; + let oneExtension = oneMatch[3] || ''; - let otherName = otherMatch[1] || otherMatch[3] || ''; - let otherExtension = otherMatch[2] || ''; + let otherName = otherMatch[1] || ''; + let otherExtension = otherMatch[3] || ''; if (oneName !== otherName) { return oneName < otherName ? -1 : 1; } + if (oneExtension === otherExtension) { + return 0; + } + return oneExtension < otherExtension ? -1 : 1; } diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index f3e67f108f850ebb2c3f938b762ec1e092facd36..34ded84f8924f3a6bbb1a2e6318e13f07ade0a6b 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -179,13 +179,16 @@ function _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: nu } } +interface ICamelCaseAnalysis { + upperPercent: number; + lowerPercent: number; + alphaPercent: number; + numericPercent: number; +} + // Heuristic to avoid computing camel case matcher for words that don't // look like camelCaseWords. -function isCamelCaseWord(word: string): boolean { - if (word.length > 60) { - return false; - } - +function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis { let upper = 0, lower = 0, alpha = 0, numeric = 0, code = 0; for (let i = 0; i < word.length; i++) { @@ -202,6 +205,16 @@ function isCamelCaseWord(word: string): boolean { let alphaPercent = alpha / word.length; let numericPercent = numeric / word.length; + return { upperPercent, lowerPercent, alphaPercent, numericPercent }; +} + +function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean { + const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis; + return lowerPercent === 0 && upperPercent > 0.6; +} + +function isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean { + const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis; return lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2; } @@ -234,10 +247,20 @@ export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] return null; } - if (!isCamelCaseWord(camelCaseWord)) { + if (camelCaseWord.length > 60) { return null; } + const analysis = analyzeCamelCaseWord(camelCaseWord); + + if (!isCamelCaseWord(analysis)) { + if (!isUpperCaseWord(analysis)) { + return null; + } + + camelCaseWord = camelCaseWord.toLowerCase(); + } + let result: IMatch[] = null; let i = 0; diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index 013d00a0b1f64cd386052bc2103c3d2fe495d921..4c8554ef61fb734c11daee11390924d204dd76c4 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -7,11 +7,38 @@ import {transformErrorForSerialization} from 'vs/base/common/errors'; import {Disposable} from 'vs/base/common/lifecycle'; import {ErrorCallback, TPromise, ValueCallback} from 'vs/base/common/winjs.base'; -import {IWorker, IWorkerFactory} from './workerClient'; import {ShallowCancelThenPromise} from 'vs/base/common/async'; +import {isWeb} from 'vs/base/common/platform'; const INITIALIZE = '$initialize'; +export interface IWorker { + getId():number; + postMessage(message:string):void; + dispose():void; +} + +export interface IWorkerCallback { + (message:string):void; +} + +export interface IWorkerFactory { + create(moduleId:string, callback:IWorkerCallback, onErrorCallback:(err:any)=>void):IWorker; +} + +let webWorkerWarningLogged = false; +export function logOnceWebWorkerWarning(err: any): void { + if (!isWeb) { + // running tests + return; + } + if (!webWorkerWarningLogged) { + webWorkerWarningLogged = true; + console.warn('Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/Microsoft/monaco-editor#faq'); + } + console.warn(err.message); +} + interface IMessage { vsWorker: number; req?: string; @@ -308,7 +335,6 @@ export class SimpleWorkerServer { private initialize(workerId: number, moduleId: string, loaderConfig:any): TPromise { this._protocol.setWorkerId(workerId); - // TODO@Alex: share this code with workerServer if (loaderConfig) { // Remove 'baseUrl', handling it is beyond scope for now if (typeof loaderConfig.baseUrl !== 'undefined') { diff --git a/src/vs/base/common/worker/workerClient.ts b/src/vs/base/common/worker/workerClient.ts deleted file mode 100644 index 86a5676b3305d392b3813288cd02716c8e3812f2..0000000000000000000000000000000000000000 --- a/src/vs/base/common/worker/workerClient.ts +++ /dev/null @@ -1,327 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {onUnexpectedError} from 'vs/base/common/errors'; -import {parse, stringify} from 'vs/base/common/marshalling'; -import {TPromise} from 'vs/base/common/winjs.base'; -import * as workerProtocol from 'vs/base/common/worker/workerProtocol'; -import {isWeb} from 'vs/base/common/platform'; - -export interface IWorker { - getId():number; - postMessage(message:string):void; - dispose():void; -} - -let webWorkerWarningLogged = false; -export function logOnceWebWorkerWarning(err: any): void { - if (!isWeb) { - // running tests - return; - } - if (!webWorkerWarningLogged) { - webWorkerWarningLogged = true; - console.warn('Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/Microsoft/monaco-editor#faq'); - } - console.warn(err.message); -} - -export interface IWorkerCallback { - (message:string):void; -} - -export interface IWorkerFactory { - create(moduleId:string, callback:IWorkerCallback, onErrorCallback:(err:any)=>void):IWorker; -} - -interface IActiveRequest { - complete:(value:any)=>void; - error:(err:any)=>void; - progress:(progress:any)=>void; - type:string; - payload:any; -} - -export class WorkerClient { - - private _lastMessageId:number; - private _promises:{[id:string]:IActiveRequest;}; - private _worker:IWorker; - - private _messagesQueue:workerProtocol.IClientMessage[]; - private _processQueueTimeout:number; - private _waitingForWorkerReply:boolean; - - public onModuleLoaded:TPromise; - - constructor(workerFactory:IWorkerFactory, moduleId:string) { - this._lastMessageId = 0; - this._promises = {}; - - this._messagesQueue = []; - this._processQueueTimeout = -1; - this._waitingForWorkerReply = false; - - this._worker = workerFactory.create( - 'vs/base/common/worker/workerServer', - (msg) => this._onSerializedMessage(msg), - (err) => { - // reject the onModuleLoaded promise, this signals that things are bad - let promiseEntry:IActiveRequest = this._promises[1]; - delete this._promises[1]; - promiseEntry.error(err); - }); - - let loaderConfiguration:any = null; - - let globalRequire = (window).require; - if (typeof globalRequire.getConfig === 'function') { - // Get the configuration from the Monaco AMD Loader - loaderConfiguration = globalRequire.getConfig(); - } else if (typeof (window).requirejs !== 'undefined') { - // Get the configuration from requirejs - loaderConfiguration = (window).requirejs.s.contexts._.config; - } - - this.onModuleLoaded = this._sendMessage(workerProtocol.MessageType.INITIALIZE, { - id: this._worker.getId(), - moduleId: moduleId, - loaderConfiguration: loaderConfiguration - }); - } - - public request(requestName:string, payload:any): TPromise { - - if (requestName.charAt(0) === '$') { - throw new Error('Illegal requestName: ' + requestName); - } - - let shouldCancelPromise = false, - messagePromise:TPromise; - - return new TPromise((c, e, p) => { - - // hide the initialize promise inside this - // promise so that it won't be canceled by accident - this.onModuleLoaded.then(() => { - if (!shouldCancelPromise) { - messagePromise = this._sendMessage(requestName, payload).then(c, e, p); - } - }, e, p); - - }, () => { - // forward cancel to the proper promise - if(messagePromise) { - messagePromise.cancel(); - } else { - shouldCancelPromise = true; - } - }); - } - - public dispose(): void { - let promises = Object.keys(this._promises); - if (promises.length > 0) { - console.warn('Terminating a worker with ' + promises.length + ' pending promises:'); - console.warn(this._promises); - for (let id in this._promises) { - if (promises.hasOwnProperty(id)) { - this._promises[id].error('Worker forcefully terminated'); - } - } - } - this._worker.dispose(); - } - - private _sendMessage(type:string, payload:any):TPromise { - - let msg = { - id: ++this._lastMessageId, - type: type, - timestamp: Date.now(), - payload: payload - }; - - let pc:(value:any)=>void, pe:(err:any)=>void, pp:(progress:any)=>void; - let promise = new TPromise((c, e, p) => { - pc = c; - pe = e; - pp = p; - }, () => { - this._removeMessage(msg.id); - } - ); - - this._promises[msg.id] = { - complete: pc, - error: pe, - progress: pp, - type: type, - payload: payload - }; - - this._enqueueMessage(msg); - - return promise; - } - - private _enqueueMessage(msg:workerProtocol.IClientMessage): void { - - let lastIndexSmallerOrEqual = -1, - i:number; - - // Find the right index to insert at - keep the queue ordered by timestamp - for (i = this._messagesQueue.length - 1; i >= 0; i--) { - if (this._messagesQueue[i].timestamp <= msg.timestamp) { - lastIndexSmallerOrEqual = i; - break; - } - } - - this._messagesQueue.splice(lastIndexSmallerOrEqual + 1, 0, msg); - this._processMessagesQueue(); - } - - private _removeMessage(msgId:number): void { - for (let i = 0, len = this._messagesQueue.length; i < len; i++) { - if (this._messagesQueue[i].id === msgId) { - if (this._promises.hasOwnProperty(String(msgId))) { - delete this._promises[String(msgId)]; - } - this._messagesQueue.splice(i, 1); - this._processMessagesQueue(); - return; - } - } - } - - private _processMessagesQueue(): void { - if (this._processQueueTimeout !== -1) { - clearTimeout(this._processQueueTimeout); - this._processQueueTimeout = -1; - } - - if (this._messagesQueue.length === 0) { - return; - } - - if (this._waitingForWorkerReply) { - return; - } - - let delayUntilNextMessage = this._messagesQueue[0].timestamp - (new Date()).getTime(); - delayUntilNextMessage = Math.max(0, delayUntilNextMessage); - - this._processQueueTimeout = setTimeout(() => { - this._processQueueTimeout = -1; - if (this._messagesQueue.length === 0) { - return; - } - this._waitingForWorkerReply = true; - let msg = this._messagesQueue.shift(); - this._postMessage(msg); - }, delayUntilNextMessage); - } - - private _postMessage(msg:any): void { - if (this._worker) { - this._worker.postMessage(stringify(msg)); - } - } - - private _onSerializedMessage(msg:string): void { - let message:workerProtocol.IServerMessage = null; - try { - message = parse(msg); - } catch (e) { - // nothing - } - if (message) { - this._onmessage(message); - } - } - - private _onmessage(msg:workerProtocol.IServerMessage): void { - if (!msg.monacoWorker) { - return; - } - if (msg.from && msg.from !== this._worker.getId()) { - return; - } - - switch (msg.type) { - case workerProtocol.MessageType.REPLY: - let serverReplyMessage = msg; - - this._waitingForWorkerReply = false; - - if (!this._promises.hasOwnProperty(String(serverReplyMessage.id))) { - this._onError('Received unexpected message from Worker:', msg); - return; - } - - switch (serverReplyMessage.action) { - case workerProtocol.ReplyType.COMPLETE: - this._promises[serverReplyMessage.id].complete(serverReplyMessage.payload); - delete this._promises[serverReplyMessage.id]; - break; - - case workerProtocol.ReplyType.ERROR: - this._onError('Main Thread sent to worker the following message:', { - type: this._promises[serverReplyMessage.id].type, - payload: this._promises[serverReplyMessage.id].payload - }); - this._onError('And the worker replied with an error:', serverReplyMessage.payload); - onUnexpectedError(serverReplyMessage.payload); - this._promises[serverReplyMessage.id].error(serverReplyMessage.payload); - delete this._promises[serverReplyMessage.id]; - break; - - case workerProtocol.ReplyType.PROGRESS: - this._promises[serverReplyMessage.id].progress(serverReplyMessage.payload); - break; - } - break; - - case workerProtocol.MessageType.PRINT: - let serverPrintMessage = msg; - this._consoleLog(serverPrintMessage.level, serverPrintMessage.payload); - break; - - default: - this._onError('Received unexpected message from worker:', msg); - } - - this._processMessagesQueue(); - } - - _consoleLog(level:string, payload:any): void { - switch (level) { - case workerProtocol.PrintType.LOG: - console.log(payload); - break; - case workerProtocol.PrintType.DEBUG: - console.info(payload); - break; - case workerProtocol.PrintType.INFO: - console.info(payload); - break; - case workerProtocol.PrintType.WARN: - console.warn(payload); - break; - case workerProtocol.PrintType.ERROR: - console.error(payload); - break; - default: - this._onError('Received unexpected message from Worker:', payload); - } - } - - _onError(message:string, error?:any): void { - console.error(message); - console.info(error); - } -} diff --git a/src/vs/base/common/worker/workerProtocol.ts b/src/vs/base/common/worker/workerProtocol.ts deleted file mode 100644 index 7e063e0210cfc1dba6ef42984c9a8e5deb297c49..0000000000000000000000000000000000000000 --- a/src/vs/base/common/worker/workerProtocol.ts +++ /dev/null @@ -1,61 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -/** - * A message sent from the UI thread to a worker - */ -export interface IClientMessage { - id:number; - type:string; - timestamp:number; - payload:any; -} - -/** - * A message sent from a worker to the UI thread - */ -export interface IServerMessage { - monacoWorker:boolean; - from:number; - req:string; - type:string; - payload:any; -} - -/** - * A message sent from a worker to the UI thread in reply to a UI thread request - */ -export interface IServerReplyMessage extends IServerMessage { - id:number; - action:string; -} - -/** - * A message sent from a worker to the UI thread for debugging purposes (console.log, console.info, etc.) - */ -export interface IServerPrintMessage extends IServerMessage { - level:string; -} - -export var MessageType = { - INITIALIZE: '$initialize', - REPLY: '$reply', - PRINT: '$print' -}; - -export var ReplyType = { - COMPLETE: 'complete', - ERROR: 'error', - PROGRESS: 'progress' -}; - -export var PrintType = { - LOG: 'log', - DEBUG: 'debug', - INFO: 'info', - WARN: 'warn', - ERROR: 'error' -}; diff --git a/src/vs/base/common/worker/workerServer.ts b/src/vs/base/common/worker/workerServer.ts deleted file mode 100644 index 7122a3e1bd9eacbdcd051429207ed809f45f767d..0000000000000000000000000000000000000000 --- a/src/vs/base/common/worker/workerServer.ts +++ /dev/null @@ -1,147 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {setUnexpectedErrorHandler, transformErrorForSerialization} from 'vs/base/common/errors'; -import {parse, stringify} from 'vs/base/common/marshalling'; -import * as workerProtocol from 'vs/base/common/worker/workerProtocol'; - -export class WorkerServer { - - private _postSerializedMessage:(msg:string)=>void; - private _workerId:number; - private _requestHandler:any; - - constructor(postSerializedMessage:(msg:string)=>void) { - this._postSerializedMessage = postSerializedMessage; - this._workerId = 0; - this._requestHandler = null; - this._bindConsole(); - } - - private _bindConsole(): void { - ( self).console = { - log: this._sendPrintMessage.bind(this, workerProtocol.PrintType.LOG), - debug: this._sendPrintMessage.bind(this, workerProtocol.PrintType.DEBUG), - info: this._sendPrintMessage.bind(this, workerProtocol.PrintType.INFO), - warn: this._sendPrintMessage.bind(this, workerProtocol.PrintType.WARN), - error: this._sendPrintMessage.bind(this, workerProtocol.PrintType.ERROR) - }; - setUnexpectedErrorHandler((e) => { - self.console.error(e); - }); - } - - private _sendPrintMessage(level:string, ...objects:any[]): void { - let transformedObjects = objects.map((obj) => (obj instanceof Error) ? transformErrorForSerialization(obj) : obj); - let msg:workerProtocol.IServerPrintMessage = { - monacoWorker: true, - from: this._workerId, - req: '0', - type: workerProtocol.MessageType.PRINT, - level: level, - payload: (transformedObjects.length === 1 ? transformedObjects[0] : transformedObjects) - }; - this._postMessage(msg); - } - - private _sendReply(msgId:number, action:string, payload:any): void { - let msg:workerProtocol.IServerReplyMessage = { - monacoWorker: true, - from: this._workerId, - req: '0', - id: msgId, - type: workerProtocol.MessageType.REPLY, - action: action, - payload: (payload instanceof Error) ? transformErrorForSerialization(payload) : payload - }; - this._postMessage(msg); - } - - public loadModule(moduleId:string, callback:Function, errorback:(err:any)=>void): void { - // Use the global require to be sure to get the global config - (self).require([moduleId], (...result:any[]) => { - callback(result[0]); - }, errorback); - } - - public onmessage(msg:string): void { - this._onmessage(parse(msg)); - } - - private _postMessage(msg:workerProtocol.IServerMessage): void { - this._postSerializedMessage(stringify(msg)); - } - - private _onmessage(msg:workerProtocol.IClientMessage): void { - - let c = this._sendReply.bind(this, msg.id, workerProtocol.ReplyType.COMPLETE); - let e = this._sendReply.bind(this, msg.id, workerProtocol.ReplyType.ERROR); - let p = this._sendReply.bind(this, msg.id, workerProtocol.ReplyType.PROGRESS); - - switch(msg.type) { - case workerProtocol.MessageType.INITIALIZE: - this._workerId = msg.payload.id; - - let loaderConfig = msg.payload.loaderConfiguration; - // TODO@Alex: share this code with simpleWorker - if (loaderConfig) { - // Remove 'baseUrl', handling it is beyond scope for now - if (typeof loaderConfig.baseUrl !== 'undefined') { - delete loaderConfig['baseUrl']; - } - if (typeof loaderConfig.paths !== 'undefined') { - if (typeof loaderConfig.paths.vs !== 'undefined') { - delete loaderConfig.paths['vs']; - } - } - let nlsConfig = loaderConfig['vs/nls']; - // We need to have pseudo translation - if (nlsConfig && nlsConfig.pseudo) { - require(['vs/nls'], function(nlsPlugin) { - nlsPlugin.setPseudoTranslation(nlsConfig.pseudo); - }); - } - - // Since this is in a web worker, enable catching errors - loaderConfig.catchError = true; - (self).require.config(loaderConfig); - } - - this.loadModule(msg.payload.moduleId, (handlerModule:any) => { - this._requestHandler = handlerModule.value; - c(); - }, e); - break; - - default: - this._handleMessage(msg, c, e, p); - break; - } - } - - private _handleMessage(msg:workerProtocol.IClientMessage, c:(value:any)=>void, e:(err:any)=>void, p:(progress:any)=>void): void { - if (!this._requestHandler) { - e('Request handler not loaded'); - return; - } - - let handlerMethod = this._requestHandler[msg.type]; - if (typeof handlerMethod !== 'function') { - e('Handler does not have method ' + msg.type); - return; - } - - try { - handlerMethod.call(this._requestHandler, this, c, e, p, msg.payload); - } catch (handlerError) { - e(transformErrorForSerialization(handlerError)); - } - } -} - -export function create(postMessage:(msg:string)=>void): WorkerServer { - return new WorkerServer(postMessage); -} diff --git a/src/vs/base/test/common/comparers.test.ts b/src/vs/base/test/common/comparers.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b1b475303e0c9816f8704b6c92d805caaf2ad256 --- /dev/null +++ b/src/vs/base/test/common/comparers.test.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { compareFileNames } from 'vs/base/common/comparers'; +import * as assert from 'assert'; + +suite('Comparers', () => { + + test('compareFileNames', () => { + + assert(compareFileNames('', '') === 0, 'empty should be equal'); + assert(compareFileNames('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNames('.abc', '.abc') === 0, 'equal full names should be equal'); + assert(compareFileNames('.env', '.env.example') < 0); + assert(compareFileNames('.env.example', '.gitattributes') < 0); + }); +}); diff --git a/src/vs/base/worker/defaultWorkerFactory.ts b/src/vs/base/worker/defaultWorkerFactory.ts index 87d36ddc78b243c8bd6441aa299736270ec5bfa0..612809e6ef6fc0d4e78e215d11bcad8017e3c485 100644 --- a/src/vs/base/worker/defaultWorkerFactory.ts +++ b/src/vs/base/worker/defaultWorkerFactory.ts @@ -5,9 +5,7 @@ 'use strict'; import * as flags from 'vs/base/common/flags'; -import {IDisposable, dispose} from 'vs/base/common/lifecycle'; -import {logOnceWebWorkerWarning, IWorker, IWorkerCallback, IWorkerFactory} from 'vs/base/common/worker/workerClient'; -import * as dom from 'vs/base/browser/dom'; +import {logOnceWebWorkerWarning, IWorker, IWorkerCallback, IWorkerFactory} from 'vs/base/common/worker/simpleWorker'; function defaultGetWorkerUrl(workerId:string, label:string): string { return require.toUrl('./' + workerId) + '#' + label; @@ -52,117 +50,25 @@ class WebWorker implements IWorker { } } -/** - * A worker that runs in an iframe and therefore does have its - * own global scope, but no own thread. - */ -class FrameWorker implements IWorker { - - private id: number; - private iframe: HTMLIFrameElement; - - private onMessage: EventListener; - private loaded: boolean; - private beforeLoadMessages: any[]; - - private _listeners: IDisposable[]; - - constructor(moduleId:string, id: number, onMessageCallback:IWorkerCallback) { - this.id = id; - this._listeners = []; - - // Collect all messages sent to the worker until the iframe is loaded - this.loaded = false; - this.beforeLoadMessages = []; - - this.postMessage(moduleId); - - this.iframe = document.createElement('iframe'); - this.iframe.id = this.iframeId(); - this.iframe.src = require.toUrl('./workerMainCompatibility.html'); - ( this.iframe).frameborder = this.iframe.height = this.iframe.width = '0'; - this.iframe.style.display = 'none'; - this._listeners.push(dom.addDisposableListener(this.iframe, 'load', () => this.onLoaded())); - - this.onMessage = function(ev:any) { - onMessageCallback(ev.data); - }; - this._listeners.push(dom.addDisposableListener(window, 'message', this.onMessage)); - document.body.appendChild(this.iframe); - } - - public dispose(): void { - this._listeners = dispose(this._listeners); - window.removeEventListener('message', this.onMessage); - window.frames[this.iframeId()].close(); - } - - private iframeId(): string { - return 'worker_iframe_' + this.id; - } - - private onLoaded(): void { - this.loaded = true; - while (this.beforeLoadMessages.length > 0) { - this.postMessage(this.beforeLoadMessages.shift()); - } - } - - public getId(): number { - return this.id; - } - - public postMessage(msg:string): void { - if (this.loaded === true) { - var iframe = window.frames[this.iframeId()]; - if (iframe.postMessage) { - iframe.postMessage(msg, '*'); - } else { - iframe.contentWindow.postMessage(msg, '*'); - } - } else { - this.beforeLoadMessages.push(msg); - } - } -} - export class DefaultWorkerFactory implements IWorkerFactory { private static LAST_WORKER_ID = 0; private _label: string; - private _fallbackToIframe:boolean; private _webWorkerFailedBeforeError:any; - constructor(label:string, fallbackToIframe:boolean) { + constructor(label:string) { this._label = label; - this._fallbackToIframe = fallbackToIframe; this._webWorkerFailedBeforeError = false; } public create(moduleId:string, onMessageCallback:IWorkerCallback, onErrorCallback:(err:any)=>void):IWorker { let workerId = (++DefaultWorkerFactory.LAST_WORKER_ID); - if (this._fallbackToIframe) { - if (this._webWorkerFailedBeforeError) { - // Avoid always trying to create web workers if they would just fail... - return new FrameWorker(moduleId, workerId, onMessageCallback); - } - - try { - return new WebWorker(moduleId, workerId, this._label || 'anonymous' + workerId, onMessageCallback, (err) => { - logOnceWebWorkerWarning(err); - this._webWorkerFailedBeforeError = err; - onErrorCallback(err); - }); - } catch(err) { - logOnceWebWorkerWarning(err); - return new FrameWorker(moduleId, workerId, onMessageCallback); - } - } if (this._webWorkerFailedBeforeError) { throw this._webWorkerFailedBeforeError; } + return new WebWorker(moduleId, workerId, this._label || 'anonymous' + workerId, onMessageCallback, (err) => { logOnceWebWorkerWarning(err); this._webWorkerFailedBeforeError = err; diff --git a/src/vs/base/worker/workerMainCompatibility.html b/src/vs/base/worker/workerMainCompatibility.html deleted file mode 100644 index fd14681aadde9c4a1884c8c2e01659593d0e4312..0000000000000000000000000000000000000000 --- a/src/vs/base/worker/workerMainCompatibility.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - -
compatibility worker iframe
- - diff --git a/src/vs/editor/browser/editor.all.ts b/src/vs/editor/browser/editor.all.ts index 0ae86cff88cb9050ab85877a7b13d627b02d07a2..2451aec5e4659b450a7766e8bcb63f596cc4b4c8 100644 --- a/src/vs/editor/browser/editor.all.ts +++ b/src/vs/editor/browser/editor.all.ts @@ -43,5 +43,3 @@ import 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; import 'vs/editor/contrib/folding/browser/folding'; import 'vs/editor/contrib/indentation/common/indentation'; -// include these in the editor bundle because they are widely used by many languages -import 'vs/editor/common/languages.common'; diff --git a/src/vs/editor/browser/standalone/standaloneLanguages.ts b/src/vs/editor/browser/standalone/standaloneLanguages.ts index cb7e444264682002e9447232092bf29c48370a6c..088dd6d55310105c93f0f9bf916928b74511d046 100644 --- a/src/vs/editor/browser/standalone/standaloneLanguages.ts +++ b/src/vs/editor/browser/standalone/standaloneLanguages.ts @@ -37,7 +37,6 @@ export function register(language:ILanguageExtensionPoint): void { export function getLanguages(): ILanguageExtensionPoint[] { let result:ILanguageExtensionPoint[] = []; result = result.concat(ModesRegistry.getLanguages()); - result = result.concat(ModesRegistry.getCompatModes()); return result; } @@ -105,7 +104,24 @@ export function registerSignatureHelpProvider(languageId:string, provider:modes. * Register a hover provider (used by e.g. editor hover). */ export function registerHoverProvider(languageId:string, provider:modes.HoverProvider): IDisposable { - return modes.HoverProviderRegistry.register(languageId, provider); + return modes.HoverProviderRegistry.register(languageId, { + provideHover: (model:editorCommon.IReadOnlyModel, position:Position, token:CancellationToken): Thenable => { + let word = model.getWordAtPosition(position); + + return toThenable(provider.provideHover(model, position, token)).then((value) => { + if (!value) { + return; + } + if (!value.range && word) { + value.range = new Range(position.lineNumber, word.startColumn, position.column, word.endColumn); + } + if (!value.range) { + value.range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); + } + return value; + }); + } + }); } /** diff --git a/src/vs/editor/buildfile.js b/src/vs/editor/buildfile.js deleted file mode 100644 index ddbe46302a425ddfbc51c8837f11df4561965b77..0000000000000000000000000000000000000000 --- a/src/vs/editor/buildfile.js +++ /dev/null @@ -1,10 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -exports.collectModules = function() { - return []; -}; diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 28d4a2debea41c2567e8017cc3b1d5efc09e9d29..c74baecfea6baa4062f194002e8e82d6044e4923 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -10,7 +10,7 @@ import {Disposable, IDisposable, dispose} from 'vs/base/common/lifecycle'; import {TPromise} from 'vs/base/common/winjs.base'; import {ServicesAccessor, IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; -import {IContextKey, IContextKeyServiceTarget, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; +import {ContextKeyExpr, IContextKey, IContextKeyServiceTarget, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; import {CommonEditorConfiguration} from 'vs/editor/common/config/commonEditorConfig'; import {DefaultConfig} from 'vs/editor/common/config/defaultConfig'; import {Cursor} from 'vs/editor/common/controller/cursor'; @@ -27,6 +27,8 @@ import {SplitLinesCollection} from 'vs/editor/common/viewModel/splitLinesCollect import {ViewModel} from 'vs/editor/common/viewModel/viewModelImpl'; import {hash} from 'vs/base/common/hash'; import {EditorModeContext} from 'vs/editor/common/modes/editorModeContext'; +import {MenuId, MenuRegistry, IMenuItem} from 'vs/platform/actions/common/actions'; +import {CommandsRegistry} from 'vs/platform/commands/common/commands'; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -511,7 +513,30 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom ) { throw new Error('Invalid action descriptor, `id`, `label` and `run` are required properties!'); } + + // Generate a unique id to allow the same descriptor.id across multiple editor instances + let uniqueId = this.getId() + ':' + descriptor.id; + let action = new DynamicEditorAction(descriptor, this); + + // Register the command + CommandsRegistry.registerCommand(uniqueId, () => action.run()); + + if (descriptor.contextMenuGroupId) { + let menuItem: IMenuItem = { + command: { + id: uniqueId, + title: descriptor.label + }, + when: ContextKeyExpr.equals('editorId', this.getId()), + group: descriptor.contextMenuGroupId, + order: descriptor.contextMenuOrder || 0 + }; + + // Register the menu item + MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem); + } + this._actions[action.id] = action; } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index e892b495887ed7badb5bc62c3cb734c4032ddd31..08f35cc944f58acaac60367c3b0719601392a9a9 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -3439,6 +3439,20 @@ export interface IActionDescriptor { * An array of keybindings for the action. */ keybindings?: number[]; + /** + * Control if the action should show up in the context menu and where. + * The context menu of the editor has these default: + * navigation - The navigation group comes first in all cases. + * 1_modification - This group comes next and contains commands that modify your code. + * 9_cutcopypaste - The last default group with the basic editing commands. + * You can also create your own group. + * Defaults to null (don't show in context menu). + */ + contextMenuGroupId?: string; + /** + * Control the order in the context menu group. + */ + contextMenuOrder?: number; /** * The keybinding rule. */ diff --git a/src/vs/editor/common/languages.common.ts b/src/vs/editor/common/languages.common.ts deleted file mode 100644 index 7354ba318b26b4e90f31e1971c266a6b74df888c..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/languages.common.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -// base common -import 'vs/base/common/assert'; -import 'vs/base/common/async'; -import 'vs/base/common/callbackList'; -import 'vs/base/common/cancellation'; -import 'vs/base/common/collections'; -import 'vs/base/common/event'; -import 'vs/base/common/events'; -import 'vs/base/common/lifecycle'; -import 'vs/base/common/paths'; -import 'vs/base/common/uri'; - -// platform common -import 'vs/platform/platform'; -import 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import 'vs/platform/workspace/common/workspace'; -import 'vs/platform/telemetry/common/telemetry'; - -// editor common -import 'vs/editor/common/editorCommon'; -import 'vs/editor/common/modes'; -import 'vs/editor/common/modes/abstractMode'; -import 'vs/editor/common/modes/abstractState'; -import 'vs/editor/common/modes/monarch/monarchCommon'; -import 'vs/editor/common/modes/monarch/monarchLexer'; -import 'vs/editor/common/modes/monarch/monarchCompile'; -import 'vs/editor/common/modes/languageConfigurationRegistry'; -import 'vs/editor/common/modes/supports/suggestSupport'; -import 'vs/editor/common/modes/supports/tokenizationSupport'; -import 'vs/editor/common/services/modelService'; -import 'vs/editor/common/services/modeService'; -import 'vs/editor/common/services/compatWorkerService'; diff --git a/src/vs/editor/common/model/compatMirrorModel.ts b/src/vs/editor/common/model/compatMirrorModel.ts deleted file mode 100644 index 23fcc2abb06888f8795ab4c5756deeb6de80af38..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/model/compatMirrorModel.ts +++ /dev/null @@ -1,144 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 URI from 'vs/base/common/uri'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import {ModelLine} from 'vs/editor/common/model/modelLine'; -import {TextModelWithTokens} from 'vs/editor/common/model/textModelWithTokens'; -import {ICompatMirrorModel} from 'vs/editor/common/services/resourceService'; - -export interface ICompatMirrorModelEvents { - contentChanged: editorCommon.IModelContentChangedEvent[]; -} - -const NO_TAB_SIZE = 0; - -export class CompatMirrorModel extends TextModelWithTokens implements ICompatMirrorModel { - - protected _associatedResource:URI; - - constructor(versionId:number, value:editorCommon.IRawText, languageId:string, associatedResource?:URI) { - super(['changed', editorCommon.EventType.ModelDispose], value, languageId); - - this._setVersionId(versionId); - this._associatedResource = associatedResource; - } - - public dispose(): void { - this.emit(editorCommon.EventType.ModelDispose); - super.dispose(); - } - - public get uri(): URI { - return this._associatedResource; - } - - protected _constructLines(rawText:editorCommon.IRawText):void { - super._constructLines(rawText); - // Force EOL to be \n - this._EOL = '\n'; - } - - public onEvents(events:ICompatMirrorModelEvents) : void { - let changed = false; - for (let i = 0, len = events.contentChanged.length; i < len; i++) { - let contentChangedEvent = events.contentChanged[i]; - - this._setVersionId(contentChangedEvent.versionId); - switch (contentChangedEvent.changeType) { - case editorCommon.EventType.ModelRawContentChangedFlush: - this._onLinesFlushed(contentChangedEvent); - changed = true; - break; - - case editorCommon.EventType.ModelRawContentChangedLinesDeleted: - this._onLinesDeleted(contentChangedEvent); - changed = true; - break; - - case editorCommon.EventType.ModelRawContentChangedLinesInserted: - this._onLinesInserted(contentChangedEvent); - changed = true; - break; - - case editorCommon.EventType.ModelRawContentChangedLineChanged: - this._onLineChanged(contentChangedEvent); - changed = true; - break; - } - } - - if (changed) { - this.emit('changed', {}); - } - } - - private _onLinesFlushed(e:editorCommon.IModelContentChangedFlushEvent): void { - // Flush my lines - this._constructLines(e.detail); - this._resetTokenizationState(); - } - - private _onLineChanged(e:editorCommon.IModelContentChangedLineChangedEvent) : void { - this._lines[e.lineNumber - 1].applyEdits({}, [{ - startColumn: 1, - endColumn: Number.MAX_VALUE, - text: e.detail, - forceMoveMarkers: false - }], NO_TAB_SIZE); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.changeValue(e.lineNumber - 1, this._lines[e.lineNumber - 1].text.length + this._EOL.length); - } - - this._invalidateLine(e.lineNumber - 1); - } - - private _onLinesDeleted(e:editorCommon.IModelContentChangedLinesDeletedEvent) : void { - var fromLineIndex = e.fromLineNumber - 1, - toLineIndex = e.toLineNumber - 1; - - // Save first line's state - var firstLineState = this._lines[fromLineIndex].getState(); - - this._lines.splice(fromLineIndex, toLineIndex - fromLineIndex + 1); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.removeValues(fromLineIndex, toLineIndex - fromLineIndex + 1); - } - - if (fromLineIndex < this._lines.length) { - // This check is always true in real world, but the tests forced this - - // Restore first line's state - this._lines[fromLineIndex].setState(firstLineState); - - // Invalidate line - this._invalidateLine(fromLineIndex); - } - } - - private _onLinesInserted(e:editorCommon.IModelContentChangedLinesInsertedEvent) : void { - var lineIndex:number, - i:number, - splitLines = e.detail.split('\n'); - - let newLengths:number[] = []; - for (lineIndex = e.fromLineNumber - 1, i = 0; lineIndex < e.toLineNumber; lineIndex++, i++) { - this._lines.splice(lineIndex, 0, new ModelLine(0, splitLines[i], NO_TAB_SIZE)); - newLengths.push(splitLines[i].length + this._EOL.length); - } - if (this._lineStarts) { - // update prefix sum - this._lineStarts.insertValues(e.fromLineNumber - 1, newLengths); - } - - if (e.fromLineNumber >= 2) { - // This check is always true in real world, but the tests forced this - this._invalidateLine(e.fromLineNumber - 2); - } - } -} diff --git a/src/vs/editor/common/model/wordHelper.ts b/src/vs/editor/common/model/wordHelper.ts index 7f1c8f0ed421e7446156977fc78755e9ea52204f..2fefeae019dc182ceed649245bf34b2e883f0c5a 100644 --- a/src/vs/editor/common/model/wordHelper.ts +++ b/src/vs/editor/common/model/wordHelper.ts @@ -15,7 +15,7 @@ export const USUAL_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?'; * The default would look like this: * /(-?\d*\.\d\w*)|([^\`\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g */ -export function createWordRegExp(allowInWords:string = ''): RegExp { +function createWordRegExp(allowInWords:string = ''): RegExp { var usualSeparators = USUAL_WORD_SEPARATORS; var source = '(-?\\d*\\.\\d\\w*)|([^'; for (var i = 0; i < usualSeparators.length; i++) { diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index da7ad5d7ba3c1b29d9dd6d2f8305cb040932c33a..90339beb8d0dbded43239e27978494f12d1ca65e 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -18,15 +18,6 @@ import {Position} from 'vs/editor/common/core/position'; import {Range} from 'vs/editor/common/core/range'; import Event, {Emitter} from 'vs/base/common/event'; -/** - * @internal - */ -export interface ITokenizationResult { - type?:string; - dontMergeWithPrev?:boolean; - nextState?:IState; -} - /** * @internal */ @@ -34,131 +25,10 @@ export interface IState { clone():IState; equals(other:IState):boolean; getModeId():string; - tokenize(stream:IStream):ITokenizationResult; getStateData(): IState; setStateData(state:IState):void; } -/** - * An IStream is a character & token stream abstraction over a line of text. It - * is never multi-line. The stream can be navigated character by character, or - * token by token, given some token rules. - * @internal - */ -export interface IStream { - - /** - * Returns the current character position of the stream on the line. - */ - pos():number; - - /** - * Returns true iff the stream is at the end of the line. - */ - eos():boolean; - - /** - * Returns the next character in the stream. - */ - peek():string; - - /** - * Returns the next character in the stream, and advances it by one character. - */ - next(): string; - next2(): void; - - /** - * Advances the stream by `n` characters. - */ - advance(n:number):string; - - /** - * Advances the stream until the end of the line. - */ - advanceToEOS():string; - - /** - * Brings the stream back `n` characters. - */ - goBack(n:number):void; - - /** - * Advances the stream if the next characters validate a condition. A condition can be - * - * - a regular expression (always starting with ^) - * EXAMPLES: /^\d+/, /^function|var|interface|class/ - * - * - a string - * EXAMPLES: "1954", "albert" - */ - advanceIfCharCode(charCode: number): string; - advanceIfCharCode2(charCode:number): number; - - advanceIfString(condition: string): string; - advanceIfString2(condition: string): number; - - advanceIfStringCaseInsensitive(condition: string): string; - advanceIfStringCaseInsensitive2(condition: string): number; - - advanceIfRegExp(condition: RegExp): string; - advanceIfRegExp2(condition:RegExp): number; - - - /** - * Advances the stream while the next characters validate a condition. Check #advanceIf for - * details on the possible types for condition. - */ - advanceWhile(condition:string):string; - advanceWhile(condition:RegExp):string; - - /** - * Advances the stream until the some characters validate a condition. Check #advanceIf for - * details on the possible types for condition. The `including` boolean value indicates - * whether the stream will advance the characters that matched the condition as well, or not. - */ - advanceUntil(condition: string, including: boolean): string; - advanceUntil(condition: RegExp, including: boolean): string; - - advanceUntilString(condition: string, including: boolean): string; - advanceUntilString2(condition: string, including: boolean): number; - - /** - * The token rules define how consecutive characters should be put together as a token, - * or separated into two different tokens. They are given through a separator characters - * string and a whitespace characters string. A separator is always one token. Consecutive - * whitespace is always one token. Everything in between these two token types, is also a token. - * - * EXAMPLE: stream.setTokenRules("+-", " "); - * Setting these token rules defines the tokens for the string "123+456 - 7" as being - * ["123", "+", "456", " ", "-", " ", "7"] - */ - setTokenRules(separators:string, whitespace:string):void; - - /** - * Returns the next token, given that the stream was configured with token rules. - */ - peekToken():string; - - /** - * Returns the next token, given that the stream was configured with token rules, and advances the - * stream by the exact length of the found token. - */ - nextToken():string; - - /** - * Returns the next whitespace, if found. Returns an empty string otherwise. - */ - peekWhitespace():string; - - /** - * Returns the next whitespace, if found, and advances the stream by the exact length of the found - * whitespace. Returns an empty string otherwise. - */ - skipWhitespace(): string; - skipWhitespace2(): number; -} - /** * @internal */ diff --git a/src/vs/editor/common/modes/TMState.ts b/src/vs/editor/common/modes/TMState.ts index d2f225cc12e25fbecd33c928e004ef75d1441865..e05ffc62d6daa98ee014bb42143fe4130afde250 100644 --- a/src/vs/editor/common/modes/TMState.ts +++ b/src/vs/editor/common/modes/TMState.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IState, ITokenizationResult} from 'vs/editor/common/modes'; +import {IState} from 'vs/editor/common/modes'; import {AbstractState} from 'vs/editor/common/modes/abstractState'; import {StackElement} from 'vscode-textmate'; @@ -50,10 +50,6 @@ export class TMState implements IState { return this._modeId; } - public tokenize(stream:any):ITokenizationResult { - throw new Error(); - } - public getStateData():IState { return this._parentEmbedderState; } diff --git a/src/vs/editor/common/modes/abstractMode.ts b/src/vs/editor/common/modes/abstractMode.ts index 7ebd7fe1f9cc64cac33ebb2950adff56ca254cfb..d7769f9f7f2736b915a7a134a21e461e9d446e2a 100644 --- a/src/vs/editor/common/modes/abstractMode.ts +++ b/src/vs/editor/common/modes/abstractMode.ts @@ -4,77 +4,13 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {AsyncDescriptor1, createAsyncDescriptor1} from 'vs/platform/instantiation/common/descriptors'; -import {IInstantiationService, optional} from 'vs/platform/instantiation/common/instantiation'; +import {optional} from 'vs/platform/instantiation/common/instantiation'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import * as modes from 'vs/editor/common/modes'; import {TextualSuggestSupport} from 'vs/editor/common/modes/supports/suggestSupport'; import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; -import * as wordHelper from 'vs/editor/common/model/wordHelper'; -import {ICompatWorkerService, ICompatMode} from 'vs/editor/common/services/compatWorkerService'; -import {CharCode} from 'vs/base/common/charCode'; - -export function createWordRegExp(allowInWords:string = ''): RegExp { - return wordHelper.createWordRegExp(allowInWords); -} - -export class ModeWorkerManager { - - private _descriptor: modes.IModeDescriptor; - private _workerDescriptor: AsyncDescriptor1; - private _superWorkerModuleId: string; - private _instantiationService: IInstantiationService; - private _workerPiecePromise:TPromise; - - constructor( - descriptor:modes.IModeDescriptor, - workerModuleId:string, - workerClassName:string, - superWorkerModuleId:string, - instantiationService: IInstantiationService - ) { - this._descriptor = descriptor; - this._workerDescriptor = createAsyncDescriptor1(workerModuleId, workerClassName); - this._superWorkerModuleId = superWorkerModuleId; - this._instantiationService = instantiationService; - this._workerPiecePromise = null; - } - - public worker(runner:(worker:W)=>TPromise): TPromise - public worker(runner:(worker:W)=>T): TPromise { - return this._getOrCreateWorker().then(runner); - } - - private _getOrCreateWorker(): TPromise { - if (!this._workerPiecePromise) { - // TODO@Alex: workaround for missing `bundles` config - - // First, load the code of the worker super class - let superWorkerCodePromise = (this._superWorkerModuleId ? ModeWorkerManager._loadModule(this._superWorkerModuleId) : TPromise.as(null)); - - this._workerPiecePromise = superWorkerCodePromise.then(() => { - // Second, load the code of the worker (without instantiating it) - return ModeWorkerManager._loadModule(this._workerDescriptor.moduleName); - }).then(() => { - // Finally, create the mode worker instance - return this._instantiationService.createInstance(this._workerDescriptor, this._descriptor.id); - }); - } - - return this._workerPiecePromise; - } - - private static _loadModule(moduleName:string): TPromise { - return new TPromise((c, e, p) => { - // Use the global require to be sure to get the global config - (self).require([moduleName], c, e); - }, () => { - // Cannot cancel loading code - }); - } -} +// TODO@Alex: inline to FrankensteinMode, review optional IEditorWorkerService export abstract class AbstractMode implements modes.IMode { private _modeId: string; @@ -88,59 +24,6 @@ export abstract class AbstractMode implements modes.IMode { } } -export abstract class CompatMode extends AbstractMode implements ICompatMode { - - public compatWorkerService:ICompatWorkerService; - - constructor(modeId:string, compatWorkerService:ICompatWorkerService) { - super(modeId); - this.compatWorkerService = compatWorkerService; - - if (this.compatWorkerService) { - this.compatWorkerService.registerCompatMode(this); - } - } - -} - -export function isDigit(character:string, base:number): boolean { - let c = character.charCodeAt(0); - switch (base) { - case 1: - return c === CharCode.Digit0; - case 2: - return c >= CharCode.Digit0 && c <= CharCode.Digit1; - case 3: - return c >= CharCode.Digit0 && c <= CharCode.Digit2; - case 4: - return c >= CharCode.Digit0 && c <= CharCode.Digit3; - case 5: - return c >= CharCode.Digit0 && c <= CharCode.Digit4; - case 6: - return c >= CharCode.Digit0 && c <= CharCode.Digit5; - case 7: - return c >= CharCode.Digit0 && c <= CharCode.Digit6; - case 8: - return c >= CharCode.Digit0 && c <= CharCode.Digit7; - case 9: - return c >= CharCode.Digit0 && c <= CharCode.Digit8; - case 10: - return c >= CharCode.Digit0 && c <= CharCode.Digit9; - case 11: - return (c >= CharCode.Digit0 && c <= CharCode.Digit9) || (c === CharCode.a) || (c === CharCode.A); - case 12: - return (c >= CharCode.Digit0 && c <= CharCode.Digit9) || (c >= CharCode.a && c <= CharCode.b) || (c >= CharCode.A && c <= CharCode.B); - case 13: - return (c >= CharCode.Digit0 && c <= CharCode.Digit9) || (c >= CharCode.a && c <= CharCode.c) || (c >= CharCode.A && c <= CharCode.C); - case 14: - return (c >= CharCode.Digit0 && c <= CharCode.Digit9) || (c >= CharCode.a && c <= CharCode.d) || (c >= CharCode.A && c <= CharCode.D); - case 15: - return (c >= CharCode.Digit0 && c <= CharCode.Digit9) || (c >= CharCode.a && c <= CharCode.e) || (c >= CharCode.A && c <= CharCode.E); - default: - return (c >= CharCode.Digit0 && c <= CharCode.Digit9) || (c >= CharCode.a && c <= CharCode.f) || (c >= CharCode.A && c <= CharCode.F); - } -} - export class FrankensteinMode extends AbstractMode { constructor( diff --git a/src/vs/editor/common/modes/abstractState.ts b/src/vs/editor/common/modes/abstractState.ts index 6a6546b2440ae5acf455dc6b83cfb07ce5053553..16aba109b605a74b72c2a612d3412866ceef19cd 100644 --- a/src/vs/editor/common/modes/abstractState.ts +++ b/src/vs/editor/common/modes/abstractState.ts @@ -4,10 +4,22 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IState, IStream, ITokenizationResult} from 'vs/editor/common/modes'; +import {IState} from 'vs/editor/common/modes'; +import {LineStream} from 'vs/editor/common/modes/lineStream'; + +/** + * @internal + */ +export interface ITokenizationResult { + type?:string; + dontMergeWithPrev?:boolean; + nextState?:AbstractState; +} export abstract class AbstractState implements IState { + _abstractStateBrand: void; + private modeId:string; private stateData:IState; @@ -50,7 +62,7 @@ export abstract class AbstractState implements IState { return false; } - public abstract tokenize(stream:IStream):ITokenizationResult; + public abstract tokenize(stream:LineStream):ITokenizationResult; public static safeEquals(a: IState, b: IState): boolean { if (a === null && b === null) { diff --git a/src/vs/editor/common/modes/lineStream.ts b/src/vs/editor/common/modes/lineStream.ts index 3ca3009cb147a0ccf4f4d3310c79031d31403e85..e0b59398ba49bb40fecaded5190fe6edc7840d8c 100644 --- a/src/vs/editor/common/modes/lineStream.ts +++ b/src/vs/editor/common/modes/lineStream.ts @@ -4,66 +4,41 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IStream} from 'vs/editor/common/modes'; -import {CharacterClassifier} from 'vs/editor/common/core/characterClassifier'; - -class CharacterSet { - - private static _CACHE:{ [key:string]:CharacterSet; } = {}; // TODO@Alex unbounded cache - - public static getOrCreate(source:string): CharacterSet { - if (!CharacterSet._CACHE.hasOwnProperty(source)) { - CharacterSet._CACHE[source] = new CharacterSet(source); - } - return CharacterSet._CACHE[source]; - } - - private _classifier: CharacterClassifier; - - constructor(source:string) { - this._classifier = new CharacterClassifier(false); - for (let i = 0, len = source.length; i < len; i++) { - this._classifier.set(source.charCodeAt(i), true); - } - } - - public contains(charCode:number): boolean { - return this._classifier.get(charCode); - } -} - -export class LineStream implements IStream { +/** + * A LineStream is a character & token stream abstraction over a line of text. It + * is never multi-line. The stream can be navigated character by character, or + * token by token, given some token rules. + * @internal + */ +export class LineStream { private _source:string; private _sourceLength:number; private _pos:number; - private _whitespace:string; - private _whitespaceArr:CharacterSet; - private _separators:string; - private _separatorsArr:CharacterSet; - private _tokenStart:number; - private _tokenEnd:number; constructor(source:string) { this._source = source; this._sourceLength = source.length; this._pos = 0; - this._whitespace = '\t \u00a0'; - this._whitespaceArr = CharacterSet.getOrCreate(this._whitespace); - this._separators = ''; - this._separatorsArr = CharacterSet.getOrCreate(this._separators); - this._tokenStart = -1; - this._tokenEnd = -1; } + /** + * Returns the current character position of the stream on the line. + */ public pos():number { return this._pos; } + /** + * Returns true iff the stream is at the end of the line. + */ public eos() { return this._pos >= this._sourceLength; } + /** + * Returns the next character in the stream. + */ public peek():string { // Check EOS if (this._pos >= this._sourceLength) { @@ -72,359 +47,29 @@ export class LineStream implements IStream { return this._source[this._pos]; } - public next():string { - // Check EOS - if (this._pos >= this._sourceLength) { - throw new Error('Stream is at the end'); - } - - // Reset peeked token - this._tokenStart = -1; - this._tokenEnd = -1; - - return this._source[this._pos++]; - } - - public next2(): void { - // Check EOS - if (this._pos >= this._sourceLength) { - throw new Error('Stream is at the end'); - } - - // Reset peeked token - this._tokenStart = -1; - this._tokenEnd = -1; - - this._pos++; - } - - public advance(n: number): string { + /** + * Advances the stream by `n` characters. + */ + public advance(n: number): void { if (n === 0) { - return ''; + return; } - const oldPos = this._pos; this._pos += n; - // Reset peeked token - this._tokenStart = -1; - this._tokenEnd = -1; - return this._source.substring(oldPos, this._pos); - } - - private _advance2(n: number): number { - if (n === 0) { - return n; - } - this._pos += n; - // Reset peeked token - this._tokenStart = -1; - this._tokenEnd = -1; - return n; } + /** + * Advances the stream until the end of the line. + */ public advanceToEOS():string { const oldPos = this._pos; this._pos = this._sourceLength; - this.resetPeekedToken(); return this._source.substring(oldPos, this._pos); } + /** + * Brings the stream back `n` characters. + */ public goBack(n:number) { this._pos -= n; - this.resetPeekedToken(); - } - - private createPeeker(condition:RegExp|string):()=>number { - if (condition instanceof RegExp) { - return () => { - let result = condition.exec(this._source.substr(this._pos)); - if (result === null) { - return 0; - } else if (result.index !== 0) { - throw new Error('Regular expression must begin with the character "^"'); - } - return result[0].length; - }; - } else if ((typeof condition === 'string') && condition) { - return () => { - const len = condition.length; - let match = (this._pos + len <= this._sourceLength); - for (let i = 0; match && i < len; i++) { - match = this._source.charCodeAt(this._pos + i) === condition.charCodeAt(i); - } - return (match ? len : 0); - }; - } - throw new Error('Condition must be either a regular expression, function or a non-empty string'); - } - - // --- BEGIN `_advanceIfStringCaseInsensitive` - private _advanceIfStringCaseInsensitive(condition:string): number { - const oldPos = this._pos; - const source = this._source; - const len = condition.length; - - if (len < 1 || oldPos + len > this._sourceLength) { - return 0; - } - - for (let i = 0; i < len; i++) { - if (source.charAt(oldPos + i).toLowerCase() !== condition.charAt(i).toLowerCase()) { - return 0; - } - } - - return len; - } - public advanceIfStringCaseInsensitive(condition: string): string { - return this.advance(this._advanceIfStringCaseInsensitive(condition)); - } - public advanceIfStringCaseInsensitive2(condition: string): number { - return this._advance2(this._advanceIfStringCaseInsensitive(condition)); - } - // --- END - - // --- BEGIN `advanceIfString` - private _advanceIfString(condition: string): number { - const oldPos = this._pos; - const source = this._source; - const len = condition.length; - - if (len < 1 || oldPos + len > this._sourceLength) { - return 0; - } - - for (let i = 0; i < len; i++) { - if (source.charCodeAt(oldPos + i) !== condition.charCodeAt(i)) { - return 0; - } - } - - return len; - } - public advanceIfString(condition:string): string { - return this.advance(this._advanceIfString(condition)); - } - public advanceIfString2(condition: string): number { - return this._advance2(this._advanceIfString(condition)); - } - // --- END - - // --- BEGIN `advanceIfString` - private _advanceIfCharCode(charCode:number): number { - if (this._pos < this._sourceLength && this._source.charCodeAt(this._pos) === charCode) { - return 1; - } - - return 0; - } - public advanceIfCharCode(charCode: number): string { - return this.advance(this._advanceIfCharCode(charCode)); - } - public advanceIfCharCode2(charCode: number): number { - return this._advance2(this._advanceIfCharCode(charCode)); - } - // --- END - - // --- BEGIN `advanceIfRegExp` - private _advanceIfRegExp(condition:RegExp): number { - if (this._pos >= this._sourceLength) { - return 0; - } - if (!condition.test(this._source.substr(this._pos))) { - return 0; - } - return RegExp.lastMatch.length; - } - public advanceIfRegExp(condition: RegExp): string { - return this.advance(this._advanceIfRegExp(condition)); - } - public advanceIfRegExp2(condition: RegExp): number { - return this._advance2(this._advanceIfRegExp(condition)); - } - // --- END - - private advanceLoop(condition:RegExp|string, isWhile:boolean, including:boolean):string { - if (this.eos()) { - return ''; - } - const peeker = this.createPeeker(condition); - const oldPos = this._pos; - let n = 0; - let f = null; - if (isWhile) { - f = (n) => { - return n > 0; - }; - } else { - f = (n) => { - return n === 0; - }; - } - while (!this.eos() && f(n = peeker())) { - if (n > 0) { - this.advance(n); - } else { - this.next(); - } - } - if (including && !this.eos()) { - this.advance(n); - } - return this._source.substring(oldPos, this._pos); - } - - public advanceWhile(condition:RegExp|string):string { - return this.advanceLoop(condition, true, false); - } - - public advanceUntil(condition:RegExp|string, including:boolean):string { - return this.advanceLoop(condition, false, including); - } - - // --- BEGIN `advanceUntilString` - private _advanceUntilString(condition: string, including: boolean): number { - if (this.eos() || condition.length === 0) { - return 0; - } - - const oldPos = this._pos; - const index = this._source.indexOf(condition, oldPos); - - if (index === -1) { - // String was not found => advanced to `eos` - return (this._sourceLength - oldPos); - } - - if (including) { - // String was found => advance to include `condition` - return (index + condition.length - oldPos); - } - - // String was found => advance right before `condition` - return (index - oldPos); - } - public advanceUntilString(condition: string, including: boolean): string { - return this.advance(this._advanceUntilString(condition, including)); - } - public advanceUntilString2(condition: string, including: boolean): number { - return this._advance2(this._advanceUntilString(condition, including)); - } - // --- END - - private resetPeekedToken() { - this._tokenStart = -1; - this._tokenEnd = -1; - } - - public setTokenRules(separators:string, whitespace:string):void { - if (this._separators !== separators || this._whitespace !== whitespace) { - this._separators = separators; - this._separatorsArr = CharacterSet.getOrCreate(this._separators); - this._whitespace = whitespace; - this._whitespaceArr = CharacterSet.getOrCreate(this._whitespace); - this.resetPeekedToken(); - } - } - - // --- tokens - - public peekToken():string { - if (this._tokenStart !== -1) { - return this._source.substring(this._tokenStart, this._tokenEnd); - } - - const source = this._source; - const sourceLength = this._sourceLength; - const whitespaceArr = this._whitespaceArr; - const separatorsArr = this._separatorsArr; - - let tokenStart = this._pos; - - // Check EOS - if (tokenStart >= sourceLength) { - throw new Error('Stream is at the end'); - } - - // Skip whitespace - while (whitespaceArr.contains(source.charCodeAt(tokenStart)) && tokenStart < sourceLength) { - tokenStart++; - } - - let tokenEnd = tokenStart; - // If a separator is hit, it is a token - if (separatorsArr.contains(source.charCodeAt(tokenEnd)) && tokenEnd < sourceLength) { - tokenEnd++; - } else { - // Advance until a separator or a whitespace is hit - while (!separatorsArr.contains(source.charCodeAt(tokenEnd)) && !whitespaceArr.contains(source.charCodeAt(tokenEnd)) && tokenEnd < sourceLength) { - tokenEnd++; - } - } - - // Cache peeked token - this._tokenStart = tokenStart; - this._tokenEnd = tokenEnd; - - return source.substring(tokenStart, tokenEnd); - } - - public nextToken():string { - // Check EOS - if (this._pos >= this._sourceLength) { - throw new Error('Stream is at the end'); - } - - // Peek token if necessary - let result:string; - if (this._tokenStart === -1) { - result = this.peekToken(); - } else { - result = this._source.substring(this._tokenStart, this._tokenEnd); - } - - // Advance to tokenEnd - this._pos = this._tokenEnd; - - // Reset peeked token - this._tokenStart = -1; - this._tokenEnd = -1; - - return result; - } - - // -- whitespace - - public peekWhitespace():string { - const source = this._source; - const sourceLength = this._sourceLength; - const whitespaceArr = this._whitespaceArr; - - let peek = this._pos; - while (whitespaceArr.contains(source.charCodeAt(peek)) && peek < sourceLength) { - peek++; - } - return source.substring(this._pos, peek); - } - - // --- BEGIN `skipWhitespace` - private _skipWhitespace(): number { - const source = this._source; - const sourceLength = this._sourceLength; - const whitespaceArr = this._whitespaceArr; - const oldPos = this._pos; - - let peek = this._pos; - while (whitespaceArr.contains(source.charCodeAt(peek)) && peek < sourceLength) { - peek++; - } - - return (peek - oldPos); - } - public skipWhitespace(): string { - return this.advance(this._skipWhitespace()); - } - public skipWhitespace2(): number { - return this._advance2(this._skipWhitespace()); } - // --- END } diff --git a/src/vs/editor/common/modes/modesRegistry.ts b/src/vs/editor/common/modes/modesRegistry.ts index cdb6d6980956017c3775fe4311b1ded30b9ebeaf..bac659c4eb741ba0802eb412eb5eabdf53543bae 100644 --- a/src/vs/editor/common/modes/modesRegistry.ts +++ b/src/vs/editor/common/modes/modesRegistry.ts @@ -9,18 +9,6 @@ import Event, {Emitter} from 'vs/base/common/event'; import {Registry} from 'vs/platform/platform'; import {ILanguageExtensionPoint} from 'vs/editor/common/services/modeService'; -export interface ILegacyLanguageDefinition { - id: string; - extensions: string[]; - filenames?: string[]; - firstLine?: string; - aliases: string[]; - mimetypes: string[]; - moduleId: string; - ctorName: string; - deps?: string[]; -} - // Define extension point ids export var Extensions = { ModesRegistry: 'editor.modesRegistry' @@ -28,35 +16,15 @@ export var Extensions = { export class EditorModesRegistry { - private _compatModes: ILegacyLanguageDefinition[]; private _languages: ILanguageExtensionPoint[]; - private _onDidAddCompatModes: Emitter = new Emitter(); - public onDidAddCompatModes: Event = this._onDidAddCompatModes.event; - private _onDidAddLanguages: Emitter = new Emitter(); public onDidAddLanguages: Event = this._onDidAddLanguages.event; constructor() { - this._compatModes = []; this._languages = []; } - // --- compat modes - - - public registerCompatModes(def:ILegacyLanguageDefinition[]): void { - this._compatModes = this._compatModes.concat(def); - this._onDidAddCompatModes.fire(def); - } - public registerCompatMode(def:ILegacyLanguageDefinition): void { - this._compatModes.push(def); - this._onDidAddCompatModes.fire([def]); - } - public getCompatModes(): ILegacyLanguageDefinition[] { - return this._compatModes.slice(0); - } - // --- languages public registerLanguage(def:ILanguageExtensionPoint): void { diff --git a/src/vs/editor/common/modes/monarch/monarchLexer.ts b/src/vs/editor/common/modes/monarch/monarchLexer.ts index 324c10d4eb24f9fbde35d27b521d3641befa43cd..e467c5aedf3f4dac6c084250847ebcc024f5357f 100644 --- a/src/vs/editor/common/modes/monarch/monarchLexer.ts +++ b/src/vs/editor/common/modes/monarch/monarchLexer.ts @@ -10,7 +10,7 @@ */ import * as modes from 'vs/editor/common/modes'; -import {AbstractState} from 'vs/editor/common/modes/abstractState'; +import {AbstractState, ITokenizationResult} from 'vs/editor/common/modes/abstractState'; import {LineStream} from 'vs/editor/common/modes/lineStream'; import * as monarchCommon from 'vs/editor/common/modes/monarch/monarchCommon'; import {IModeLocator, TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; @@ -94,7 +94,7 @@ export class MonarchLexer extends AbstractState { * TODO: there are many optimizations possible here for the common cases * but for now I concentrated on functionality and correctness. */ - public tokenize(stream: modes.IStream, noConsumeIsOk?: boolean): modes.ITokenizationResult { + public tokenize(stream: LineStream, noConsumeIsOk?: boolean): ITokenizationResult { var stackLen0 = this.stack.length; // these are saved to check progress var groupLen0 = 0; var state: string = this.stack[0]; // the current state @@ -388,7 +388,7 @@ function findBracket(lexer: monarchCommon.ILexer, matched: string) { export function createTokenizationSupport(_modeService:IModeService, modeId:string, lexer: monarchCommon.ILexer): modes.ITokenizationSupport { return new TokenizationSupport(_modeService, modeId, { - getInitialState: (): modes.IState => { + getInitialState: (): AbstractState => { return new MonarchLexer(modeId, _modeService, lexer); }, diff --git a/src/vs/editor/common/modes/nullMode.ts b/src/vs/editor/common/modes/nullMode.ts index 30a18927bb6879863a68468f651c7be98c59295c..5b55b42d5e0126054ff4a035f6a434f8b148c14a 100644 --- a/src/vs/editor/common/modes/nullMode.ts +++ b/src/vs/editor/common/modes/nullMode.ts @@ -4,9 +4,11 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IState, IStream, ITokenizationResult, ILineTokens} from 'vs/editor/common/modes'; +import {IState, ILineTokens} from 'vs/editor/common/modes'; import {ModeTransition} from 'vs/editor/common/core/modeTransition'; import {Token} from 'vs/editor/common/core/token'; +import {ITokenizationResult} from 'vs/editor/common/modes/abstractState'; +import {LineStream} from 'vs/editor/common/modes/lineStream'; export class NullState implements IState { @@ -41,7 +43,7 @@ export class NullState implements IState { return this.modeId; } - public tokenize(stream:IStream):ITokenizationResult { + public tokenize(stream:LineStream):ITokenizationResult { stream.advanceToEOS(); return { type:'' }; } diff --git a/src/vs/editor/common/modes/supports/tokenizationSupport.ts b/src/vs/editor/common/modes/supports/tokenizationSupport.ts index 54b3951d1a862d80f87c2f5c5c41eccf73ffd8fe..786578635a35f8c3b9781661d7de157ac083a90b 100644 --- a/src/vs/editor/common/modes/supports/tokenizationSupport.ts +++ b/src/vs/editor/common/modes/supports/tokenizationSupport.ts @@ -11,6 +11,7 @@ import {NullState, nullTokenize, NULL_MODE_ID} from 'vs/editor/common/modes/null import {Token} from 'vs/editor/common/core/token'; import {ModeTransition} from 'vs/editor/common/core/modeTransition'; import {IModeService} from 'vs/editor/common/services/modeService'; +import {AbstractState, ITokenizationResult} from 'vs/editor/common/modes/abstractState'; export interface ILeavingNestedModeData { /** @@ -26,7 +27,7 @@ export interface ILeavingNestedModeData { /** * The state that will be used for continuing tokenization by the parent mode after the nested mode */ - stateAfterNestedMode: modes.IState; + stateAfterNestedMode: AbstractState; } export interface IModeLocator { @@ -35,11 +36,11 @@ export interface IModeLocator { export interface ITokenizationCustomization { - getInitialState():modes.IState; + getInitialState():AbstractState; - enterNestedMode?: (state:modes.IState) => boolean; + enterNestedMode?: (state:AbstractState) => boolean; - getNestedMode?: (state:modes.IState, locator:IModeLocator) => modes.IMode; + getNestedMode?: (state:AbstractState, locator:IModeLocator) => modes.IMode; /** * Return null if the line does not leave the nested mode @@ -109,7 +110,7 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa if (state.getModeId() !== this._modeId) { return this._nestedTokenize(line, state, deltaOffset, stopAtOffset, [], []); } else { - return this._myTokenize(line, state, deltaOffset, stopAtOffset, [], []); + return this._myTokenize(line, state, deltaOffset, stopAtOffset, [], []); } } @@ -178,9 +179,9 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa * Precondition is: state.getMode() === this * This means we are in the current mode when parsing starts on this line. */ - private _myTokenize(buffer:string, myState:modes.IState, deltaOffset:number, stopAtOffset:number, prependTokens:Token[], prependModeTransitions:ModeTransition[]):modes.ILineTokens { + private _myTokenize(buffer:string, myState:AbstractState, deltaOffset:number, stopAtOffset:number, prependTokens:Token[], prependModeTransitions:ModeTransition[]):modes.ILineTokens { let lineStream = new LineStream(buffer); - let tokenResult:modes.ITokenizationResult, beforeTokenizeStreamPos:number; + let tokenResult:ITokenizationResult, beforeTokenizeStreamPos:number; let previousType:string = null; myState = myState.clone(); @@ -228,7 +229,12 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa return result; } else { // Transition to the nested mode state - myState = nestedModeState; + return { + tokens: prependTokens, + actualStopOffset: lineStream.pos() + deltaOffset, + modeTransitions: prependModeTransitions, + endState: nestedModeState + }; } } } @@ -251,7 +257,7 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa return result; } - private _enterNestedMode(state:modes.IState): boolean { + private _enterNestedMode(state:AbstractState): boolean { if (this.defaults.enterNestedMode) { return false; } @@ -259,7 +265,7 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa } - private _getNestedMode(state:modes.IState): modes.IMode { + private _getNestedMode(state:AbstractState): modes.IMode { if (this.defaults.getNestedMode) { return null; } @@ -291,7 +297,7 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa return this.customization.getNestedMode(state, locator); } - private _getNestedModeInitialState(state:modes.IState): modes.IState { + private _getNestedModeInitialState(state:AbstractState): modes.IState { let nestedMode = this._getNestedMode(state); if (nestedMode) { let tokenizationSupport = modes.TokenizationRegistry.get(nestedMode.getId()); diff --git a/src/vs/editor/common/services/compatWorkerService.ts b/src/vs/editor/common/services/compatWorkerService.ts deleted file mode 100644 index 3daf2531866178480434093c5aea282f2f354609..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/services/compatWorkerService.ts +++ /dev/null @@ -1,48 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 URI from 'vs/base/common/uri'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; -import {IRawText} from 'vs/editor/common/editorCommon'; - -export var ICompatWorkerService = createDecorator('compatWorkerService'); - -export interface IRawModelData { - url: URI; - versionId: number; - value: IRawText; - modeId: string; -} - -export interface ICompatMode { - getId(): string; - compatWorkerService: ICompatWorkerService; -} - -export interface ICompatWorkerService { - _serviceBrand: any; - isInMainThread: boolean; - registerCompatMode(compatMode:ICompatMode): void; - CompatWorker(obj: ICompatMode, methodName: string, target: Function, param: any[]): TPromise; -} - -function findMember(proto: any, target: any): string { - for (let i in proto) { - if (proto[i] === target) { - return i; - } - } - throw new Error('Member not found in prototype'); -} - -export function CompatWorkerAttr(type: Function, target: Function): void { - let methodName = findMember(type.prototype, target); - type.prototype[methodName] = function(...param: any[]) { - let obj = this; - return obj.compatWorkerService.CompatWorker(obj, methodName, target, param); - }; -} diff --git a/src/vs/editor/common/services/compatWorkerServiceMain.ts b/src/vs/editor/common/services/compatWorkerServiceMain.ts deleted file mode 100644 index 97bbbaf0e6532ba75aa74d13de5ce75ce22b6c3f..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/services/compatWorkerServiceMain.ts +++ /dev/null @@ -1,177 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {TPromise} from 'vs/base/common/winjs.base'; -import {IDisposable} from 'vs/base/common/lifecycle'; -import {IModel, EventType, IModelContentChangedEvent} from 'vs/editor/common/editorCommon'; -import {ICompatWorkerService, ICompatMode} from 'vs/editor/common/services/compatWorkerService'; -import {DefaultWorkerFactory} from 'vs/base/worker/defaultWorkerFactory'; -import {WorkerClient} from 'vs/base/common/worker/workerClient'; -import {IModelService} from 'vs/editor/common/services/modelService'; -import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; - -export class MainThreadCompatWorkerService implements ICompatWorkerService { - public _serviceBrand: any; - public isInMainThread = true; - - private _workerFactory: DefaultWorkerFactory; - private _worker: WorkerClient; - private _workerCreatedPromise: TPromise; - private _triggerWorkersCreatedPromise: (value: void) => void; - - private _modelListeners: { [uri: string]: IDisposable }; - - constructor( - @IModelService modelService: IModelService - ) { - this._workerFactory = new DefaultWorkerFactory('compatWorker', true); - this._worker = null; - this._workerCreatedPromise = new TPromise((c, e, p) => { - this._triggerWorkersCreatedPromise = c; - }, () => { - // Not cancelable - }); - - this._modelListeners = Object.create(null); - - const isInterestingModel = (model:IModel) => { - if (model.isTooLargeForHavingARichMode()) { - return false; - } - - let modeId = model.getModeId(); - - let compatModes = ModesRegistry.getCompatModes(); - for (let i = 0; i < compatModes.length; i++) { - if (compatModes[i].id === modeId) { - return true; - } - } - - return false; - }; - - const onModelAdded = (model:IModel) => { - if (!isInterestingModel(model)) { - return; - } - - this._modelListeners[model.uri.toString()] = model.addBulkListener((events) => { - let contentChangedEvents = ( - events - .filter(e => e.getType() === EventType.ModelRawContentChanged) - .map(e => e.getData()) - ); - if (contentChangedEvents.length === 0) { - return; - } - - this._call('$', 'acceptModelEvents', [model.uri, { contentChanged: contentChangedEvents }]); - }); - - this._call('$', 'acceptNewModel', [{ - url: model.uri, - versionId: model.getVersionId(), - value: model.toRawText(), - modeId: model.getMode().getId() - }]); - }; - - const onModelRemoved = (model:IModel) => { - if (this._modelListeners[model.uri.toString()]) { - this._modelListeners[model.uri.toString()].dispose(); - delete this._modelListeners[model.uri.toString()]; - - this._call('$', 'acceptDidDisposeModel', [model.uri]); - } - }; - - modelService.onModelAdded(onModelAdded); - modelService.onModelRemoved(onModelRemoved); - modelService.onModelModeChanged(event => { - onModelRemoved(event.model); - onModelAdded(event.model); - }); - } - - public registerCompatMode(compatMode:ICompatMode): void { - this._call('$', 'instantiateCompatMode', [compatMode.getId()]); - } - - public CompatWorker(obj: ICompatMode, methodName: string, target: Function, param: any[]): TPromise { - return this._call(obj.getId(), methodName, param); - } - - private _ensureWorkers(): void { - if (this._triggerWorkersCreatedPromise) { - // Workers not created yet - - this._createWorker(); - - let complete = this._triggerWorkersCreatedPromise; - this._triggerWorkersCreatedPromise = null; - complete(null); - } - } - - private _afterWorkers(): TPromise { - this._ensureWorkers(); - - let shouldCancelPromise = false; - - return new TPromise((c, e, p) => { - - // hide the initialize promise inside this - // promise so that it won't be canceled by accident - this._workerCreatedPromise.then(() => { - if (!shouldCancelPromise) { - c(null); - } - }, e, p); - - }, () => { - // mark that this promise is canceled - shouldCancelPromise = true; - }); - } - - private _createWorker(isRetry:boolean = false): void { - this._worker = new WorkerClient( - this._workerFactory, - 'vs/editor/common/worker/editorWorkerServer' - ); - this._worker.onModuleLoaded = this._worker.request('initialize', { - modesRegistryData: { - compatModes: ModesRegistry.getCompatModes(), - languages: ModesRegistry.getLanguages() - } - }).then(() => { - ModesRegistry.onDidAddCompatModes((m) => this._call('$', 'acceptCompatModes', [m])); - ModesRegistry.onDidAddLanguages((m) => this._call('$', 'acceptLanguages', [m])); - }, (err) => { - this._worker.dispose(); - this._worker = null; - if (isRetry) { - console.warn('Creating the web worker already failed twice. Giving up!'); - } else { - this._createWorker(true); - } - }); - } - - private _call(rpcId: string, methodName: string, args:any[]): TPromise { - return this._afterWorkers().then(_ => { - if (this._worker === null) { - throw new Error('Cannot fulfill request...'); - } - return this._worker.request('request', { - target: rpcId, - methodName: methodName, - args: args - }); - }); - } -} diff --git a/src/vs/editor/common/services/compatWorkerServiceWorker.ts b/src/vs/editor/common/services/compatWorkerServiceWorker.ts deleted file mode 100644 index f90ef7dc43098b7792a7d88084c7d816cecd0e4d..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/services/compatWorkerServiceWorker.ts +++ /dev/null @@ -1,110 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {TPromise} from 'vs/base/common/winjs.base'; -import {ICompatWorkerService, ICompatMode, IRawModelData} from 'vs/editor/common/services/compatWorkerService'; -import {IResourceService} from 'vs/editor/common/services/resourceService'; -import {ILanguageExtensionPoint, IModeService} from 'vs/editor/common/services/modeService'; -import {ICompatMirrorModelEvents, CompatMirrorModel} from 'vs/editor/common/model/compatMirrorModel'; -import {onUnexpectedError} from 'vs/base/common/errors'; -import URI from 'vs/base/common/uri'; -import {ILegacyLanguageDefinition, ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; - -export class CompatWorkerServiceWorker implements ICompatWorkerService { - public _serviceBrand: any; - public isInMainThread = false; - private _compatModes: {[modeId:string]:ICompatMode;}; - - constructor( - @IResourceService private resourceService: IResourceService, - @IModeService private modeService: IModeService, - modesRegistryData: { - compatModes: ILegacyLanguageDefinition[]; - languages: ILanguageExtensionPoint[]; - } - ) { - ModesRegistry.registerCompatModes(modesRegistryData.compatModes); - ModesRegistry.registerLanguages(modesRegistryData.languages); - this._compatModes = Object.create(null); - } - - registerCompatMode(compatMode:ICompatMode): void { - this._compatModes[compatMode.getId()] = compatMode; - } - - public handleMainRequest(rpcId: string, methodName: string, args: any[]): any { - if (rpcId === '$') { - switch (methodName) { - case 'acceptNewModel': - return this._acceptNewModel(args[0]); - case 'acceptDidDisposeModel': - return this._acceptDidDisposeModel(args[0]); - case 'acceptModelEvents': - return this._acceptModelEvents(args[0], args[1]); - case 'acceptCompatModes': - return this._acceptCompatModes(args[0]); - case 'acceptLanguages': - return this._acceptLanguages(args[0]); - case 'instantiateCompatMode': - return this._instantiateCompatMode(args[0]); - } - } - - let obj = this._compatModes[rpcId]; - return TPromise.as(obj[methodName].apply(obj, args)); - } - - public CompatWorker(obj: ICompatMode, methodName: string, target: Function, param: any[]): TPromise { - return target.apply(obj, param); - } - - private _acceptNewModel(data: IRawModelData): TPromise { - // Create & insert the mirror model eagerly in the resource service - let mirrorModel = new CompatMirrorModel(data.versionId, data.value, null, data.url); - this.resourceService.insert(mirrorModel.uri, mirrorModel); - - // Block worker execution until the mode is instantiated - return this.modeService.getOrCreateMode(data.modeId).then((mode) => { - // Changing mode should trigger a remove & an add, therefore: - - // (1) Remove from resource service - this.resourceService.remove(mirrorModel.uri); - - // (2) Change mode - mirrorModel.setMode(mode.getId()); - - // (3) Insert again to resource service (it will have the new mode) - this.resourceService.insert(mirrorModel.uri, mirrorModel); - }); - } - - private _acceptDidDisposeModel(uri: URI): void { - let model = this.resourceService.get(uri); - this.resourceService.remove(uri); - model.dispose(); - } - - private _acceptModelEvents(uri: URI, events: ICompatMirrorModelEvents): void { - let model = this.resourceService.get(uri); - try { - model.onEvents(events); - } catch (err) { - onUnexpectedError(err); - } - } - - private _acceptCompatModes(modes:ILegacyLanguageDefinition[]): void { - ModesRegistry.registerCompatModes(modes); - } - - private _acceptLanguages(languages:ILanguageExtensionPoint[]): void { - ModesRegistry.registerLanguages(languages); - } - - private _instantiateCompatMode(modeId:string): TPromise { - return this.modeService.getOrCreateMode(modeId).then(_ => void 0); - } -} diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index e823cf81a05984f11387bdd65a0ade8b401fb200..f0923375e30c3f9008da5a485fe072aefaa403ff 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -8,7 +8,7 @@ import {IntervalTimer, ShallowCancelThenPromise, wireCancellationToken} from 'vs import {Disposable, IDisposable, dispose} from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; -import {SimpleWorkerClient} from 'vs/base/common/worker/simpleWorker'; +import {SimpleWorkerClient, logOnceWebWorkerWarning} from 'vs/base/common/worker/simpleWorker'; import {DefaultWorkerFactory} from 'vs/base/worker/defaultWorkerFactory'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {WordHelper} from 'vs/editor/common/model/textModelWithTokensHelpers'; @@ -16,7 +16,6 @@ import {IInplaceReplaceSupportResult, ILink, ISuggestResult, LinkProviderRegistr import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; import {IModelService} from 'vs/editor/common/services/modelService'; import {EditorSimpleWorkerImpl} from 'vs/editor/common/services/editorSimpleWorker'; -import {logOnceWebWorkerWarning} from 'vs/base/common/worker/workerClient'; /** * Stop syncing a model to the worker if it was not needed for 1 min. @@ -256,7 +255,7 @@ export class EditorWorkerClient extends Disposable { constructor(modelService: IModelService, label:string) { super(); this._modelService = modelService; - this._workerFactory = new DefaultWorkerFactory(label, /*do not use iframe*/false); + this._workerFactory = new DefaultWorkerFactory(label); this._worker = null; this._modelManager = null; } diff --git a/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts index 5111fa0c4a7a76f51ef920d0b80b50f89cfb88b7..be437e3dee37d880b8c9cffa34871b8568e6ce41 100644 --- a/src/vs/editor/common/services/languagesRegistry.ts +++ b/src/vs/editor/common/services/languagesRegistry.ts @@ -8,17 +8,11 @@ import {onUnexpectedError} from 'vs/base/common/errors'; import Event, {Emitter} from 'vs/base/common/event'; import * as mime from 'vs/base/common/mime'; import * as strings from 'vs/base/common/strings'; -import {ILegacyLanguageDefinition, ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; +import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; import {ILanguageExtensionPoint} from 'vs/editor/common/services/modeService'; var hasOwnProperty = Object.prototype.hasOwnProperty; -export interface ICompatModeDescriptor { - moduleId: string; - ctorName: string; - deps: string[]; -} - export class LanguagesRegistry { private knownModeIds: { [id: string]: boolean; }; @@ -27,7 +21,6 @@ export class LanguagesRegistry { private id2Name: { [id: string]: string; }; private id2Extensions: { [id: string]: string[]; }; private id2Filenames: { [id: string]: string[]; }; - private compatModes: { [id: string]: ICompatModeDescriptor; }; private lowerName2Id: { [name: string]: string; }; private id2ConfigurationFiles: { [id:string]: string[]; }; @@ -41,44 +34,15 @@ export class LanguagesRegistry { this.id2Name = {}; this.id2Extensions = {}; this.id2Filenames = {}; - this.compatModes = {}; this.lowerName2Id = {}; this.id2ConfigurationFiles = {}; if (useModesRegistry) { - this._registerCompatModes(ModesRegistry.getCompatModes()); - ModesRegistry.onDidAddCompatModes((m) => this._registerCompatModes(m)); - this._registerLanguages(ModesRegistry.getLanguages()); ModesRegistry.onDidAddLanguages((m) => this._registerLanguages(m)); } } - _registerCompatModes(defs:ILegacyLanguageDefinition[]): void { - let addedModes: string[] = []; - for (let i = 0; i < defs.length; i++) { - let def = defs[i]; - - this._registerLanguage({ - id: def.id, - extensions: def.extensions, - filenames: def.filenames, - firstLine: def.firstLine, - aliases: def.aliases, - mimetypes: def.mimetypes - }); - - this.compatModes[def.id] = { - moduleId: def.moduleId, - ctorName: def.ctorName, - deps: def.deps - }; - - addedModes.push(def.id); - } - this._onDidAddModes.fire(addedModes); - } - _registerLanguages(desc:ILanguageExtensionPoint[]): void { let addedModes: string[] = []; for (let i = 0; i < desc.length; i++) { @@ -263,10 +227,6 @@ export class LanguagesRegistry { return this.extractModeIds(mimeTypes.join(',')); } - public getCompatMode(modeId: string): ICompatModeDescriptor { - return this.compatModes[modeId] || null; - } - public getExtensions(languageName: string): string[] { let languageId = this.name2LanguageId[languageName]; if (!languageId) { diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index e9c8d9bddd2dede3e2568d1e70001d3aa4bfb9f8..f47af7d089661540dd812d7bed637488ab270b12 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -46,7 +46,6 @@ export interface IModeService { // --- reading isRegisteredMode(mimetypeOrModeId: string): boolean; - isCompatMode(modeId: string): boolean; getRegisteredModes(): string[]; getRegisteredLanguageNames(): string[]; getExtensions(alias: string): string[]; diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index 96cddb7b9d27b3bd662bbdaf3ae63c88d0fd2dea..519d57477fcd4e4350734a7d042e6f5f75404946 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -11,7 +11,6 @@ import * as paths from 'vs/base/common/paths'; import {TPromise} from 'vs/base/common/winjs.base'; import mime = require('vs/base/common/mime'); import {IFilesConfiguration} from 'vs/platform/files/common/files'; -import {createAsyncDescriptor1} from 'vs/platform/instantiation/common/descriptors'; import {IExtensionService} from 'vs/platform/extensions/common/extensions'; import {IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry} from 'vs/platform/extensions/common/extensionsRegistry'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; @@ -137,7 +136,6 @@ export class ModeServiceImpl implements IModeService { private _instantiationService: IInstantiationService; protected _extensionService: IExtensionService; - private _activationPromises: { [modeId: string]: TPromise; }; private _instantiatedModes: { [modeId: string]: modes.IMode; }; private _registry: LanguagesRegistry; @@ -155,7 +153,6 @@ export class ModeServiceImpl implements IModeService { this._instantiationService = instantiationService; this._extensionService = extensionService; - this._activationPromises = {}; this._instantiatedModes = {}; this._registry = new LanguagesRegistry(); @@ -166,11 +163,6 @@ export class ModeServiceImpl implements IModeService { return this._registry.isRegisteredMode(mimetypeOrModeId); } - public isCompatMode(modeId:string): boolean { - let compatModeData = this._registry.getCompatMode(modeId); - return (compatModeData ? true : false); - } - public getRegisteredModes(): string[] { return this._registry.getRegisteredModes(); } @@ -300,61 +292,18 @@ export class ModeServiceImpl implements IModeService { }); } - private _getOrCreateMode(modeId: string): TPromise { - if (this._instantiatedModes.hasOwnProperty(modeId)) { - return TPromise.as(this._instantiatedModes[modeId]); - } - - if (this._activationPromises.hasOwnProperty(modeId)) { - return this._activationPromises[modeId]; - } - var c, e; - var promise = new TPromise((cc,ee,pp) => { c = cc; e = ee; }); - this._activationPromises[modeId] = promise; - - this._createMode(modeId).then((mode) => { - this._instantiatedModes[modeId] = mode; - delete this._activationPromises[modeId]; + private _getOrCreateMode(modeId: string): modes.IMode { + if (!this._instantiatedModes.hasOwnProperty(modeId)) { + this._instantiatedModes[modeId] = this._instantiationService.createInstance(FrankensteinMode, { + id: modeId + }); - this._onDidCreateMode.fire(mode); + this._onDidCreateMode.fire(this._instantiatedModes[modeId]); this._extensionService.activateByEvent(`onLanguage:${modeId}`).done(null, onUnexpectedError); - - return this._instantiatedModes[modeId]; - }).then(c, e); - - return promise; - } - - private _createMode(modeId:string): TPromise { - let modeDescriptor = this._createModeDescriptor(modeId); - - let compatModeData = this._registry.getCompatMode(modeId); - if (compatModeData) { - // This is a compatibility mode - - let resolvedDeps: TPromise = null; - if (Array.isArray(compatModeData.deps)) { - resolvedDeps = TPromise.join(compatModeData.deps.map(dep => this.getOrCreateMode(dep))); - } else { - resolvedDeps = TPromise.as(null); - } - - return resolvedDeps.then(_ => { - let compatModeAsyncDescriptor = createAsyncDescriptor1(compatModeData.moduleId, compatModeData.ctorName); - return this._instantiationService.createInstance(compatModeAsyncDescriptor, modeDescriptor); - }); } - - return TPromise.as(this._instantiationService.createInstance(FrankensteinMode, modeDescriptor)); + return this._instantiatedModes[modeId]; } - - private _createModeDescriptor(modeId:string): modes.IModeDescriptor { - return { - id: modeId - }; - } - } export class TokenizationState2Adapter implements modes.IState { diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 33ce3b5c61e2fdf9d556e95c3b66e071354e550e..9907d9204252e0878a982338b0711deeef058dad 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -26,13 +26,6 @@ import {DEFAULT_INDENTATION, DEFAULT_TRIM_AUTO_WHITESPACE} from 'vs/editor/commo import {IMessageService} from 'vs/platform/message/common/message'; import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; -export interface IRawModelData { - url: URI; - versionId: number; - value: editorCommon.IRawText; - modeId: string; -} - function MODEL_ID(resource: URI): string { return resource.toString(); } diff --git a/src/vs/editor/common/services/resourceService.ts b/src/vs/editor/common/services/resourceService.ts deleted file mode 100644 index 305b960858d2e2553086fcb35b3186caa259f2b8..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/services/resourceService.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 URI from 'vs/base/common/uri'; -import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; -import {ITokenizedModel} from 'vs/editor/common/editorCommon'; - -export interface ICompatMirrorModel extends ITokenizedModel { -} - -// Resource Service - -export let IResourceService = createDecorator('resourceService'); - -export interface IResourceService { - _serviceBrand: any; - - insert(url: URI, element: ICompatMirrorModel): void; - get(url: URI): ICompatMirrorModel; - remove(url: URI): void; -} diff --git a/src/vs/editor/common/services/resourceServiceImpl.ts b/src/vs/editor/common/services/resourceServiceImpl.ts deleted file mode 100644 index cd924f4ed3cab8ed8e85f86748d4f6b24fc77396..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/services/resourceServiceImpl.ts +++ /dev/null @@ -1,86 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 URI from 'vs/base/common/uri'; -import {IResourceService, ICompatMirrorModel} from 'vs/editor/common/services/resourceService'; - -class CompatMirrorModelMap { - - private _data: {[key:string]:ICompatMirrorModel}; - - constructor() { - this._data = {}; - } - - public set(key:string, data:ICompatMirrorModel): void { - this._data[key] = data; - } - - public get(key:string): ICompatMirrorModel { - return this._data[key] || null; - } - - public contains(key:string): boolean { - return !!this._data[key]; - } - - public remove(key:string): void { - delete this._data[key]; - } -} - -export class ResourceService implements IResourceService { - public _serviceBrand: any; - - private _map:CompatMirrorModelMap; - - constructor() { - this._map = new CompatMirrorModelMap(); - } - - private static _anonymousModelId(input:string): string { - let r = ''; - for (let i = 0; i < input.length; i++) { - let ch = input[i]; - if (ch >= '0' && ch <= '9') { - r += '0'; - continue; - } - if (ch >= 'a' && ch <= 'z') { - r += 'a'; - continue; - } - if (ch >= 'A' && ch <= 'Z') { - r += 'A'; - continue; - } - r += ch; - } - return r; - } - - public insert(uri:URI, element:ICompatMirrorModel): void { - let key = uri.toString(); - - if (this._map.contains(key)) { - // There already exists a model with this id => this is a programmer error - throw new Error('ResourceService: Cannot add model ' + ResourceService._anonymousModelId(key) + ' because it already exists!'); - } - this._map.set(key, element); - } - - public get(uri:URI):ICompatMirrorModel { - let key = uri.toString(); - - return this._map.get(key); - } - - public remove(uri:URI):void { - let key = uri.toString(); - - this._map.remove(key); - } -} diff --git a/src/vs/editor/common/worker/editorWorkerServer.ts b/src/vs/editor/common/worker/editorWorkerServer.ts deleted file mode 100644 index b28adbf0b044af4ebff5905fa7b793afc0626b69..0000000000000000000000000000000000000000 --- a/src/vs/editor/common/worker/editorWorkerServer.ts +++ /dev/null @@ -1,109 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -// include these in the editor bundle because they are widely used by many languages -import 'vs/editor/common/languages.common'; -import Severity from 'vs/base/common/severity'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {WorkerServer} from 'vs/base/common/worker/workerServer'; -import {EventService} from 'vs/platform/event/common/eventService'; -import {IEventService} from 'vs/platform/event/common/event'; -import {AbstractExtensionService, ActivatedExtension} from 'vs/platform/extensions/common/abstractExtensionService'; -import {IExtensionDescription, IExtensionService} from 'vs/platform/extensions/common/extensions'; -import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; -import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService'; -import {ModeServiceImpl} from 'vs/editor/common/services/modeServiceImpl'; -import {IModeService, ILanguageExtensionPoint} from 'vs/editor/common/services/modeService'; -import {ResourceService} from 'vs/editor/common/services/resourceServiceImpl'; -import {IResourceService} from 'vs/editor/common/services/resourceService'; -import {CompatWorkerServiceWorker} from 'vs/editor/common/services/compatWorkerServiceWorker'; -import {ICompatWorkerService} from 'vs/editor/common/services/compatWorkerService'; -import {ILegacyLanguageDefinition} from 'vs/editor/common/modes/modesRegistry'; - -export interface IInitData { - modesRegistryData?: { - compatModes: ILegacyLanguageDefinition[]; - languages: ILanguageExtensionPoint[]; - }; -} - -export interface ICallback { - (something:any):void; -} - -class WorkerExtensionService extends AbstractExtensionService { - - constructor() { - super(true); - } - - protected _showMessage(severity:Severity, msg:string): void { - switch (severity) { - case Severity.Error: - console.error(msg); - break; - case Severity.Warning: - console.warn(msg); - break; - case Severity.Info: - console.info(msg); - break; - default: - console.log(msg); - } - } - - protected _createFailedExtension(): ActivatedExtension { - throw new Error('unexpected'); - } - - protected _actualActivateExtension(extensionDescription: IExtensionDescription): TPromise { - throw new Error('unexpected'); - } -} - -export class EditorWorkerServer { - - private compatWorkerService:CompatWorkerServiceWorker; - - constructor() { - } - - public initialize(mainThread:WorkerServer, complete:ICallback, error:ICallback, progress:ICallback, initData:IInitData):void { - - const services = new ServiceCollection(); - const instantiationService = new InstantiationService(services); - - const extensionService = new WorkerExtensionService(); - services.set(IExtensionService, extensionService); - - const resourceService = new ResourceService(); - services.set(IResourceService, resourceService); - - services.set(IEventService, new EventService()); - - const modeService = new ModeServiceImpl(instantiationService, extensionService); - services.set(IModeService, modeService); - - this.compatWorkerService = new CompatWorkerServiceWorker(resourceService, modeService, initData.modesRegistryData); - services.set(ICompatWorkerService, this.compatWorkerService); - - complete(undefined); - } - - public request(mainThread:WorkerServer, complete:ICallback, error:ICallback, progress:ICallback, data:any):void { - try { - TPromise.as( - this.compatWorkerService.handleMainRequest(data.target, data.methodName, data.args) - ).then(complete, error); - } catch (err) { - error(err); - } - } -} - -export var value = new EditorWorkerServer(); diff --git a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts index 8b131f667fb5b431cb71b18d946dd4d25dc3fdfc..1e2d9321168b3c5962b5d90c040f785715acec4c 100644 --- a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts @@ -16,7 +16,7 @@ import {ActionItem, Separator} from 'vs/base/browser/ui/actionbar/actionbar'; import {IContextMenuService, IContextViewService} from 'vs/platform/contextview/browser/contextView'; import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; import {IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; -import {IMenuService, IMenu, MenuId} from 'vs/platform/actions/common/actions'; +import {IMenuService, MenuId} from 'vs/platform/actions/common/actions'; import {ICommonCodeEditor, IEditorContribution, MouseTargetType, EditorContextKeys, IScrollEvent} from 'vs/editor/common/editorCommon'; import {editorAction, ServicesAccessor, EditorAction} from 'vs/editor/common/editorCommonExtensions'; import {ICodeEditor, IEditorMouseEvent} from 'vs/editor/browser/editorBrowser'; @@ -39,7 +39,6 @@ export class ContextMenuController implements IEditorContribution { private _toDispose: IDisposable[] = []; private _contextMenuIsBeingShownCount: number = 0; private _editor: ICodeEditor; - private _contextMenu: IMenu; constructor( editor: ICodeEditor, @@ -51,9 +50,6 @@ export class ContextMenuController implements IEditorContribution { ) { this._editor = editor; - this._contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); - this._toDispose.push(this._contextMenu); - this._toDispose.push(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e))); this._toDispose.push(this._editor.onDidScrollChange((e: IScrollEvent) => { if (this._contextMenuIsBeingShownCount > 0) { @@ -129,7 +125,10 @@ export class ContextMenuController implements IEditorContribution { private _getMenuActions(): IAction[] { const result: IAction[] = []; - const groups = this._contextMenu.getActions(); + + let contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); + const groups = contextMenu.getActions(); + contextMenu.dispose(); for (let group of groups) { const [, actions] = group; diff --git a/src/vs/editor/test/common/mocks/mockMode.ts b/src/vs/editor/test/common/mocks/mockMode.ts index 2e38ea910befee0d6332e9751d885222ebd80fd0..eb4457630ab7b8acbf6c4962d098f54cf272c13f 100644 --- a/src/vs/editor/test/common/mocks/mockMode.ts +++ b/src/vs/editor/test/common/mocks/mockMode.ts @@ -4,12 +4,13 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IMode, IState, IStream, ITokenizationResult, ITokenizationSupport, TokenizationRegistry} from 'vs/editor/common/modes'; -import {AbstractState} from 'vs/editor/common/modes/abstractState'; +import {IMode, IState, TokenizationRegistry} from 'vs/editor/common/modes'; +import {AbstractState, ITokenizationResult} from 'vs/editor/common/modes/abstractState'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; +import {LineStream} from 'vs/editor/common/modes/lineStream'; let instanceCount = 0; -export function generateMockModeId(): string { +function generateMockModeId(): string { return 'mockMode' + (++instanceCount); } @@ -45,7 +46,7 @@ export class StateForMockTokenizingMode extends AbstractState { return true; } - public tokenize(stream:IStream):ITokenizationResult { + public tokenize(stream:LineStream):ITokenizationResult { stream.advanceToEOS(); return { type: this._tokenType }; } diff --git a/src/vs/editor/test/common/mocks/mockModeService.ts b/src/vs/editor/test/common/mocks/mockModeService.ts deleted file mode 100644 index cd95c88a66527e3b2582e9cdcec824b341c3789b..0000000000000000000000000000000000000000 --- a/src/vs/editor/test/common/mocks/mockModeService.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 Event from 'vs/base/common/event'; -import {IDisposable} from 'vs/base/common/lifecycle'; -import {TPromise} from 'vs/base/common/winjs.base'; -import * as modes from 'vs/editor/common/modes'; -import {IModeService, IModeLookupResult} from 'vs/editor/common/services/modeService'; - -export class MockModeService implements IModeService { - _serviceBrand: any; - - onDidAddModes: Event = undefined; - onDidCreateMode: Event = undefined; - - // --- reading - isRegisteredMode(mimetypeOrModeId: string): boolean { - throw new Error('Not implemented'); - } - isCompatMode(modeId: string): boolean { - throw new Error('Not implemented'); - } - getRegisteredModes(): string[] { - throw new Error('Not implemented'); - } - getRegisteredLanguageNames(): string[] { - throw new Error('Not implemented'); - } - getExtensions(alias: string): string[] { - throw new Error('Not implemented'); - } - getFilenames(alias: string): string[] { - throw new Error('Not implemented'); - } - getMimeForMode(modeId: string): string { - throw new Error('Not implemented'); - } - getLanguageName(modeId:string): string { - throw new Error('Not implemented'); - } - getModeIdForLanguageName(alias:string): string { - throw new Error('Not implemented'); - } - getModeIdByFilenameOrFirstLine(filename: string, firstLine?: string): string { - throw new Error('Not implemented'); - } - getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string { - throw new Error('Not implemented'); - } - getConfigurationFiles(modeId: string): string[] { - throw new Error('Not implemented'); - } - - // --- instantiation - lookup(commaSeparatedMimetypesOrCommaSeparatedIds: string): IModeLookupResult[] { - throw new Error('Not implemented'); - } - getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): modes.IMode { - throw new Error('Not implemented'); - } - getOrCreateMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): TPromise { - throw new Error('Not implemented'); - } - getOrCreateModeByLanguageName(languageName: string): TPromise { - throw new Error('Not implemented'); - } - getOrCreateModeByFilenameOrFirstLine(filename: string, firstLine?:string): TPromise { - throw new Error('Not implemented'); - } - - registerTokenizationSupport(modeId: string, callback: (mode: modes.IMode) => modes.ITokenizationSupport): IDisposable { - throw new Error('Not implemented'); - } - registerTokenizationSupport2(modeId: string, support: modes.TokensProvider): IDisposable { - throw new Error('Not implemented'); - } -} diff --git a/src/vs/editor/test/common/model/compatMirrorModel.test.ts b/src/vs/editor/test/common/model/compatMirrorModel.test.ts deleted file mode 100644 index dc336c86862aefea835936e7313879bab8213f08..0000000000000000000000000000000000000000 --- a/src/vs/editor/test/common/model/compatMirrorModel.test.ts +++ /dev/null @@ -1,261 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import {ICompatMirrorModelEvents, CompatMirrorModel} from 'vs/editor/common/model/compatMirrorModel'; -import {Position} from 'vs/editor/common/core/position'; -import {MirrorModel as SimpleMirrorModel} from 'vs/editor/common/services/editorSimpleWorker'; -import {DEFAULT_WORD_REGEXP} from 'vs/editor/common/model/wordHelper'; -import {TextModel} from 'vs/editor/common/model/textModel'; - -function createTestMirrorModelFromString(value:string): CompatMirrorModel { - return new CompatMirrorModel(0, TextModel.toRawText(value, TextModel.DEFAULT_CREATION_OPTIONS), null); -} - -function contentChangedFlushEvent(detail: editorCommon.IRawText): editorCommon.IModelContentChangedFlushEvent { - return { - changeType: editorCommon.EventType.ModelRawContentChangedFlush, - isRedoing: false, - isUndoing: false, - versionId: 0, - detail: detail - }; -} - -function contentChangedLinesDeletedEvent(fromLineNumber: number, toLineNumber: number): editorCommon.IModelContentChangedLinesDeletedEvent { - return { - changeType: editorCommon.EventType.ModelRawContentChangedLinesDeleted, - isRedoing: false, - isUndoing: false, - versionId: 0, - fromLineNumber: fromLineNumber, - toLineNumber: toLineNumber - }; -} - -function contentChangedLinesInsertedEvent(fromLineNumber: number, toLineNumber: number, detail: string): editorCommon.IModelContentChangedLinesInsertedEvent { - return { - changeType: editorCommon.EventType.ModelRawContentChangedLinesInserted, - isRedoing: false, - isUndoing: false, - versionId: 0, - fromLineNumber: fromLineNumber, - toLineNumber: toLineNumber, - detail: detail - }; -} - -function contentChangedLineChanged(lineNumber: number, detail: string): editorCommon.IModelContentChangedLineChangedEvent { - return { - changeType: editorCommon.EventType.ModelRawContentChangedLineChanged, - isRedoing: false, - isUndoing: false, - versionId: 0, - lineNumber: lineNumber, - detail: detail - }; -} - -function mirrorModelEvents(contentChanged:editorCommon.IModelContentChangedEvent[]): ICompatMirrorModelEvents { - return { - contentChanged: contentChanged - }; -} - -suite('Editor Model - MirrorModel', () => { - - var mirrorModel:CompatMirrorModel; - - setup(() => { - mirrorModel = createTestMirrorModelFromString('line1\nline2\nline3\nline4'); - }); - - teardown(() => { - mirrorModel.dispose(); - mirrorModel = null; - }); - - test('get line start ', () => { - assert.equal(mirrorModel.getOffsetAt(new Position(1, 1)), 0); - assert.equal(mirrorModel.getOffsetAt(new Position(2, 1)), 6); - assert.equal(mirrorModel.getOffsetAt(new Position(3, 1)), 12); - assert.equal(mirrorModel.getOffsetAt(new Position(4, 1)), 18); - assert.equal(mirrorModel.getOffsetAt(new Position(1000, 1)), mirrorModel.getOffsetAt(new Position(mirrorModel.getLineCount(), mirrorModel.getLineMaxColumn(mirrorModel.getLineCount())))); - }); - - test('get line start /flush event/', () => { - assert.equal(mirrorModel.getOffsetAt(new Position(2, 1)), 6); - assert.equal(mirrorModel.getOffsetAt(new Position(3, 1)), 12); - - mirrorModel.onEvents(mirrorModelEvents([contentChangedFlushEvent({ - length: -1, - lines: [ - 'foo', - 'bar' - ], - BOM: '', - EOL: '\n', - options: { - tabSize: 4, - insertSpaces: true, - trimAutoWhitespace: true, - defaultEOL: editorCommon.DefaultEndOfLine.LF - } - })])); - - assert.equal(mirrorModel.getOffsetAt(new Position(1, 1)), 0); - assert.equal(mirrorModel.getOffsetAt(new Position(2, 1)), 4); - }); - - test('get offset', () => { - assert.equal(mirrorModel.getOffsetAt({lineNumber: 1, column: 1}), 0); - assert.equal(mirrorModel.getOffsetAt({lineNumber: 1, column: 3}), 2); - assert.equal(mirrorModel.getOffsetAt({lineNumber: 2, column: 1}), 6); - assert.equal(mirrorModel.getOffsetAt({lineNumber: 4, column: 6}), 23); - assert.equal(mirrorModel.getOffsetAt({lineNumber: 4, column: 7}), 23); - }); - - test('get position from offset', () => { - assert.deepEqual(mirrorModel.getPositionAt(0), {lineNumber: 1, column: 1}); - assert.deepEqual(mirrorModel.getPositionAt(2), {lineNumber: 1, column: 3}); - assert.deepEqual(mirrorModel.getPositionAt(6), {lineNumber: 2, column: 1}); - assert.deepEqual(mirrorModel.getPositionAt(23), {lineNumber: 4, column: 6}); - assert.deepEqual(mirrorModel.getPositionAt(24), {lineNumber: 4, column: 6}); - }); - - test('get (all/unique) words', () => { - let model = new SimpleMirrorModel(null, [ 'foo bar foo bar' ], '\n', 1); - let uniqueWords = model.getAllUniqueWords(DEFAULT_WORD_REGEXP); - assert.equal(uniqueWords.length, 2); - assert.equal(uniqueWords[0], 'foo'); - assert.equal(uniqueWords[1], 'bar'); - - model = new SimpleMirrorModel(null, [ 'foo bar', 'foo', 'bar' ], '\n', 1); - uniqueWords = model.getAllUniqueWords(DEFAULT_WORD_REGEXP); - assert.equal(uniqueWords.length, 2); - assert.equal(uniqueWords[0], 'foo'); - assert.equal(uniqueWords[1], 'bar'); - - model = new SimpleMirrorModel(null, [ 'toString', 'hasOwnProperty', 'foo' ], '\n', 1); - uniqueWords = model.getAllUniqueWords(DEFAULT_WORD_REGEXP); - assert.equal(uniqueWords.length, 3); - assert.equal(uniqueWords[0], 'toString'); - assert.equal(uniqueWords[1], 'hasOwnProperty'); - assert.equal(uniqueWords[2], 'foo'); - }); - - test('word at/until pos', () => { - var pos = { lineNumber: 1, column: 3 }; - assert.equal(mirrorModel.getWordAtPosition(pos).word, 'line1'); - - var model = createTestMirrorModelFromString('foo bar 1234 :";\''); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 1}).word, 'foo'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 2}).word, 'foo'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 3}).word, 'foo'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 4}).word, 'foo'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 5}).word, 'bar'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 6}).word, 'bar'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 7}).word, 'bar'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 8}).word, 'bar'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 9}).word, '1234'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 10}).word, '1234'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 11}).word, '1234'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 12}).word, '1234'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 13}).word, '1234'); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 14}), null); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 15}), null); - assert.equal(model.getWordAtPosition({lineNumber: 1, column: 16}), null); - - assert.equal(mirrorModel.getWordUntilPosition(pos).word, 'li'); - - }); -}); - -suite('Editor Model - MirrorModel Eventing', () => { - - var mirrorModel:CompatMirrorModel; - - setup(() => { - mirrorModel = createTestMirrorModelFromString('line one\nline two\nline three\nline four'); - }); - - teardown(() => { - mirrorModel.dispose(); - mirrorModel = null; - }); - - test('delete single line', () => { - assert.equal(mirrorModel.getLineContent(3), 'line three'); - - mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesDeletedEvent(3, 3)])); - - assert.equal(mirrorModel.getLineContent(3), 'line four'); - }); - - test('delete multiple lines', () => { - mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesDeletedEvent(1, 2)])); - - assert.equal(mirrorModel.getLineContent(1), 'line three'); - assert.equal(mirrorModel.getLineContent(2), 'line four'); - }); - - test('delete all lines', () => { - mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesDeletedEvent(1, 4)])); - }); - - test('add single lines', () => { - assert.equal(mirrorModel.getLineContent(1), 'line one'); - - mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesInsertedEvent(1, 1, 'foo bar\nbar foo')])); - - assert.equal(mirrorModel.getLineContent(1), 'foo bar'); - assert.equal(mirrorModel.getLineContent(2), 'line one'); - }); - - - test('add multiple lines', () => { - assert.equal(mirrorModel.getLineContent(1), 'line one'); - - mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesInsertedEvent(1, 2, 'foo bar\nbar foo')])); - - assert.equal(mirrorModel.getLineContent(1), 'foo bar'); - assert.equal(mirrorModel.getLineContent(2), 'bar foo'); - assert.equal(mirrorModel.getLineContent(3), 'line one'); - }); - - test('change line', () => { - assert.equal(mirrorModel.getLineContent(1), 'line one'); - - mirrorModel.onEvents(mirrorModelEvents([contentChangedLineChanged(1, 'foobar')])); - - assert.equal(mirrorModel.getLineContent(1), 'foobar'); - }); - - test('flush model', () => { - assert.equal(mirrorModel.getLineContent(1), 'line one'); - assert.equal(mirrorModel.getLineContent(2), 'line two'); - - mirrorModel.onEvents(mirrorModelEvents([contentChangedFlushEvent({ - length: -1, - lines: [ - 'foo', - 'bar' - ], - BOM: '', - EOL: '\n', - options: { - tabSize: 4, - insertSpaces: true, - trimAutoWhitespace: true, - defaultEOL: editorCommon.DefaultEndOfLine.LF - } - })])); - - assert.equal(mirrorModel.getLineContent(1), 'foo'); - assert.equal(mirrorModel.getLineContent(2), 'bar'); - }); - -}); diff --git a/src/vs/editor/test/common/model/editableTextModelTestUtils.ts b/src/vs/editor/test/common/model/editableTextModelTestUtils.ts index 8aeef0f5ba30c1c3e79c0f59467cdec19efcc34a..afde76f3171d8e05500f125646df496f20e3b5f1 100644 --- a/src/vs/editor/test/common/model/editableTextModelTestUtils.ts +++ b/src/vs/editor/test/common/model/editableTextModelTestUtils.ts @@ -7,7 +7,6 @@ import * as assert from 'assert'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {EditableTextModel} from 'vs/editor/common/model/editableTextModel'; -import {ICompatMirrorModelEvents, CompatMirrorModel} from 'vs/editor/common/model/compatMirrorModel'; import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2'; import {TextModel} from 'vs/editor/common/model/textModel'; import {Position} from 'vs/editor/common/core/position'; @@ -90,25 +89,9 @@ export function assertSyncedModels(text:string, callback:(model:EditableTextMode assertLineMapping(model, 'model'); } - var mirrorModel1 = new CompatMirrorModel(model.getVersionId(), model.toRawText(), null); - assertLineMapping(mirrorModel1, 'mirrorModel1'); - var mirrorModel1PrevVersionId = model.getVersionId(); - var mirrorModel2 = new MirrorModel2(null, model.toRawText().lines, model.toRawText().EOL, model.getVersionId()); var mirrorModel2PrevVersionId = model.getVersionId(); - model.onDidChangeRawContent((e:editorCommon.IModelContentChangedEvent) => { - let versionId = e.versionId; - if (versionId < mirrorModel1PrevVersionId) { - console.warn('Model version id did not advance between edits (1)'); - } - mirrorModel1PrevVersionId = versionId; - let mirrorModelEvents:ICompatMirrorModelEvents = { - contentChanged: [e] - }; - mirrorModel1.onEvents(mirrorModelEvents); - }); - model.onDidChangeContent((e:editorCommon.IModelContentChangedEvent2) => { let versionId = e.versionId; if (versionId < mirrorModel2PrevVersionId) { @@ -120,17 +103,13 @@ export function assertSyncedModels(text:string, callback:(model:EditableTextMode var assertMirrorModels = () => { assertLineMapping(model, 'model'); - assertLineMapping(mirrorModel1, 'mirrorModel1'); model._assertLineNumbersOK(); assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK'); assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK'); - assert.equal(mirrorModel1.getValue(), model.getValue(), 'mirror model 1 text OK'); - assert.equal(mirrorModel1.getVersionId(), model.getVersionId(), 'mirror model 1 version OK'); }; callback(model, assertMirrorModels); model.dispose(); - mirrorModel1.dispose(); mirrorModel2.dispose(); } diff --git a/src/vs/editor/test/common/model/model.modes.test.ts b/src/vs/editor/test/common/model/model.modes.test.ts index 0853fe937fb270b5edd7f4ebe2a7c744b98894bc..c6fc70968d77b10dcaa491cf98ad174b06c94b26 100644 --- a/src/vs/editor/test/common/model/model.modes.test.ts +++ b/src/vs/editor/test/common/model/model.modes.test.ts @@ -9,9 +9,10 @@ import {EditOperation} from 'vs/editor/common/core/editOperation'; import {Position} from 'vs/editor/common/core/position'; import {Range} from 'vs/editor/common/core/range'; import {Model} from 'vs/editor/common/model/model'; -import {AbstractState} from 'vs/editor/common/modes/abstractState'; +import {AbstractState, ITokenizationResult} from 'vs/editor/common/modes/abstractState'; import * as modes from 'vs/editor/common/modes'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; +import {LineStream} from 'vs/editor/common/modes/lineStream'; // --------- utils @@ -38,8 +39,10 @@ suite('Editor Model - Model Modes 1', () => { public equals(other: modes.IState): boolean { return this === other; } - public tokenize(stream:modes.IStream): modes.ITokenizationResult { - calledState.calledFor.push(stream.next()); + public tokenize(stream:LineStream): ITokenizationResult { + let chr = stream.peek(); + stream.advance(1); + calledState.calledFor.push(chr); stream.advanceToEOS(); return { type: '' }; } @@ -188,11 +191,8 @@ suite('Editor Model - Model Modes 2', () => { return (other instanceof ModelState2) && (this.prevLineContent === (other).prevLineContent); } - public tokenize(stream:modes.IStream):modes.ITokenizationResult { - var line= ''; - while (!stream.eos()) { - line+= stream.next(); - } + public tokenize(stream:LineStream):ITokenizationResult { + var line= stream.advanceToEOS(); this.prevLineContent= line; return { type: '' }; } @@ -309,7 +309,7 @@ suite('Editor Model - Token Iterator', () => { class NState extends AbstractState { private n:number; - private allResults:modes.ITokenizationResult[]; + private allResults:ITokenizationResult[]; constructor(modeId:string, n:number) { super(modeId); @@ -325,10 +325,12 @@ suite('Editor Model - Token Iterator', () => { return true; } - public tokenize(stream:modes.IStream):modes.ITokenizationResult { + public tokenize(stream:LineStream):ITokenizationResult { var ndash = this.n, value = ''; while(!stream.eos() && ndash > 0) { - value += stream.next(); + let chr = stream.peek(); + stream.advance(1); + value += chr; ndash--; } return { type: 'n-' + (this.n - ndash) + '-' + value }; diff --git a/src/vs/editor/test/common/modes/lineStream.test.ts b/src/vs/editor/test/common/modes/lineStream.test.ts index 6982b8ae1761a57bcd14de7b224d18b3cd4a0263..19490b888abd9a2182d94835a039cf4da4ad8079 100644 --- a/src/vs/editor/test/common/modes/lineStream.test.ts +++ b/src/vs/editor/test/common/modes/lineStream.test.ts @@ -8,361 +8,34 @@ import {LineStream} from 'vs/editor/common/modes/lineStream'; suite('Editor Modes - LineStream', () => { - test('advanceIf - regex', () => { - var lineStream = new LineStream('...xxx...x.'); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfRegExp(/^x/), 'x'); - assert.equal(lineStream.advanceIfRegExp(/^x/), 'x'); - assert.equal(lineStream.advanceIfRegExp(/^x/), 'x'); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfRegExp(/^x/), 'x'); - assert.equal(lineStream.advanceIfRegExp(/^x/), ''); - lineStream.next(); - assert.ok(lineStream.eos()); - }); - - test('advanceWhile - regex', () => { - var lineStream = new LineStream('...xxx...x.'); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile(/^x/), 'xxx'); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile(/^x/), 'x'); - assert.equal(lineStream.advanceWhile(/^x/), ''); - lineStream.next(); - assert.ok(lineStream.eos()); - }); - - test('advanceUntil - regex', () => { - var lineStream = new LineStream('...x..xx..x'); - assert.equal(lineStream.advanceUntil(/^x/, false), '...'); - assert.equal(lineStream.advanceUntil(/^x/, false), ''); - lineStream.next(); - assert.equal(lineStream.advanceUntil(/^x/, false), '..'); - assert.equal(lineStream.advanceUntil(/^x/, false), ''); - lineStream.next(); - assert.equal(lineStream.advanceUntil(/^x/, false), ''); - lineStream.next(); - assert.equal(lineStream.advanceUntil(/^x/, false), '..'); - assert.equal(lineStream.advanceUntil(/^x/, false), ''); - lineStream.next(); - assert.ok(lineStream.eos()); - }); - - test('advanceUntil - regex (including)', () => { - var lineStream = new LineStream('...x..xx..x'); - assert.equal(lineStream.advanceUntil(/^x/, true), '...x'); - assert.equal(lineStream.advanceUntil(/^x/, true), '..x'); - assert.equal(lineStream.advanceUntil(/^x/, true), 'x'); - assert.equal(lineStream.advanceUntil(/^x/, true), '..x'); - assert.ok(lineStream.eos()); - }); - - test('advanceIf - string', () => { - var lineStream = new LineStream('...abcabcabc...abc.'); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfString('abc'), 'abc'); - assert.equal(lineStream.advanceIfString('abc'), 'abc'); - assert.equal(lineStream.advanceIfString('abc'), 'abc'); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceIfString('abc'), 'abc'); - assert.equal(lineStream.advanceIfString('abc'), ''); - lineStream.next(); - assert.ok(lineStream.eos()); - }); - - test('advanceWhile - string', () => { - var lineStream = new LineStream('...abcabcabc...abc.'); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile('abc'), 'abcabcabc'); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.equal(lineStream.advanceWhile('abc'), 'abc'); - assert.equal(lineStream.advanceWhile('abc'), ''); - lineStream.next(); - assert.ok(lineStream.eos()); - }); - - test('advanceUntil - string', () => { - var lineStream = new LineStream('...abc..ab..abc..bc'); - assert.equal(lineStream.advanceUntil('abc', false), '...'); - assert.equal(lineStream.advanceUntil('abc', false), ''); - lineStream.next(); - assert.equal(lineStream.advanceUntil('abc', false), 'bc..ab..'); - assert.equal(lineStream.advanceUntil('abc', false), ''); - lineStream.next(); - assert.equal(lineStream.advanceUntil('abc', false), 'bc..bc'); - assert.ok(lineStream.eos()); - }); - - test('advanceUntil - string (including)', () => { - var lineStream = new LineStream('...abc..ab..abc..bc'); - assert.equal(lineStream.advanceUntil('abc', true), '...abc'); - assert.equal(lineStream.advanceUntil('abc', true), '..ab..abc'); - assert.equal(lineStream.advanceUntil('abc', true), '..bc'); - assert.ok(lineStream.eos()); - }); - - test('skipWhitespace', () => { - var lineStream = new LineStream('\ta bc d \t e '); - assert.equal(lineStream.skipWhitespace(), '\t'); - lineStream.next(); - assert.equal(lineStream.skipWhitespace(), ' '); - lineStream.next(); - lineStream.next(); - assert.equal(lineStream.skipWhitespace(), ' '); - lineStream.next(); - assert.equal(lineStream.skipWhitespace(), ' \t '); - lineStream.next(); - assert.equal(lineStream.skipWhitespace(), ' '); - assert.ok(lineStream.eos()); - }); - - test('peekToken', () => { - var lineStream = new LineStream('a b c edf '); - assert.equal(lineStream.peekToken(), 'a'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'b'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'b'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'c'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'c'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'c'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'edf'); - lineStream.next(); - assert.equal(lineStream.peekToken(), 'edf'); - lineStream.next(); - lineStream.next(); - lineStream.next(); - lineStream.next(); - assert.throws(() => { lineStream.peekToken(); }); - assert.ok(lineStream.eos()); - }); - - test('nextToken', () => { - var lineStream = new LineStream('a b c edf '); - assert.equal(lineStream.nextToken(), 'a'); - assert.equal(lineStream.nextToken(), 'b'); - assert.equal(lineStream.nextToken(), 'c'); - assert.equal(lineStream.nextToken(), 'edf'); - assert.equal(lineStream.nextToken(), ''); - assert.throws(() => { lineStream.nextToken(); }); - assert.ok(lineStream.eos()); - }); - - function newTokenStream(source, separators, whitespace) { - var lineStream = new LineStream(source); - lineStream.setTokenRules(separators, whitespace); - return lineStream; - } - - function checkPos(lineStream,pos) { - assert.equal(lineStream.pos(), pos); - } - - function check(lineStream, pos, token) { - checkPos(lineStream, pos); - assert.equal(lineStream.nextToken(), token); - } test('corner cases', () => { - var input, lineStream; - var noTokens = (lineStream) => { + let noTokens = (lineStream) => { assert.equal(lineStream.pos(), 0); assert.ok(lineStream.eos()); }; - noTokens(newTokenStream('', '', '')); - noTokens(newTokenStream('', '', 'x')); - noTokens(newTokenStream('', 'x', '')); - noTokens(newTokenStream('', 'x', 'x')); - - input = '.....'; - lineStream = newTokenStream(input, '.', ''); - for (var i = 0; i < input.length; i++) { - check(lineStream, i, '.'); - } - - input = ' . . . . .'; - lineStream = newTokenStream(input, '.', ' '); - for (var i = 0; i < input.length / 2; i++) { - check(lineStream, (i * 2) , '.'); - } - - input = '. . . . . '; - lineStream = newTokenStream(input, '.', ' '); - for (var i = 0; i < input.length / 2; i++) { - check(lineStream, i === 0 ? 0 : (i * 2) - 1, '.'); - } + noTokens(new LineStream('')); }); - test('javascript assign', () => { - var lineStream = newTokenStream(' var foo =bar("foo"); //x ', '+-*/%&|^~!=<>(){}[]\'"\\/?;,', '\t '); + test('advanceToEOS', () => { + var lineStream = new LineStream(' var foo =bar("foo"); //x '); assert.equal(lineStream.pos(), 0); - assert.equal(lineStream.peekToken(), 'var'); - - check(lineStream, 0, 'var'); - check(lineStream, 5, 'foo'); - check(lineStream, 9, '='); - check(lineStream, 11, 'bar'); - check(lineStream, 14, '('); - check(lineStream, 15, '"'); - check(lineStream, 16, 'foo'); - check(lineStream, 19, '"'); - check(lineStream, 20, ')'); - check(lineStream, 21, ';'); - check(lineStream, 22, '/'); - check(lineStream, 24, '/'); - check(lineStream, 25, 'x'); - checkPos(lineStream, 26); - - lineStream.skipWhitespace(); - assert.ok(lineStream.eos(), 'Stream finished'); - }); - - test('javascript strings', () => { - var lineStream = newTokenStream('x = " my \\"string\\" ";', '=()\\";/', '\t '); - - check(lineStream, 0, 'x'); - check(lineStream, 1, '='); - check(lineStream, 3, '"'); - check(lineStream, 5, 'my'); - check(lineStream, 9, '\\'); - check(lineStream, 11, '"'); - check(lineStream, 12, 'string'); - check(lineStream, 18, '\\'); - check(lineStream, 19, '"'); - check(lineStream, 20, '"'); - check(lineStream, 22, ';'); + lineStream.advanceToEOS(); assert.ok(lineStream.eos(), 'Stream finished'); }); test('peek', () => { - var lineStream = newTokenStream('albert, bart, charlie, damon, erich', ',', ' '); + var lineStream = new LineStream('albert, bart, charlie, damon, erich'); - assert.equal(lineStream.peekToken(), 'albert'); assert.equal(lineStream.peek(), 'a'); + lineStream.advance(1); - assert.equal(lineStream.nextToken(), 'albert'); - assert.equal(lineStream.nextToken(), ','); - - assert.equal(lineStream.peekToken(), 'bart'); - assert.equal(lineStream.peek(), ' '); - assert.equal(lineStream.nextToken(), 'bart'); - - assert.equal(lineStream.peekToken(), ','); - assert.equal(lineStream.peek(), ','); - assert.equal(lineStream.nextToken(), ','); - - lineStream.advanceToEOS(); - assert.throws(() => { lineStream.peekToken(); }); - assert.throws(() => { lineStream.peek(); }); - }); - - test('next', () => { - var lineStream = newTokenStream('albert, bart, charlie, damon, erich', ',', ' '); - - assert.equal(lineStream.peekToken(), 'albert'); - assert.equal(lineStream.next(), 'a'); - assert.equal(lineStream.next(), 'l'); - assert.equal(lineStream.next(), 'b'); - - assert.equal(lineStream.nextToken(), 'ert'); - assert.equal(lineStream.nextToken(), ','); - - assert.equal(lineStream.nextToken(), 'bart'); - - assert.equal(lineStream.peekToken(), ','); - assert.equal(lineStream.next(), ','); - assert.equal(lineStream.next(), ' '); - assert.equal(lineStream.next(), 'c'); - assert.equal(lineStream.next(), 'h'); - assert.equal(lineStream.next(), 'a'); - assert.equal(lineStream.next(), 'r'); - assert.equal(lineStream.next(), 'l'); - assert.equal(lineStream.next(), 'i'); - assert.equal(lineStream.next(), 'e'); - assert.equal(lineStream.next(), ','); - - assert.equal(lineStream.nextToken(), 'damon'); + assert.equal(lineStream.peek(), 'l'); lineStream.advanceToEOS(); - assert.throws(() => { lineStream.peekToken(); }); assert.throws(() => { lineStream.peek(); }); }); - test('next & goBack', () => { - var lineStream = new LineStream('albert, bart, charlie, damon, erich'); - lineStream.setTokenRules(',', ' '); - - assert.equal(lineStream.peekToken(), 'albert'); - assert.equal(lineStream.next(), 'a'); - assert.equal(lineStream.next(), 'l'); - assert.equal(lineStream.next(), 'b'); - assert.equal(lineStream.nextToken(), 'ert'); - lineStream.goBack(6); - - assert.equal(lineStream.nextToken(), 'albert'); - assert.equal(lineStream.next(), ','); - lineStream.goBack(7); - - assert.equal(lineStream.nextToken(), 'albert'); - assert.equal(lineStream.nextToken(), ','); - assert.equal(lineStream.next(), ' '); - assert.equal(lineStream.next(), 'b'); - assert.equal(lineStream.next(), 'a'); - lineStream.goBack(3); - - assert.equal(lineStream.nextToken(), 'bart'); - lineStream.goBack(5); - - assert.equal(lineStream.next(), ' '); - - lineStream.advanceToEOS(); - assert.throws(() => { lineStream.peekToken(); }); - assert.throws(() => { lineStream.peek(); }); - }); }); diff --git a/src/vs/editor/test/common/modes/modesRegistry.test.ts b/src/vs/editor/test/common/modes/modesRegistry.test.ts deleted file mode 100644 index e18da2312044352f38292cbdc5f843f80f97e8b0..0000000000000000000000000000000000000000 --- a/src/vs/editor/test/common/modes/modesRegistry.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 'vs/languages/html/common/html.contribution'; -import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; -import * as assert from 'assert'; -import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; -import {IExtensionService} from 'vs/platform/extensions/common/extensions'; - -suite('Editor Modes - Modes Registry', () => { - - let instantiationService: TestInstantiationService; - - setup(() => { - instantiationService= new TestInstantiationService(); - instantiationService.stub(IExtensionService); - }); - - test('Bug 12104: [f12] createModel not successfully handling mime type list?', () => { - let modeService = instantiationService.createInstance(ModeServiceImpl); - assert.equal(modeService.getModeId('text/html,text/plain'), 'html'); - }); -}); - diff --git a/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts b/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts index 3503a64383c9855ff344bfac3885d7c95d0d7b29..a2b8951495354472da84ef99c31b16c612422fa0 100644 --- a/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts +++ b/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts @@ -5,11 +5,12 @@ 'use strict'; import * as assert from 'assert'; -import {IStream, ITokenizationResult, TokenizationRegistry} from 'vs/editor/common/modes'; -import {AbstractState} from 'vs/editor/common/modes/abstractState'; +import {TokenizationRegistry} from 'vs/editor/common/modes'; +import {AbstractState, ITokenizationResult} from 'vs/editor/common/modes/abstractState'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {tokenizeToHtmlContent} from 'vs/editor/common/modes/textToHtmlTokenizer'; import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; +import {LineStream} from 'vs/editor/common/modes/lineStream'; suite('Editor Modes - textToHtmlTokenizer', () => { test('TextToHtmlTokenizer', () => { @@ -67,8 +68,10 @@ class State extends AbstractState { return new State(this.getModeId()); } - public tokenize(stream:IStream):ITokenizationResult { - return { type: stream.next() === '.' ? '' : 'text' }; + public tokenize(stream:LineStream):ITokenizationResult { + let chr = stream.peek(); + stream.advance(1); + return { type: chr === '.' ? '' : 'text' }; } } diff --git a/src/vs/editor/test/common/modes/tokenization.test.ts b/src/vs/editor/test/common/modes/tokenization.test.ts index 0222191e130831a5c9ffdf882bdd7e4cf5943b05..e4e83709d5e6faa3e840791486036e6827c6be03 100644 --- a/src/vs/editor/test/common/modes/tokenization.test.ts +++ b/src/vs/editor/test/common/modes/tokenization.test.ts @@ -6,13 +6,14 @@ import * as assert from 'assert'; import * as modes from 'vs/editor/common/modes'; -import {AbstractState} from 'vs/editor/common/modes/abstractState'; +import {AbstractState, ITokenizationResult} from 'vs/editor/common/modes/abstractState'; import {handleEvent} from 'vs/editor/common/modes/supports'; import {IModeLocator, ILeavingNestedModeData, TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {createMockLineContext} from 'vs/editor/test/common/modesTestUtils'; import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; import {ModeTransition} from 'vs/editor/common/core/modeTransition'; import {Token} from 'vs/editor/common/core/token'; +import {LineStream} from 'vs/editor/common/modes/lineStream'; export interface IModeSwitchingDescriptor { [character:string]:{ @@ -36,14 +37,28 @@ export class StateMemorizingLastWord extends AbstractState { return new StateMemorizingLastWord(this.getModeId(), this.descriptor, this.lastWord); } - public tokenize(stream:modes.IStream):modes.ITokenizationResult { - stream.setTokenRules('[]{}()==--', '\t \u00a0'); - if (stream.skipWhitespace() !== '') { - return { - type: '' - }; + public tokenize(stream:LineStream):ITokenizationResult { + let contents = stream.advanceToEOS(); + stream.goBack(contents.length); + + let m = contents.match(/^([\t \u00a0]+)/); + if (m) { + stream.advance(m[0].length); + return { type: '' }; } - var word = stream.nextToken(); + + m = contents.match(/^([\[\]\{\}\(\)])/); + let word: string; + if (m) { + stream.advance(m[0].length); + word = m[1]; + + } else { + m = contents.match(/([a-zA-Z]+)/); + stream.advance(m[0].length); + word = m[1]; + } + return { type: this.getModeId() + '.' + word, nextState: new StateMemorizingLastWord(this.getModeId(), this.descriptor, word) @@ -61,7 +76,7 @@ export class SwitchingMode extends MockMode { modes.TokenizationRegistry.register(this.getId(), new TokenizationSupport(null, this.getId(), this, true)); } - public getInitialState():modes.IState { + public getInitialState():AbstractState { return new StateMemorizingLastWord(this.getId(), this._switchingModeDescriptor, null); } @@ -167,8 +182,10 @@ suite('Editor Modes - Tokenization', () => { return new State(this.getModeId()); } - public tokenize(stream:modes.IStream):modes.ITokenizationResult { - return { type: stream.next() === '.' ? '' : 'text' }; + public tokenize(stream:LineStream):ITokenizationResult { + let chr = stream.peek(); + stream.advance(1); + return { type: chr === '.' ? '' : 'text' }; } } diff --git a/src/vs/editor/test/common/modesUtil.ts b/src/vs/editor/test/common/modesUtil.ts index c57c8bf6b0f6b96df20d25d63bd3eeec8df3823e..4cd5deba3d3d8e1b80317f7ebcc5b91a2ea17124 100644 --- a/src/vs/editor/test/common/modesUtil.ts +++ b/src/vs/editor/test/common/modesUtil.ts @@ -5,11 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import {Model} from 'vs/editor/common/model/model'; import * as modes from 'vs/editor/common/modes'; -import {RichEditSupport, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {Token} from 'vs/editor/common/core/token'; -import {generateMockModeId} from 'vs/editor/test/common/mocks/mockMode'; export interface ITestToken { startIndex: number; @@ -21,10 +17,6 @@ export interface ITestItem { tokens: ITestToken[]; } -export function assertWords(actual:string[], expected:string[], message?:string): void { - assert.deepEqual(actual, expected, message); -} - export function assertTokenization(tokenizationSupport: modes.ITokenizationSupport, tests: ITestItem[]): void { var state = tokenizationSupport.getInitialState(); for (var i = 0, len = tests.length; i < len; i++) { @@ -37,71 +29,3 @@ export function assertTokenization(tokenizationSupport: modes.ITokenizationSuppo state = result.endState; } } - -export interface IOnEnterAsserter { - nothing(oneLineAboveText:string, beforeText:string, afterText:string): void; - indents(oneLineAboveText:string, beforeText:string, afterText:string): void; - outdents(oneLineAboveText:string, beforeText:string, afterText:string): void; - indentsOutdents(oneLineAboveText:string, beforeText:string, afterText:string): void; -} - -export function createOnEnterAsserter(conf: LanguageConfiguration): IOnEnterAsserter { - const modeId = generateMockModeId(); - - const assertOne = (oneLineAboveText:string, beforeText:string, afterText:string, expected: modes.IndentAction) => { - let model = Model.createFromString( - [ oneLineAboveText, beforeText + afterText ].join('\n'), - undefined, - modeId - ); - let richEditSupport = new RichEditSupport(modeId, null, conf); - let actual = richEditSupport.onEnter.onEnter(model, { lineNumber: 2, column: beforeText.length + 1 }); - if (expected === modes.IndentAction.None) { - assert.equal(actual, null, oneLineAboveText + '\\n' + beforeText + '|' + afterText); - } else { - assert.equal(actual.indentAction, expected, oneLineAboveText + '\\n' + beforeText + '|' + afterText); - } - model.dispose(); - }; - - return { - nothing: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.None); - }, - indents: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.Indent); - }, - outdents: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.Outdent); - }, - indentsOutdents: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.IndentOutdent); - } - }; -} - -export function executeTests(tokenizationSupport: modes.ITokenizationSupport, tests:ITestItem[][]): void { - for (var i = 0, len = tests.length; i < len; i++) { - assert.ok(true, 'TEST #' + i); - executeTest(tokenizationSupport, tests[i]); - } -} - -function executeTest(tokenizationSupport: modes.ITokenizationSupport, tests:ITestItem[]): void { - var state = tokenizationSupport.getInitialState(); - for (var i = 0, len = tests.length; i < len; i++) { - assert.ok(true, tests[i].line); - - var result = tokenizationSupport.tokenize(tests[i].line, state); - - if (tests[i].tokens) { - assertTokens(result.tokens, tests[i].tokens, 'Tokenizing line ' + tests[i].line); - } - - state = result.endState; - } -} - -function assertTokens(actual:Token[], expected:ITestToken[], message?:string): void { - assert.deepEqual(actual, expected, message + ': ' + JSON.stringify(actual, null, '\t')); -} diff --git a/src/vs/editor/test/common/services/languagesRegistry.test.ts b/src/vs/editor/test/common/services/languagesRegistry.test.ts index 76b432f2ee72a1dfe6f7b4145ff470b89f017bd1..3a9805a62c4c90bdef9698b2be02c2ae8312d5a5 100644 --- a/src/vs/editor/test/common/services/languagesRegistry.test.ts +++ b/src/vs/editor/test/common/services/languagesRegistry.test.ts @@ -12,13 +12,11 @@ suite('LanguagesRegistry', () => { test('output mode does not have a name', () => { let registry = new LanguagesRegistry(false); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'outputModeId', extensions: [], aliases: [null], mimetypes: ['outputModeMimeType'], - moduleId: 'outputModeModuleId', - ctorName: 'outputModeCtorName' }]); assert.deepEqual(registry.getRegisteredLanguageNames(), []); @@ -27,13 +25,11 @@ suite('LanguagesRegistry', () => { test('mode with alias does have a name', () => { let registry = new LanguagesRegistry(false); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'modeId', extensions: [], aliases: ['ModeName'], mimetypes: ['bla'], - moduleId: 'bla', - ctorName: 'bla' }]); assert.deepEqual(registry.getRegisteredLanguageNames(), ['ModeName']); @@ -43,13 +39,11 @@ suite('LanguagesRegistry', () => { test('mode without alias gets a name', () => { let registry = new LanguagesRegistry(false); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'modeId', extensions: [], aliases: [], mimetypes: ['bla'], - moduleId: 'bla', - ctorName: 'bla' }]); assert.deepEqual(registry.getRegisteredLanguageNames(), ['modeId']); @@ -59,22 +53,18 @@ suite('LanguagesRegistry', () => { test('bug #4360: f# not shown in status bar', () => { let registry = new LanguagesRegistry(false); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'modeId', extensions: ['.ext1'], aliases: ['ModeName'], mimetypes: ['bla'], - moduleId: 'bla', - ctorName: 'bla' }]); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'modeId', extensions: ['.ext2'], aliases: [], mimetypes: ['bla'], - moduleId: 'bla', - ctorName: 'bla' }]); assert.deepEqual(registry.getRegisteredLanguageNames(), ['ModeName']); @@ -84,22 +74,18 @@ suite('LanguagesRegistry', () => { test('issue #5278: Extension cannot override language name anymore', () => { let registry = new LanguagesRegistry(false); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'modeId', extensions: ['.ext1'], aliases: ['ModeName'], mimetypes: ['bla'], - moduleId: 'bla', - ctorName: 'bla' }]); - registry._registerCompatModes([{ + registry._registerLanguages([{ id: 'modeId', extensions: ['.ext2'], aliases: ['BetterModeName'], mimetypes: ['bla'], - moduleId: 'bla', - ctorName: 'bla' }]); assert.deepEqual(registry.getRegisteredLanguageNames(), ['BetterModeName']); diff --git a/src/vs/editor/test/common/services/resourceService.test.ts b/src/vs/editor/test/common/services/resourceService.test.ts deleted file mode 100644 index 4f7f75053d5f7478942594735e008d9c2142bd0f..0000000000000000000000000000000000000000 --- a/src/vs/editor/test/common/services/resourceService.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 * as assert from 'assert'; -import URI from 'vs/base/common/uri'; -import {CompatMirrorModel} from 'vs/editor/common/model/compatMirrorModel'; -import {ResourceService} from 'vs/editor/common/services/resourceServiceImpl'; -import {TextModel} from 'vs/editor/common/model/textModel'; - -function createTestMirrorModelFromString(value:string): CompatMirrorModel { - return new CompatMirrorModel(0, TextModel.toRawText(value, TextModel.DEFAULT_CREATION_OPTIONS), null); -} - -suite('Editor Services - ResourceService', () => { - - test('insert, remove, all', () => { - - let service = new ResourceService(); - - service.insert(URI.parse('test://1'), createTestMirrorModelFromString('hi')); - assert.equal(service.get(URI.parse('test://1')).getValue(), 'hi'); - - service.insert(URI.parse('test://2'), createTestMirrorModelFromString('hi')); - - service.remove(URI.parse('test://1')); - service.remove(URI.parse('test://1')); - service.remove(URI.parse('test://2')); - - assert.equal(service.get(URI.parse('test://1')), null); - }); - - test('inserting the same resource twice throws', () => { - let service = new ResourceService(); - - service.insert(URI.parse('test://path/some-N1ce-name'), createTestMirrorModelFromString('hello')); - - assert.throws(() => { - service.insert(URI.parse('test://path/some-N1ce-name'), createTestMirrorModelFromString('hello again')); - }); - }); -}); diff --git a/src/vs/languages/buildfile.js b/src/vs/languages/buildfile.js deleted file mode 100644 index 0fea1f9007d6a1e9fd130bc52c4651436b9cc489..0000000000000000000000000000000000000000 --- a/src/vs/languages/buildfile.js +++ /dev/null @@ -1,58 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -var EntryPoint = (function() { - function toArray(param) { - if (!param) { - return []; - } - if (!Array.isArray(param)) { - return [param]; - } - return param; - } - - function EntryPoint(result, modules) { - this.result = result; - this.modules = toArray(modules); - } - EntryPoint.prototype.define = function(moduleId, excludes) { - excludes = toArray(excludes); - this.result.push({ - name: moduleId, - exclude: ['vs/css', 'vs/nls'].concat(this.modules).concat(excludes) - }); - return new EntryPoint(this.result, this.modules.concat([moduleId].concat(excludes))); - }; - EntryPoint.prototype.combine = function(other) { - return new EntryPoint(this.result, this.modules.concat(other.modules)); - }; - return EntryPoint; -})(); -exports.collectModules = function(args) { - - var result = []; - // var common = new EntryPoint(result, 'vs/editor/common/languages.common'); - // var worker = new EntryPoint(result, ['vs/editor/common/languages.common', 'vs/base/common/worker/workerServer', 'vs/editor/common/worker/editorWorkerServer']); - - // ---- beautify-html (shared btw html and xml) ----------------------------- - // worker.define('vs/languages/lib/common/beautify-html'); - - // // ---- handlebars ---------------------------------- - // common.define('vs/languages/handlebars/common/handlebars', ['vs/languages/html/common/html']); - - // // ---- html ---------------------------------- - // common.define('vs/languages/html/common/html') - // .combine(worker) - // .define('vs/languages/html/common/htmlWorker', ['vs/languages/lib/common/beautify-html']); - - // // ---- razor ----------------------------------- - // common.define('vs/languages/razor/common/razor', ['vs/languages/html/common/html']) - // .combine(worker) - // .define('vs/languages/razor/common/razorWorker', ['vs/languages/html/common/htmlWorker', 'vs/languages/lib/common/beautify-html'] ); - - return result; -}; \ No newline at end of file diff --git a/src/vs/languages/handlebars/common/handlebars.contribution.ts b/src/vs/languages/handlebars/common/handlebars.contribution.ts deleted file mode 100644 index 0aef06b9b09e6b7cce2a842fd5db3a1b7656482e..0000000000000000000000000000000000000000 --- a/src/vs/languages/handlebars/common/handlebars.contribution.ts +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; - -ModesRegistry.registerCompatMode({ - id: 'handlebars', - extensions: ['.handlebars', '.hbs'], - aliases: ['Handlebars', 'handlebars'], - mimetypes: ['text/x-handlebars-template'], - moduleId: 'vs/languages/handlebars/common/handlebars', - ctorName: 'HandlebarsMode' -}); diff --git a/src/vs/languages/handlebars/common/handlebars.ts b/src/vs/languages/handlebars/common/handlebars.ts deleted file mode 100644 index 4ccc898e1f16363dfa9eb4c23c89ced50c89900b..0000000000000000000000000000000000000000 --- a/src/vs/languages/handlebars/common/handlebars.ts +++ /dev/null @@ -1,202 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 modes = require('vs/editor/common/modes'); -import htmlMode = require('vs/languages/html/common/html'); -import handlebarsTokenTypes = require('vs/languages/handlebars/common/handlebarsTokenTypes'); -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {createWordRegExp} from 'vs/editor/common/modes/abstractMode'; -import {wireCancellationToken} from 'vs/base/common/async'; -import {ICompatWorkerService} from 'vs/editor/common/services/compatWorkerService'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {TokenizationSupport, ILeavingNestedModeData} from 'vs/editor/common/modes/supports/tokenizationSupport'; - -export enum States { - HTML, - Expression, - UnescapedExpression -} - -export class HandlebarsState extends htmlMode.State { - - constructor(modeId:string, - kind:htmlMode.States, - public handlebarsKind:States, - lastTagName:string, - lastAttributeName:string, - embeddedContentType:string, - attributeValueQuote:string, - attributeValueLength:number) { - - super(modeId, kind, lastTagName, lastAttributeName, embeddedContentType, attributeValueQuote, attributeValueLength); - } - - public makeClone(): HandlebarsState { - return new HandlebarsState(this.getModeId(), this.kind, this.handlebarsKind, this.lastTagName, this.lastAttributeName, this.embeddedContentType, this.attributeValueQuote, this.attributeValueLength); - } - - public equals(other:modes.IState):boolean { - if (other instanceof HandlebarsState) { - return ( - super.equals(other) - ); - } - return false; - } - - public tokenize(stream:modes.IStream) : modes.ITokenizationResult { - switch(this.handlebarsKind) { - case States.HTML: - if (stream.advanceIfString('{{{').length > 0) { - this.handlebarsKind = States.UnescapedExpression; - return { type: handlebarsTokenTypes.EMBED_UNESCAPED }; - } - else if (stream.advanceIfString('{{').length > 0) { - this.handlebarsKind = States.Expression; - return { type: handlebarsTokenTypes.EMBED }; - } - break; - - case States.Expression: - case States.UnescapedExpression: - if (this.handlebarsKind === States.Expression && stream.advanceIfString('}}').length > 0) { - this.handlebarsKind = States.HTML; - return { type: handlebarsTokenTypes.EMBED }; - } - else if (this.handlebarsKind === States.UnescapedExpression &&stream.advanceIfString('}}}').length > 0) { - this.handlebarsKind = States.HTML; - return { type: handlebarsTokenTypes.EMBED_UNESCAPED }; - } - else if(stream.skipWhitespace().length > 0) { - return { type: ''}; - } - - if(stream.peek() === '#') { - stream.advanceWhile(/^[^\s}]/); - return { type: handlebarsTokenTypes.KEYWORD }; - } - - if(stream.peek() === '/') { - stream.advanceWhile(/^[^\s}]/); - return { type: handlebarsTokenTypes.KEYWORD }; - } - - if(stream.advanceIfString('else')) { - var next = stream.peek(); - if(next === ' ' || next === '\t' || next === '}') { - return { type: handlebarsTokenTypes.KEYWORD }; - } - else { - stream.goBack(4); - } - } - - if(stream.advanceWhile(/^[^\s}]/).length > 0) { - return { type: handlebarsTokenTypes.VARIABLE }; - } - break; - } - return super.tokenize(stream); - } -} - -export class HandlebarsMode extends htmlMode.HTMLMode { - - public static LANG_CONFIG:LanguageConfiguration = { - wordPattern: createWordRegExp('#-?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['{{', '}}'] - ], - - __electricCharacterSupport: { - embeddedElectricCharacters: ['*', '}', ']', ')'] - }, - - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - surroundingPairs: [ - { open: '<', close: '>' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - onEnterRules: [ - { - beforeText: new RegExp(`<(?!(?:${htmlMode.EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - afterText: /^<\/(\w[\w\d]*)\s*>$/i, - action: { indentAction: modes.IndentAction.IndentOutdent } - }, - { - beforeText: new RegExp(`<(?!(?:${htmlMode.EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - action: { indentAction: modes.IndentAction.Indent } - } - ], - }; - - constructor( - descriptor:modes.IModeDescriptor, - @IInstantiationService instantiationService: IInstantiationService, - @IModeService modeService: IModeService, - @ICompatWorkerService compatWorkerService: ICompatWorkerService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(descriptor, instantiationService, modeService, compatWorkerService, workspaceContextService, configurationService); - } - - protected _registerSupports(): void { - modes.SuggestRegistry.register(this.getId(), { - triggerCharacters: ['.', ':', '<', '"', '=', '/'], - provideCompletionItems: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideCompletionItems(model.uri, position)); - } - }, true); - - modes.DocumentHighlightProviderRegistry.register(this.getId(), { - provideDocumentHighlights: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentHighlights(model.uri, position)); - } - }, true); - - modes.LinkProviderRegistry.register(this.getId(), { - provideLinks: (model, token): Thenable => { - return wireCancellationToken(token, this.provideLinks(model.uri)); - } - }, true); - - LanguageConfigurationRegistry.register(this.getId(), HandlebarsMode.LANG_CONFIG); - - modes.TokenizationRegistry.register(this.getId(), new TokenizationSupport(this._modeService, this.getId(), this, true)); - } - - public getInitialState() : modes.IState { - return new HandlebarsState(this.getId(), htmlMode.States.Content, States.HTML, '', '', '', '', 0); - } - - public getLeavingNestedModeData(line:string, state:modes.IState):ILeavingNestedModeData { - var leavingNestedModeData = super.getLeavingNestedModeData(line, state); - if (leavingNestedModeData) { - leavingNestedModeData.stateAfterNestedMode = new HandlebarsState(this.getId(), htmlMode.States.Content, States.HTML, '', '', '', '', 0); - } - return leavingNestedModeData; - } -} diff --git a/src/vs/languages/handlebars/common/handlebarsTokenTypes.ts b/src/vs/languages/handlebars/common/handlebarsTokenTypes.ts deleted file mode 100644 index 2a04f51cc9acdb1c42cb55b4fc24034f90303fcb..0000000000000000000000000000000000000000 --- a/src/vs/languages/handlebars/common/handlebarsTokenTypes.ts +++ /dev/null @@ -1,10 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 const EMBED = 'punctuation.expression.unescaped.handlebars'; -export const EMBED_UNESCAPED = 'punctuation.expression.handlebars'; -export const KEYWORD = 'keyword.helper.handlebars'; -export const VARIABLE = 'variable.parameter.handlebars'; \ No newline at end of file diff --git a/src/vs/languages/handlebars/test/common/handlebars.test.ts b/src/vs/languages/handlebars/test/common/handlebars.test.ts deleted file mode 100644 index e25688093a7e7b1ca36fff44cb80e0cbd8473231..0000000000000000000000000000000000000000 --- a/src/vs/languages/handlebars/test/common/handlebars.test.ts +++ /dev/null @@ -1,368 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 Modes = require('vs/editor/common/modes'); -import modesUtil = require('vs/editor/test/common/modesUtil'); -import {htmlTokenTypes} from 'vs/languages/html/common/html'; -import handlebarsTokenTypes = require('vs/languages/handlebars/common/handlebarsTokenTypes'); -import {HandlebarsMode} from 'vs/languages/handlebars/common/handlebars'; -import {MockModeService} from 'vs/editor/test/common/mocks/mockModeService'; -import {MockTokenizingMode} from 'vs/editor/test/common/mocks/mockMode'; - -class HandlebarsMockModeService extends MockModeService { - - private _handlebarsMode: HandlebarsMode; - - constructor() { - super(); - this._handlebarsMode = null; - } - - public setHandlebarsMode(handlebarsMode: HandlebarsMode): void { - this._handlebarsMode = handlebarsMode; - } - - isRegisteredMode(mimetypeOrModeId: string): boolean { - if (mimetypeOrModeId === 'text/javascript') { - return true; - } - if (mimetypeOrModeId === 'text/x-handlebars-template') { - return true; - } - throw new Error('Not implemented'); - } - - getModeId(mimetypeOrModeId: string): string { - if (mimetypeOrModeId === 'text/javascript') { - return 'js-mode-id'; - } - if (mimetypeOrModeId === 'text/x-handlebars-template') { - return 'handlebars-mode-id'; - } - throw new Error('Not implemented'); - } - - getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): Modes.IMode { - if (commaSeparatedMimetypesOrCommaSeparatedIds === 'js-mode-id') { - return new MockTokenizingMode('mock-js'); - } - if (commaSeparatedMimetypesOrCommaSeparatedIds === 'handlebars-mode-id') { - return this._handlebarsMode; - } - throw new Error('Not implemented'); - } -} - -suite('Handlebars', () => { - - var tokenizationSupport: Modes.ITokenizationSupport; - suiteSetup(function() { - let modeService = new HandlebarsMockModeService(); - - let mode = new HandlebarsMode( - { id: 'handlebars' }, - null, - modeService, - null, - null, - null - ); - - modeService.setHandlebarsMode(mode); - - tokenizationSupport = Modes.TokenizationRegistry.get(mode.getId()); - }); - - test('Just HTML', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

handlebars!

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: '' }, - { startIndex:15, type: htmlTokenTypes.DELIM_END }, - { startIndex:17, type: htmlTokenTypes.getTag('h1') }, - { startIndex:19, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

{{ title }}

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED }, - { startIndex:6, type: '' }, - { startIndex:7, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:12, type: '' }, - { startIndex:13, type: handlebarsTokenTypes.EMBED }, - { startIndex:15, type: htmlTokenTypes.DELIM_END }, - { startIndex:17, type: htmlTokenTypes.getTag('h1') }, - { startIndex:19, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Expressions Sans Whitespace', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

{{title}}

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED }, - { startIndex:6, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:11, type: handlebarsTokenTypes.EMBED }, - { startIndex:13, type: htmlTokenTypes.DELIM_END }, - { startIndex:15, type: htmlTokenTypes.getTag('h1') }, - { startIndex:17, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Unescaped Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

{{{ title }}}

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED_UNESCAPED }, - { startIndex:7, type: '' }, - { startIndex:8, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:13, type: '' }, - { startIndex:14, type: handlebarsTokenTypes.EMBED_UNESCAPED }, - { startIndex:17, type: htmlTokenTypes.DELIM_END }, - { startIndex:19, type: htmlTokenTypes.getTag('h1') }, - { startIndex:21, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Blocks', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '
    {{#each items}}
  • {{item}}
  • {{/each}}
', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('ul') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED }, - { startIndex:6, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:11, type: '' }, - { startIndex:12, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:17, type: handlebarsTokenTypes.EMBED }, - { startIndex:19, type: htmlTokenTypes.DELIM_START }, - { startIndex:20, type: htmlTokenTypes.getTag('li') }, - { startIndex:22, type: htmlTokenTypes.DELIM_START }, - { startIndex:23, type: handlebarsTokenTypes.EMBED }, - { startIndex:25, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:29, type: handlebarsTokenTypes.EMBED }, - { startIndex:31, type: htmlTokenTypes.DELIM_END }, - { startIndex:33, type: htmlTokenTypes.getTag('li') }, - { startIndex:35, type: htmlTokenTypes.DELIM_END }, - { startIndex:36, type: handlebarsTokenTypes.EMBED }, - { startIndex:38, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:43, type: handlebarsTokenTypes.EMBED }, - { startIndex:45, type: htmlTokenTypes.DELIM_END }, - { startIndex:47, type: htmlTokenTypes.getTag('ul') }, - { startIndex:49, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Multiline', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '
', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('div') }, - { startIndex:4, type: htmlTokenTypes.DELIM_START } - ]}, { - line: '{{#if foo}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:5, type: '' }, - { startIndex:6, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:9, type: handlebarsTokenTypes.EMBED } - ]}, { - line: '{{bar}}', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('span') }, - { startIndex:5, type: htmlTokenTypes.DELIM_START }, - { startIndex:6, type: handlebarsTokenTypes.EMBED }, - { startIndex:8, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:11, type: handlebarsTokenTypes.EMBED }, - { startIndex:13, type: htmlTokenTypes.DELIM_END }, - { startIndex:15, type: htmlTokenTypes.getTag('span') }, - { startIndex:19, type: htmlTokenTypes.DELIM_END } - ]}, { - line: '{{/if}}', - tokens: null} - ]); - }); - - test('Div end', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '
', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_END }, - { startIndex:2, type: htmlTokenTypes.getTag('div') }, - { startIndex:5, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - // shamelessly stolen from the HTML test bed since Handlebars are a superset of HTML - test('Embedded Content in HTML', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('script') }, - { startIndex:7, type: '' }, - { startIndex:8, type: htmlTokenTypes.ATTRIB_NAME }, - { startIndex:12, type: htmlTokenTypes.DELIM_ASSIGN }, - { startIndex:13, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:30, type: htmlTokenTypes.DELIM_START }, - { startIndex:31, type: 'mock-js' }, - { startIndex:41, type: htmlTokenTypes.DELIM_END }, - { startIndex:43, type: htmlTokenTypes.getTag('script') }, - { startIndex:49, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('HTML Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('script') }, - { startIndex:7, type: '' }, - { startIndex:8, type: htmlTokenTypes.ATTRIB_NAME }, - { startIndex:12, type: htmlTokenTypes.DELIM_ASSIGN }, - { startIndex:13, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:41, type: htmlTokenTypes.DELIM_START }, - { startIndex:42, type: htmlTokenTypes.DELIM_START }, - { startIndex:43, type: htmlTokenTypes.getTag('h1') }, - { startIndex:45, type: htmlTokenTypes.DELIM_START }, - { startIndex:46, type: handlebarsTokenTypes.EMBED }, - { startIndex:48, type: '' }, - { startIndex:49, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:54, type: '' }, - { startIndex:55, type: handlebarsTokenTypes.EMBED }, - { startIndex:57, type: htmlTokenTypes.DELIM_END }, - { startIndex:59, type: htmlTokenTypes.getTag('h1') }, - { startIndex:61, type: htmlTokenTypes.DELIM_END }, - { startIndex:62, type: htmlTokenTypes.DELIM_END }, - { startIndex:64, type: htmlTokenTypes.getTag('script') }, - { startIndex:70, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Multi-line HTML Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_END }, - { startIndex:2, type: htmlTokenTypes.getTag('script') }, - { startIndex:8, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('HTML Nested Modes', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '{{foo}}{{bar}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:5, type: handlebarsTokenTypes.EMBED }, - { startIndex:7, type: htmlTokenTypes.DELIM_START }, - { startIndex:8, type: htmlTokenTypes.getTag('script') }, - { startIndex:14, type: htmlTokenTypes.DELIM_START }, - { startIndex:15, type: htmlTokenTypes.DELIM_END }, - { startIndex:17, type: htmlTokenTypes.getTag('script') }, - { startIndex:23, type: htmlTokenTypes.DELIM_END }, - { startIndex:24, type: handlebarsTokenTypes.EMBED }, - { startIndex:26, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:29, type: handlebarsTokenTypes.EMBED } - ]} - ]); - }); - - test('else keyword', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '{{else}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:6, type: handlebarsTokenTypes.EMBED } - ]} - ]); - }); - - test('else keyword #2', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '{{elseFoo}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:9, type: handlebarsTokenTypes.EMBED } - ]} - ]); - }); - - test('Token inside attribute', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('a') }, - { startIndex:2, type: '' }, - { startIndex:3, type: htmlTokenTypes.ATTRIB_NAME }, - { startIndex:7, type: htmlTokenTypes.DELIM_ASSIGN }, - { startIndex:8, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:16, type: handlebarsTokenTypes.EMBED }, - { startIndex:18, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:27, type: handlebarsTokenTypes.EMBED }, - { startIndex:29, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:30, type: htmlTokenTypes.DELIM_START } - ]} - ]); - }); -}); diff --git a/src/vs/languages/html/common/OSSREADME.json b/src/vs/languages/html/common/OSSREADME.json deleted file mode 100644 index 7472b3af58e302a2fe3ba02249debadbcf0c3063..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/OSSREADME.json +++ /dev/null @@ -1,88 +0,0 @@ -// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: -[{ - "name": "HTML 5.1 W3C Working Draft", - "version": "08 October 2015", - "license": "W3C Document License", - "repositoryURL": "http://www.w3.org/TR/2015/WD-html51-20151008/", - "licenseDetail": [ - "Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes material copied ", - "from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.)", - "", - "THIS DOCUMENT IS PROVIDED \"AS IS,\" AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT ", - "NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF ", - "THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY ", - "PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.", - "", - "COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE ", - "DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF.", - "", - "The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to this document or its contents", - "without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders." - ] -}, -{ - "name": "Ionic documentation", - "version": "1.2.4", - "license": "Apache2", - "repositoryURL": "https://github.com/driftyco/ionic-site", - "licenseDetail": [ - "Copyright Drifty Co. http://drifty.com/.", - "", - "Apache License", - "", - "Version 2.0, January 2004", - "", - "http://www.apache.org/licenses/", - "", - "TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION", - "", - "1. Definitions.", - "", - "\"License\" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.", - "", - "\"Licensor\" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.", - "", - "\"Legal Entity\" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, \"control\" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.", - "", - "\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions granted by this License.", - "", - "\"Source\" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.", - "", - "\"Object\" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.", - "", - "\"Work\" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).", - "", - "\"Derivative Works\" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.", - "", - "\"Contribution\" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, \"submitted\" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as \"Not a Contribution.\"", - "", - "\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.", - "", - "2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.", - "", - "3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.", - "", - "4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:", - "", - "You must give any other recipients of the Work or Derivative Works a copy of this License; and", - "", - "You must cause any modified files to carry prominent notices stating that You changed the files; and", - "", - "You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and", - "", - "If the Work includes a \"NOTICE\" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.", - "", - "5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.", - "", - "6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.", - "", - "7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.", - "", - "8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.", - "", - "9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.", - "", - "END OF TERMS AND CONDITIONS" - ] -} -] diff --git a/src/vs/languages/html/common/html.contribution.ts b/src/vs/languages/html/common/html.contribution.ts deleted file mode 100644 index 04bbde21217a05765ef5e1e29fb1fbc4d6e2a7ff..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/html.contribution.ts +++ /dev/null @@ -1,102 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; -import nls = require('vs/nls'); -import platform = require('vs/platform/platform'); -import ConfigurationRegistry = require('vs/platform/configuration/common/configurationRegistry'); - -ModesRegistry.registerCompatMode({ - id: 'html', - extensions: ['.html', '.htm', '.shtml', '.xhtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm'], - aliases: ['HTML', 'htm', 'html', 'xhtml'], - mimetypes: ['text/html', 'text/x-jshtm', 'text/template', 'text/ng-template'], - moduleId: 'vs/languages/html/common/html', - ctorName: 'HTMLMode', - deps: ['text/css', 'text/javascript'] -}); - -var configurationRegistry = platform.Registry.as(ConfigurationRegistry.Extensions.Configuration); - -export interface IHTMLFormatConfiguration { - wrapLineLength: number; - unformatted: string; - indentInnerHtml: boolean; - preserveNewLines: boolean; - maxPreserveNewLines: number; - indentHandlebars: boolean; - endWithNewline: boolean; - extraLiners: string; -} - -export interface IHTMLConfiguration { - format: IHTMLFormatConfiguration; - suggest: {[providerId:string]:boolean}; -} - -configurationRegistry.registerConfiguration({ - 'id': 'html', - 'order': 20, - 'type': 'object', - 'title': nls.localize('htmlConfigurationTitle', "HTML"), - 'properties': { - 'html.format.wrapLineLength': { - 'type': 'integer', - 'default': 120, - 'description': nls.localize('format.wrapLineLength', "Maximum amount of characters per line (0 = disable)."), - }, - 'html.format.unformatted': { - 'type': ['string', 'null'], - 'default': 'a, abbr, acronym, b, bdo, big, br, button, cite, code, dfn, em, i, img, input, kbd, label, map, object, q, samp, script, select, small, span, strong, sub, sup, textarea, tt, var', - 'description': nls.localize('format.unformatted', "List of tags, comma separated, that shouldn't be reformatted. 'null' defaults to all tags listed at https://www.w3.org/TR/html5/dom.html#phrasing-content."), - }, - 'html.format.indentInnerHtml': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('format.indentInnerHtml', "Indent and sections."), - }, - 'html.format.preserveNewLines': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('format.preserveNewLines', "Whether existing line breaks before elements should be preserved. Only works before elements, not inside tags or for text."), - }, - 'html.format.maxPreserveNewLines': { - 'type': ['number', 'null'], - 'default': null, - 'description': nls.localize('format.maxPreserveNewLines', "Maximum number of line breaks to be preserved in one chunk. Use 'null' for unlimited."), - }, - 'html.format.indentHandlebars': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('format.indentHandlebars', "Format and indent {{#foo}} and {{/foo}}."), - }, - 'html.format.endWithNewline': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('format.endWithNewline', "End with a newline."), - }, - 'html.format.extraLiners': { - 'type': ['string', 'null'], - 'default': 'head, body, /html', - 'description': nls.localize('format.extraLiners', "List of tags, comma separated, that should have an extra newline before them. 'null' defaults to \"head, body, /html\"."), - }, -'html.suggest.angular1': { - 'type': ['boolean'], - 'default': true, - 'description': nls.localize('suggest.angular1', "Configures if the built-in HTML language support suggests Angular V1 tags and properties."), -}, -'html.suggest.ionic': { - 'type': ['boolean'], - 'default': true, - 'description': nls.localize('suggest.ionic', "Configures if the built-in HTML language support suggests Ionic tags, properties and values."), -}, -'html.suggest.html5': { - 'type': ['boolean'], - 'default': true, - 'description': nls.localize('suggest.html5', "Configures if the built-in HTML language support suggests HTML5 tags, properties and values."), -}, - } -}); diff --git a/src/vs/languages/html/common/html.ts b/src/vs/languages/html/common/html.ts deleted file mode 100644 index 0faa53bae8e97cf9561120a6b6116f0d483d85a4..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/html.ts +++ /dev/null @@ -1,473 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 URI from 'vs/base/common/uri'; -import winjs = require('vs/base/common/winjs.base'); -import editorCommon = require('vs/editor/common/editorCommon'); -import modes = require('vs/editor/common/modes'); -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import { CompatMode, createWordRegExp, ModeWorkerManager } from 'vs/editor/common/modes/abstractMode'; -import { AbstractState } from 'vs/editor/common/modes/abstractState'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import * as htmlTokenTypes from 'vs/languages/html/common/htmlTokenTypes'; -import {EMPTY_ELEMENTS} from 'vs/languages/html/common/htmlEmptyTagsShared'; -import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {TokenizationSupport, IModeLocator, ILeavingNestedModeData, ITokenizationCustomization} from 'vs/editor/common/modes/supports/tokenizationSupport'; -import {wireCancellationToken} from 'vs/base/common/async'; -import {ICompatWorkerService, CompatWorkerAttr} from 'vs/editor/common/services/compatWorkerService'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {IHTMLConfiguration} from 'vs/languages/html/common/html.contribution'; -import {CharCode} from 'vs/base/common/charCode'; - -export { htmlTokenTypes }; // export to be used by Razor. We are the main module, so Razor should get it from us. -export { EMPTY_ELEMENTS }; // export to be used by Razor. We are the main module, so Razor should get it from us. - -export enum States { - Content, - OpeningStartTag, - OpeningEndTag, - WithinDoctype, - WithinTag, - WithinComment, - WithinEmbeddedContent, - AttributeName, - AttributeValue -} - -// list of elements that embed other content -var tagsEmbeddingContent:string[] = ['script', 'style']; - - - -export class State extends AbstractState { - public kind:States; - public lastTagName:string; - public lastAttributeName:string; - public embeddedContentType:string; - public attributeValueQuote:string; - public attributeValueLength:number; - - constructor(modeId:string, kind:States, lastTagName:string, lastAttributeName:string, embeddedContentType:string, attributeValueQuote:string, attributeValueLength:number) { - super(modeId); - this.kind = kind; - this.lastTagName = lastTagName; - this.lastAttributeName = lastAttributeName; - this.embeddedContentType = embeddedContentType; - this.attributeValueQuote = attributeValueQuote; - this.attributeValueLength = attributeValueLength; - } - - static escapeTagName(s:string):string { - return htmlTokenTypes.getTag(s.replace(/[:_.]/g, '-')); - } - - public makeClone():State { - return new State(this.getModeId(), this.kind, this.lastTagName, this.lastAttributeName, this.embeddedContentType, this.attributeValueQuote, this.attributeValueLength); - } - - public equals(other:modes.IState):boolean { - if (other instanceof State) { - return ( - super.equals(other) && - this.kind === other.kind && - this.lastTagName === other.lastTagName && - this.lastAttributeName === other.lastAttributeName && - this.embeddedContentType === other.embeddedContentType && - this.attributeValueQuote === other.attributeValueQuote && - this.attributeValueLength === other.attributeValueLength - ); - } - return false; - } - - private nextElementName(stream:modes.IStream):string { - return stream.advanceIfRegExp(/^[_:\w][_:\w-.\d]*/).toLowerCase(); - } - - private nextAttributeName(stream:modes.IStream):string { - return stream.advanceIfRegExp(/^[^\s"'>/=\x00-\x0F\x7F\x80-\x9F]*/).toLowerCase(); - } - - public tokenize(stream:modes.IStream) : modes.ITokenizationResult { - - switch(this.kind){ - case States.WithinComment: - if (stream.advanceUntilString2('-->', false)) { - return { type: htmlTokenTypes.COMMENT}; - - } else if(stream.advanceIfString2('-->')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_COMMENT, dontMergeWithPrev: true }; - } - break; - - case States.WithinDoctype: - if (stream.advanceUntilString2('>', false)) { - return { type: htmlTokenTypes.DOCTYPE}; - } else if(stream.advanceIfString2('>')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_DOCTYPE, dontMergeWithPrev: true }; - } - break; - - case States.Content: - if (stream.advanceIfCharCode2(CharCode.LessThan)) { - if (!stream.eos() && stream.peek() === '!') { - if (stream.advanceIfString2('!--')) { - this.kind = States.WithinComment; - return { type: htmlTokenTypes.DELIM_COMMENT, dontMergeWithPrev: true }; - } - if (stream.advanceIfStringCaseInsensitive2('!DOCTYPE')) { - this.kind = States.WithinDoctype; - return { type: htmlTokenTypes.DELIM_DOCTYPE, dontMergeWithPrev: true }; - } - } - if (stream.advanceIfCharCode2(CharCode.Slash)) { - this.kind = States.OpeningEndTag; - return { type: htmlTokenTypes.DELIM_END, dontMergeWithPrev: true }; - } - this.kind = States.OpeningStartTag; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } - break; - - case States.OpeningEndTag: - var tagName = this.nextElementName(stream); - if (tagName.length > 0){ - return { - type: State.escapeTagName(tagName), - }; - - } else if (stream.advanceIfString2('>')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_END, dontMergeWithPrev: true }; - - } else { - stream.advanceUntilString2('>', false); - return { type: '' }; - } - - case States.OpeningStartTag: - this.lastTagName = this.nextElementName(stream); - if (this.lastTagName.length > 0) { - this.lastAttributeName = null; - if ('script' === this.lastTagName || 'style' === this.lastTagName) { - this.lastAttributeName = null; - this.embeddedContentType = null; - } - this.kind = States.WithinTag; - return { - type: State.escapeTagName(this.lastTagName), - }; - } - break; - - case States.WithinTag: - if (stream.skipWhitespace2() || stream.eos()) { - this.lastAttributeName = ''; // remember that we have seen a whitespace - return { type: '' }; - } else { - if (this.lastAttributeName === '') { - var name = this.nextAttributeName(stream); - if (name.length > 0) { - this.lastAttributeName = name; - this.kind = States.AttributeName; - return { type: htmlTokenTypes.ATTRIB_NAME }; - } - } - if (stream.advanceIfString2('/>')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } - if (stream.advanceIfCharCode2(CharCode.GreaterThan)) { - if (tagsEmbeddingContent.indexOf(this.lastTagName) !== -1) { - this.kind = States.WithinEmbeddedContent; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } else { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } - } else { - stream.next2(); - return { type: '' }; - } - } - - case States.AttributeName: - if (stream.skipWhitespace2() || stream.eos()){ - return { type: '' }; - } - - if (stream.advanceIfCharCode2(CharCode.Equals)) { - this.kind = States.AttributeValue; - return { type: htmlTokenTypes.DELIM_ASSIGN }; - } else { - this.kind = States.WithinTag; - this.lastAttributeName = ''; - return this.tokenize(stream); // no advance yet - jump to WithinTag - } - - case States.AttributeValue: - if (stream.eos()) { - return { type: '' }; - } - if(stream.skipWhitespace2()) { - if (this.attributeValueQuote === '"' || this.attributeValueQuote === '\'') { - // We are inside the quotes of an attribute value - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - return { type: '' }; - } - // We are in a attribute value - if (this.attributeValueQuote === '"' || this.attributeValueQuote === '\'') { - - if (this.attributeValueLength === 1 && ('script' === this.lastTagName || 'style' === this.lastTagName) && 'type' === this.lastAttributeName) { - let attributeValue = stream.advanceUntilString(this.attributeValueQuote, true); - if (attributeValue.length > 0) { - this.embeddedContentType = this.unquote(attributeValue); - this.kind = States.WithinTag; - this.attributeValueLength = 0; - this.attributeValueQuote = ''; - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - } else { - if (stream.advanceIfCharCode2(this.attributeValueQuote.charCodeAt(0))) { - this.kind = States.WithinTag; - this.attributeValueLength = 0; - this.attributeValueQuote = ''; - this.lastAttributeName = null; - } else { - stream.next(); - this.attributeValueLength++; - } - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - } else { - let attributeValue = stream.advanceIfRegExp(/^[^\s"'`=<>]+/); - if (attributeValue.length > 0) { - this.kind = States.WithinTag; - this.lastAttributeName = null; - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - var ch = stream.peek(); - if (ch === '\'' || ch === '"') { - this.attributeValueQuote = ch; - this.attributeValueLength = 1; - stream.next2(); - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } else { - this.kind = States.WithinTag; - this.lastAttributeName = null; - return this.tokenize(stream); // no advance yet - jump to WithinTag - } - } - } - - stream.next2(); - this.kind = States.Content; - return { type: '' }; - } - - private unquote(value:string):string { - var start = 0; - var end = value.length; - if ('"' === value[0]) { - start++; - } - if ('"' === value[end - 1]) { - end--; - } - return value.substring(start, end); - } -} - -export class HTMLMode extends CompatMode implements ITokenizationCustomization { - - public static LANG_CONFIG:LanguageConfiguration = { - wordPattern: createWordRegExp('#-?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['<', '>'], - ], - - __electricCharacterSupport: { - embeddedElectricCharacters: ['*', '}', ']', ')'] - }, - - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - surroundingPairs: [ - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - onEnterRules: [ - { - beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i, - action: { indentAction: modes.IndentAction.IndentOutdent } - }, - { - beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - action: { indentAction: modes.IndentAction.Indent } - } - ], - }; - - protected _modeService:IModeService; - private _modeWorkerManager: ModeWorkerManager; - - constructor( - descriptor:modes.IModeDescriptor, - @IInstantiationService instantiationService: IInstantiationService, - @IModeService modeService: IModeService, - @ICompatWorkerService compatWorkerService: ICompatWorkerService, - @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IConfigurationService private configurationService: IConfigurationService - ) { - super(descriptor.id, compatWorkerService); - this._modeWorkerManager = this._createModeWorkerManager(descriptor, instantiationService); - - this._modeService = modeService; - - if (this.compatWorkerService && this.compatWorkerService.isInMainThread) { - let updateConfiguration = () => { - let opts = configurationService.getConfiguration('html'); - this._configureWorker(opts); - }; - configurationService.onDidUpdateConfiguration((e) => updateConfiguration()); - updateConfiguration(); - } - - this._registerSupports(); - } - - protected _registerSupports(): void { - if (this.getId() !== 'html') { - throw new Error('This method must be overwritten!'); - } - - modes.SuggestRegistry.register(this.getId(), { - triggerCharacters: ['.', ':', '<', '"', '=', '/'], - provideCompletionItems: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideCompletionItems(model.uri, position)); - } - }, true); - - modes.DocumentHighlightProviderRegistry.register(this.getId(), { - provideDocumentHighlights: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentHighlights(model.uri, position)); - } - }, true); - - modes.DocumentRangeFormattingEditProviderRegistry.register(this.getId(), { - provideDocumentRangeFormattingEdits: (model, range, options, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentRangeFormattingEdits(model.uri, range, options)); - } - }, true); - - modes.LinkProviderRegistry.register(this.getId(), { - provideLinks: (model, token): Thenable => { - return wireCancellationToken(token, this.provideLinks(model.uri)); - } - }, true); - - LanguageConfigurationRegistry.register(this.getId(), HTMLMode.LANG_CONFIG); - - modes.TokenizationRegistry.register(this.getId(), new TokenizationSupport(this._modeService, this.getId(), this, true)); - } - - protected _createModeWorkerManager(descriptor:modes.IModeDescriptor, instantiationService: IInstantiationService): ModeWorkerManager { - return new ModeWorkerManager(descriptor, 'vs/languages/html/common/htmlWorker', 'HTMLWorker', null, instantiationService); - } - - private _worker(runner:(worker:W)=>winjs.TPromise): winjs.TPromise { - return this._modeWorkerManager.worker(runner); - } - - // TokenizationSupport - - public getInitialState():modes.IState { - return new State(this.getId(), States.Content, '', '', '', '', 0); - } - - public enterNestedMode(state:modes.IState):boolean { - return state instanceof State && (state).kind === States.WithinEmbeddedContent; - } - - public getNestedMode(state:modes.IState, locator:IModeLocator): modes.IMode { - let htmlState:State = state; - if (htmlState.embeddedContentType !== null) { - return locator.getMode(htmlState.embeddedContentType); - } - if ('script' === htmlState.lastTagName) { - return locator.getMode('text/javascript'); - } - if ('style' === htmlState.lastTagName) { - return locator.getMode('text/css'); - } - return null; - } - - public getLeavingNestedModeData(line:string, state:modes.IState):ILeavingNestedModeData { - var tagName = (state).lastTagName; - var regexp = new RegExp('<\\/' + tagName + '\\s*>', 'i'); - var match:any = regexp.exec(line); - if (match !== null) { - return { - nestedModeBuffer: line.substring(0, match.index), - bufferAfterNestedMode: line.substring(match.index), - stateAfterNestedMode: new State(this.getId(), States.Content, '', '', '', '', 0) - }; - } - return null; - } - - static $_configureWorker = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._configureWorker); - private _configureWorker(options:any): winjs.TPromise { - return this._worker((w) => w._doConfigure(options)); - } - - protected provideLinks(resource:URI):winjs.TPromise { - let workspace = this.workspaceContextService.getWorkspace(); - let workspaceResource = workspace ? workspace.resource : null; - return this._provideLinks(resource, workspaceResource); - } - - static $_provideLinks = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideLinks); - private _provideLinks(resource:URI, workspaceResource:URI):winjs.TPromise { - return this._worker((w) => w.provideLinks(resource, workspaceResource)); - } - - static $_provideDocumentRangeFormattingEdits = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideDocumentRangeFormattingEdits); - private _provideDocumentRangeFormattingEdits(resource:URI, range:editorCommon.IRange, options:modes.FormattingOptions):winjs.TPromise { - return this._worker((w) => w.provideDocumentRangeFormattingEdits(resource, range, options)); - } - - static $_provideDocumentHighlights = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideDocumentHighlights); - protected _provideDocumentHighlights(resource:URI, position:editorCommon.IPosition, strict:boolean = false): winjs.TPromise { - return this._worker((w) => w.provideDocumentHighlights(resource, position, strict)); - } - - static $_provideCompletionItems = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideCompletionItems); - protected _provideCompletionItems(resource:URI, position:editorCommon.IPosition):winjs.TPromise { - return this._worker((w) => w.provideCompletionItems(resource, position)); - } - -} diff --git a/src/vs/languages/html/common/htmlEmptyTagsShared.ts b/src/vs/languages/html/common/htmlEmptyTagsShared.ts deleted file mode 100644 index 112868dad306487d4989ba17431299b0029130e5..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/htmlEmptyTagsShared.ts +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import arrays = require('vs/base/common/arrays'); - -export const EMPTY_ELEMENTS:string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr']; - -export function isEmptyElement(e: string) : boolean { - return arrays.binarySearch(EMPTY_ELEMENTS, e,(s1: string, s2: string) => s1.localeCompare(s2)) >= 0; -} diff --git a/src/vs/languages/html/common/htmlScanner.ts b/src/vs/languages/html/common/htmlScanner.ts deleted file mode 100644 index f1b6b76832f4106292ca209858f8816ba072b855..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/htmlScanner.ts +++ /dev/null @@ -1,142 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 {isTag, DELIM_END, DELIM_START, DELIM_ASSIGN, ATTRIB_NAME, ATTRIB_VALUE} from 'vs/languages/html/common/htmlTokenTypes'; - -import EditorCommon = require('vs/editor/common/editorCommon'); - -export interface IHTMLScanner { - getTokenType(): string; - isOpenBrace(): boolean; - isAtTokenStart(): boolean; - isAtTokenEnd(): boolean; - getTokenContent(): string; - scanBack() : boolean; - scanForward() : boolean; - getTokenPosition(): EditorCommon.IPosition; - getTokenRange(): EditorCommon.IRange; - getModel(): EditorCommon.ITokenizedModel; -} - -function isDelimiter(tokenType: string) { - switch (tokenType) { - case DELIM_START: - case DELIM_END: - case DELIM_ASSIGN: - return true; - } - return false; -} - -function isInterestingToken(tokenType: string) { - switch (tokenType) { - case DELIM_START: - case DELIM_END: - case DELIM_ASSIGN: - case ATTRIB_NAME: - case ATTRIB_VALUE: - return true; - } - return isTag(tokenType); -} - -export function getScanner(model: EditorCommon.ITokenizedModel, position:EditorCommon.IPosition) : IHTMLScanner { - - var lineOffset = position.column - 1; - var currentLine = position.lineNumber; - - var tokens = model.getLineTokens(currentLine); - var lineContent = model.getLineContent(currentLine); - var tokenIndex = tokens.findTokenIndexAtOffset(lineOffset); - var tokensOnLine = tokens.getTokenCount(); - - var tokenType = tokens.getTokenType(tokenIndex); - var tokenStart = tokens.getTokenStartOffset(tokenIndex); - var tokenEnd = tokens.getTokenEndOffset(tokenIndex); - - if ((tokenType === '' || isDelimiter(tokenType)) && tokenStart === lineOffset) { - tokenIndex--; - if (tokenIndex >= 0) { - // we are at the end of a different token - tokenType = tokens.getTokenType(tokenIndex); - tokenStart = tokens.getTokenStartOffset(tokenIndex); - tokenEnd = tokens.getTokenEndOffset(tokenIndex); - } else { - tokenType = ''; - tokenStart = tokenEnd = 0; - } - } - - return { - getTokenType: () => tokenType, - isAtTokenEnd: () => lineOffset === tokenEnd, - isAtTokenStart: () => lineOffset === tokenStart, - getTokenContent: () => lineContent.substring(tokenStart, tokenEnd), - isOpenBrace: () => tokenStart < tokenEnd && lineContent.charAt(tokenStart) === '<', - getTokenPosition: () => { lineNumber: currentLine, column: tokenStart + 1 }, - getTokenRange: () => { startLineNumber: currentLine, startColumn: tokenStart + 1, endLineNumber: currentLine, endColumn: tokenEnd + 1 }, - getModel: () => model, - scanBack: () => { - if (currentLine <= 0) { - return false; - } - - tokenIndex--; - do { - while (tokenIndex >= 0) { - tokenType = tokens.getTokenType(tokenIndex); - tokenStart = tokens.getTokenStartOffset(tokenIndex); - tokenEnd = tokens.getTokenEndOffset(tokenIndex); - - if (isInterestingToken(tokenType)) { - return true; - } - tokenIndex--; - } - currentLine--; - if (currentLine > 0) { - tokens = model.getLineTokens(currentLine); - lineContent = model.getLineContent(currentLine); - tokensOnLine = tokens.getTokenCount(); - tokenIndex = tokensOnLine - 1; - } - } while (currentLine > 0); - tokens = null; - tokenType = lineContent = ''; - tokenStart = tokenEnd = tokensOnLine = 0; - return false; - }, - scanForward: () => { - if (currentLine > model.getLineCount()) { - return false; - } - - tokenIndex++; - do { - while (tokenIndex < tokensOnLine) { - tokenType = tokens.getTokenType(tokenIndex); - tokenStart = tokens.getTokenStartOffset(tokenIndex); - tokenEnd = tokens.getTokenEndOffset(tokenIndex); - - if (isInterestingToken(tokenType)) { - return true; - } - tokenIndex++; - } - currentLine++; - tokenIndex = 0; - if (currentLine <= model.getLineCount()) { - tokens = model.getLineTokens(currentLine); - lineContent = model.getLineContent(currentLine); - tokensOnLine = tokens.getTokenCount(); - } - } while (currentLine <= model.getLineCount()); - tokenType = lineContent = ''; - tokenStart = tokenEnd = tokensOnLine = 0; - return false; - } - }; -} \ No newline at end of file diff --git a/src/vs/languages/html/common/htmlTags.ts b/src/vs/languages/html/common/htmlTags.ts deleted file mode 100644 index 5ed5d206960b6e3b5c1f037818bcc8bf01b9809c..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/htmlTags.ts +++ /dev/null @@ -1,628 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -/*! -BEGIN THIRD PARTY -*/ -/*-------------------------------------------------------------------------------------------- - * This file is based on or incorporates material from the projects listed below (Third Party IP). - * The original copyright notice and the license under which Microsoft received such Third Party IP, - * are set forth below. Such licenses and notices are provided for informational purposes only. - * Microsoft licenses the Third Party IP to you under the licensing terms for the Microsoft product. - * Microsoft reserves all other rights not expressly granted under this agreement, whether by implication, - * estoppel or otherwise. - *--------------------------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------------------------- - * Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes includes material copied - * from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.)" - *--------------------------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------------------------- - * Ionic Main Site (https://github.com/driftyco/ionic-site). - * Copyright Drifty Co. http://drifty.com/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED - * WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, - * MERCHANTABLITY OR NON-INFRINGEMENT. - * - * See the Apache Version 2.0 License for specific language governing permissions - * and limitations under the License. - *--------------------------------------------------------------------------------------------*/ - -import strings = require('vs/base/common/strings'); -import nls = require('vs/nls'); - -export interface IHTMLTagProvider { - getId(): string; - collectTags(collector: (tag: string, label: string) => void): void; - collectAttributes(tag: string, collector: (attribute: string, type: string) => void): void; - collectValues(tag: string, attribute: string, collector: (value: string) => void): void; -} - -export interface ITagSet { - [tag: string]: HTMLTagSpecification; -} - -export class HTMLTagSpecification { - constructor(public label: string, public attributes: string[] = []) { } -} - -interface IValueSets { - [tag: string]: string[]; -} - -// HTML tag information sourced from http://www.w3.org/TR/2015/WD-html51-20151008/ -export const HTML_TAGS: ITagSet = { - // The root element - html: new HTMLTagSpecification( - nls.localize('tags.html', 'The html element represents the root of an HTML document.'), - ['manifest']), - // Document metadata - head: new HTMLTagSpecification( - nls.localize('tags.head', 'The head element represents a collection of metadata for the Document.')), - title: new HTMLTagSpecification( - nls.localize('tags.title', 'The title element represents the document\'s title or name. Authors should use titles that identify their documents even when they are used out of context, for example in a user\'s history or bookmarks, or in search results. The document\'s title is often different from its first heading, since the first heading does not have to stand alone when taken out of context.')), - base: new HTMLTagSpecification( - nls.localize('tags.base', 'The base element allows authors to specify the document base URL for the purposes of resolving relative URLs, and the name of the default browsing context for the purposes of following hyperlinks. The element does not represent any content beyond this information.'), - ['href', 'target']), - link: new HTMLTagSpecification( - nls.localize('tags.link', 'The link element allows authors to link their document to other resources.'), - ['href', 'crossorigin:xo', 'rel', 'media', 'hreflang', 'type', 'sizes']), - meta: new HTMLTagSpecification( - nls.localize('tags.meta', 'The meta element represents various kinds of metadata that cannot be expressed using the title, base, link, style, and script elements.'), - ['name', 'http-equiv', 'content', 'charset']), - style: new HTMLTagSpecification( - nls.localize('tags.style', 'The style element allows authors to embed style information in their documents. The style element is one of several inputs to the styling processing model. The element does not represent content for the user.'), - ['media', 'nonce', 'type', 'scoped:v']), - // Sections - body: new HTMLTagSpecification( - nls.localize('tags.body', 'The body element represents the content of the document.'), - ['onafterprint', 'onbeforeprint', 'onbeforeunload', 'onhashchange', 'onlanguagechange', 'onmessage', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate', 'onstorage', 'onunload']), - article: new HTMLTagSpecification( - nls.localize('tags.article', 'The article element represents a complete, or self-contained, composition in a document, page, application, or site and that is, in principle, independently distributable or reusable, e.g. in syndication. This could be a forum post, a magazine or newspaper article, a blog entry, a user-submitted comment, an interactive widget or gadget, or any other independent item of content. Each article should be identified, typically by including a heading (h1–h6 element) as a child of the article element.')), - section: new HTMLTagSpecification( - nls.localize('tags.section', 'The section element represents a generic section of a document or application. A section, in this context, is a thematic grouping of content. Each section should be identified, typically by including a heading ( h1- h6 element) as a child of the section element.')), - nav: new HTMLTagSpecification( - nls.localize('tags.nav', 'The nav element represents a section of a page that links to other pages or to parts within the page: a section with navigation links.')), - aside: new HTMLTagSpecification( - nls.localize('tags.aside', 'The aside element represents a section of a page that consists of content that is tangentially related to the content around the aside element, and which could be considered separate from that content. Such sections are often represented as sidebars in printed typography.')), - h1: new HTMLTagSpecification( - nls.localize('tags.h1', 'The h1 element represents a section heading.')), - h2: new HTMLTagSpecification( - nls.localize('tags.h2', 'The h2 element represents a section heading.')), - h3: new HTMLTagSpecification( - nls.localize('tags.h3', 'The h3 element represents a section heading.')), - h4: new HTMLTagSpecification( - nls.localize('tags.h4', 'The h4 element represents a section heading.')), - h5: new HTMLTagSpecification( - nls.localize('tags.h5', 'The h5 element represents a section heading.')), - h6: new HTMLTagSpecification( - nls.localize('tags.h6', 'The h6 element represents a section heading.')), - header: new HTMLTagSpecification( - nls.localize('tags.header', 'The header element represents introductory content for its nearest ancestor sectioning content or sectioning root element. A header typically contains a group of introductory or navigational aids. When the nearest ancestor sectioning content or sectioning root element is the body element, then it applies to the whole page.')), - footer: new HTMLTagSpecification( - nls.localize('tags.footer', 'The footer element represents a footer for its nearest ancestor sectioning content or sectioning root element. A footer typically contains information about its section such as who wrote it, links to related documents, copyright data, and the like.')), - address: new HTMLTagSpecification( - nls.localize('tags.address', 'The address element represents the contact information for its nearest article or body element ancestor. If that is the body element, then the contact information applies to the document as a whole.')), - // Grouping content - p: new HTMLTagSpecification( - nls.localize('tags.p', 'The p element represents a paragraph.')), - hr: new HTMLTagSpecification( - nls.localize('tags.hr', 'The hr element represents a paragraph-level thematic break, e.g. a scene change in a story, or a transition to another topic within a section of a reference book.')), - pre: new HTMLTagSpecification( - nls.localize('tags.pre', 'The pre element represents a block of preformatted text, in which structure is represented by typographic conventions rather than by elements.')), - blockquote: new HTMLTagSpecification( - nls.localize('tags.blockquote', 'The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a footer or cite element, and optionally with in-line changes such as annotations and abbreviations.'), - ['cite']), - ol: new HTMLTagSpecification( - nls.localize('tags.ol', 'The ol element represents a list of items, where the items have been intentionally ordered, such that changing the order would change the meaning of the document.'), - ['reversed:v', 'start', 'type:lt']), - ul: new HTMLTagSpecification( - nls.localize('tags.ul', 'The ul element represents a list of items, where the order of the items is not important — that is, where changing the order would not materially change the meaning of the document.')), - li: new HTMLTagSpecification( - nls.localize('tags.li', 'The li element represents a list item. If its parent element is an ol, ul, or menu element, then the element is an item of the parent element\'s list, as defined for those elements. Otherwise, the list item has no defined list-related relationship to any other li element.'), - ['value']), - dl: new HTMLTagSpecification( - nls.localize('tags.dl', 'The dl element represents an association list consisting of zero or more name-value groups (a description list). A name-value group consists of one or more names (dt elements) followed by one or more values (dd elements), ignoring any nodes other than dt and dd elements. Within a single dl element, there should not be more than one dt element for each name.')), - dt: new HTMLTagSpecification( - nls.localize('tags.dt', 'The dt element represents the term, or name, part of a term-description group in a description list (dl element).')), - dd: new HTMLTagSpecification( - nls.localize('tags.dd', 'The dd element represents the description, definition, or value, part of a term-description group in a description list (dl element).')), - figure: new HTMLTagSpecification( - nls.localize('tags.figure', 'The figure element represents some flow content, optionally with a caption, that is self-contained (like a complete sentence) and is typically referenced as a single unit from the main flow of the document.')), - figcaption: new HTMLTagSpecification( - nls.localize('tags.figcaption', 'The figcaption element represents a caption or legend for the rest of the contents of the figcaption element\'s parent figure element, if any.')), - main: new HTMLTagSpecification( - nls.localize('tags.main', 'The main element represents the main content of the body of a document or application. The main content area consists of content that is directly related to or expands upon the central topic of a document or central functionality of an application.')), - div: new HTMLTagSpecification( - nls.localize('tags.div', 'The div element has no special meaning at all. It represents its children. It can be used with the class, lang, and title attributes to mark up semantics common to a group of consecutive elements.')), - // Text-level semantics - a: new HTMLTagSpecification( - nls.localize('tags.a', 'If the a element has an href attribute, then it represents a hyperlink (a hypertext anchor) labeled by its contents.'), - ['href', 'target', 'download', 'ping', 'rel', 'hreflang', 'type']), - em: new HTMLTagSpecification( - nls.localize('tags.em', 'The em element represents stress emphasis of its contents.')), - strong: new HTMLTagSpecification( - nls.localize('tags.strong', 'The strong element represents strong importance, seriousness, or urgency for its contents.')), - small: new HTMLTagSpecification( - nls.localize('tags.small', 'The small element represents side comments such as small print.')), - s: new HTMLTagSpecification( - nls.localize('tags.s', 'The s element represents contents that are no longer accurate or no longer relevant.')), - cite: new HTMLTagSpecification( - nls.localize('tags.cite', 'The cite element represents a reference to a creative work. It must include the title of the work or the name of the author(person, people or organization) or an URL reference, or a reference in abbreviated form as per the conventions used for the addition of citation metadata.')), - q: new HTMLTagSpecification( - nls.localize('tags.q', 'The q element represents some phrasing content quoted from another source.'), - ['cite']), - dfn: new HTMLTagSpecification( - nls.localize('tags.dfn', 'The dfn element represents the defining instance of a term. The paragraph, description list group, or section that is the nearest ancestor of the dfn element must also contain the definition(s) for the term given by the dfn element.')), - abbr: new HTMLTagSpecification( - nls.localize('tags.abbr', 'The abbr element represents an abbreviation or acronym, optionally with its expansion. The title attribute may be used to provide an expansion of the abbreviation. The attribute, if specified, must contain an expansion of the abbreviation, and nothing else.')), - ruby: new HTMLTagSpecification( - nls.localize('tags.ruby', 'The ruby element allows one or more spans of phrasing content to be marked with ruby annotations. Ruby annotations are short runs of text presented alongside base text, primarily used in East Asian typography as a guide for pronunciation or to include other annotations. In Japanese, this form of typography is also known as furigana. Ruby text can appear on either side, and sometimes both sides, of the base text, and it is possible to control its position using CSS. A more complete introduction to ruby can be found in the Use Cases & Exploratory Approaches for Ruby Markup document as well as in CSS Ruby Module Level 1. [RUBY-UC] [CSSRUBY]')), - rb: new HTMLTagSpecification( - nls.localize('tags.rb', 'The rb element marks the base text component of a ruby annotation. When it is the child of a ruby element, it doesn\'t represent anything itself, but its parent ruby element uses it as part of determining what it represents.')), - rt: new HTMLTagSpecification( - nls.localize('tags.rt', 'The rt element marks the ruby text component of a ruby annotation. When it is the child of a ruby element or of an rtc element that is itself the child of a ruby element, it doesn\'t represent anything itself, but its ancestor ruby element uses it as part of determining what it represents.')), - // is not yet supported by 2+ browsers - //rtc: new HTMLTagSpecification( - // nls.localize('tags.rtc', 'The rtc element marks a ruby text container for ruby text components in a ruby annotation. When it is the child of a ruby element it doesn\'t represent anything itself, but its parent ruby element uses it as part of determining what it represents.')), - rp: new HTMLTagSpecification( - nls.localize('tags.rp', 'The rp element is used to provide fallback text to be shown by user agents that don\'t support ruby annotations. One widespread convention is to provide parentheses around the ruby text component of a ruby annotation.')), - // is not yet supported by 2+ browsers - //data: new HTMLTagSpecification( - // nls.localize('tags.data', 'The data element represents its contents, along with a machine-readable form of those contents in the value attribute.')), - time: new HTMLTagSpecification( - nls.localize('tags.time', 'The time element represents its contents, along with a machine-readable form of those contents in the datetime attribute. The kind of content is limited to various kinds of dates, times, time-zone offsets, and durations, as described below.'), - ['datetime']), - code: new HTMLTagSpecification( - nls.localize('tags.code', 'The code element represents a fragment of computer code. This could be an XML element name, a file name, a computer program, or any other string that a computer would recognize.')), - var: new HTMLTagSpecification( - nls.localize('tags.var', 'The var element represents a variable. This could be an actual variable in a mathematical expression or programming context, an identifier representing a constant, a symbol identifying a physical quantity, a function parameter, or just be a term used as a placeholder in prose.')), - samp: new HTMLTagSpecification( - nls.localize('tags.samp', 'The samp element represents sample or quoted output from another program or computing system.')), - kbd: new HTMLTagSpecification( - nls.localize('tags.kbd', 'The kbd element represents user input (typically keyboard input, although it may also be used to represent other input, such as voice commands).')), - sub: new HTMLTagSpecification( - nls.localize('tags.sub', 'The sub element represents a subscript.')), - sup: new HTMLTagSpecification( - nls.localize('tags.sup', 'The sup element represents a superscript.')), - i: new HTMLTagSpecification( - nls.localize('tags.i', 'The i element represents a span of text in an alternate voice or mood, or otherwise offset from the normal prose in a manner indicating a different quality of text, such as a taxonomic designation, a technical term, an idiomatic phrase from another language, transliteration, a thought, or a ship name in Western texts.')), - b: new HTMLTagSpecification( - nls.localize('tags.b', 'The b element represents a span of text to which attention is being drawn for utilitarian purposes without conveying any extra importance and with no implication of an alternate voice or mood, such as key words in a document abstract, product names in a review, actionable words in interactive text-driven software, or an article lede.')), - u: new HTMLTagSpecification( - nls.localize('tags.u', 'The u element represents a span of text with an unarticulated, though explicitly rendered, non-textual annotation, such as labeling the text as being a proper name in Chinese text (a Chinese proper name mark), or labeling the text as being misspelt.')), - mark: new HTMLTagSpecification( - nls.localize('tags.mark', 'The mark element represents a run of text in one document marked or highlighted for reference purposes, due to its relevance in another context. When used in a quotation or other block of text referred to from the prose, it indicates a highlight that was not originally present but which has been added to bring the reader\'s attention to a part of the text that might not have been considered important by the original author when the block was originally written, but which is now under previously unexpected scrutiny. When used in the main prose of a document, it indicates a part of the document that has been highlighted due to its likely relevance to the user\'s current activity.')), - bdi: new HTMLTagSpecification( - nls.localize('tags.bdi', 'The bdi element represents a span of text that is to be isolated from its surroundings for the purposes of bidirectional text formatting. [BIDI]')), - bdo: new HTMLTagSpecification( - nls.localize('tags.dbo', 'The bdo element represents explicit text directionality formatting control for its children. It allows authors to override the Unicode bidirectional algorithm by explicitly specifying a direction override. [BIDI]')), - span: new HTMLTagSpecification( - nls.localize('tags.span', 'The span element doesn\'t mean anything on its own, but can be useful when used together with the global attributes, e.g. class, lang, or dir. It represents its children.')), - br: new HTMLTagSpecification( - nls.localize('tags.br', 'The br element represents a line break.')), - wbr: new HTMLTagSpecification( - nls.localize('tags.wbr', 'The wbr element represents a line break opportunity.')), - // Edits - ins: new HTMLTagSpecification( - nls.localize('tags.ins', 'The ins element represents an addition to the document.')), - del: new HTMLTagSpecification( - nls.localize('tags.del', 'The del element represents a removal from the document.'), - ['cite', 'datetime']), - // Embedded content - picture: new HTMLTagSpecification( - nls.localize('tags.picture', 'The picture element is a container which provides multiple sources to its contained img element to allow authors to declaratively control or give hints to the user agent about which image resource to use, based on the screen pixel density, viewport size, image format, and other factors. It represents its children.')), - img: new HTMLTagSpecification( - nls.localize('tags.img', 'An img element represents an image.'), - ['alt', 'src', 'srcset', 'crossorigin:xo', 'usemap', 'ismap:v', 'width', 'height']), - iframe: new HTMLTagSpecification( - nls.localize('tags.iframe', 'The iframe element represents a nested browsing context.'), - ['src', 'srcdoc', 'name', 'sandbox:sb', 'seamless:v', 'allowfullscreen:v', 'width', 'height']), - embed: new HTMLTagSpecification( - nls.localize('tags.embed', 'The embed element provides an integration point for an external (typically non-HTML) application or interactive content.'), - ['src', 'type', 'width', 'height']), - object: new HTMLTagSpecification( - nls.localize('tags.object', 'The object element can represent an external resource, which, depending on the type of the resource, will either be treated as an image, as a nested browsing context, or as an external resource to be processed by a plugin.'), - ['data', 'type', 'typemustmatch:v', 'name', 'usemap', 'form', 'width', 'height']), - param: new HTMLTagSpecification( - nls.localize('tags.param', 'The param element defines parameters for plugins invoked by object elements. It does not represent anything on its own.'), - ['name', 'value']), - video: new HTMLTagSpecification( - nls.localize('tags.video', 'A video element is used for playing videos or movies, and audio files with captions.'), - ['src', 'crossorigin:xo', 'poster', 'preload:pl', 'autoplay:v', 'mediagroup', 'loop:v', 'muted:v', 'controls:v', 'width', 'height']), - audio: new HTMLTagSpecification( - nls.localize('tags.audio', 'An audio element represents a sound or audio stream.'), - ['src', 'crossorigin:xo', 'preload:pl', 'autoplay:v', 'mediagroup', 'loop:v', 'muted:v', 'controls:v']), - source: new HTMLTagSpecification( - nls.localize('tags.source', 'The source element allows authors to specify multiple alternative media resources for media elements. It does not represent anything on its own.'), - // 'When the source element has a parent that is a picture element, the source element allows authors to specify multiple alternative source sets for img elements.' - ['src', 'type']), - track: new HTMLTagSpecification( - nls.localize('tags.track', 'The track element allows authors to specify explicit external timed text tracks for media elements. It does not represent anything on its own.'), - ['default:v', 'kind:tk', 'label', 'src', 'srclang']), - map: new HTMLTagSpecification( - nls.localize('tags.map', 'The map element, in conjunction with an img element and any area element descendants, defines an image map. The element represents its children.'), - ['name']), - area: new HTMLTagSpecification( - nls.localize('tags.area', 'The area element represents either a hyperlink with some text and a corresponding area on an image map, or a dead area on an image map.'), - ['alt', 'coords', 'shape:sh', 'href', 'target', 'download', 'ping', 'rel', 'hreflang', 'type']), - // Tabular data - table: new HTMLTagSpecification( - nls.localize('tags.table', 'The table element represents data with more than one dimension, in the form of a table.'), - ['sortable:v', 'border']), - caption: new HTMLTagSpecification( - nls.localize('tags.caption', 'The caption element represents the title of the table that is its parent, if it has a parent and that is a table element.')), - colgroup: new HTMLTagSpecification( - nls.localize('tags.colgroup', 'The colgroup element represents a group of one or more columns in the table that is its parent, if it has a parent and that is a table element.'), - ['span']), - col: new HTMLTagSpecification( - nls.localize('tags.col', 'If a col element has a parent and that is a colgroup element that itself has a parent that is a table element, then the col element represents one or more columns in the column group represented by that colgroup.'), - ['span']), - tbody: new HTMLTagSpecification( - nls.localize('tags.tbody', 'The tbody element represents a block of rows that consist of a body of data for the parent table element, if the tbody element has a parent and it is a table.')), - thead: new HTMLTagSpecification( - nls.localize('tags.thead', 'The thead element represents the block of rows that consist of the column labels (headers) for the parent table element, if the thead element has a parent and it is a table.')), - tfoot: new HTMLTagSpecification( - nls.localize('tags.tfoot', 'The tfoot element represents the block of rows that consist of the column summaries (footers) for the parent table element, if the tfoot element has a parent and it is a table.')), - tr: new HTMLTagSpecification( - nls.localize('tags.tr', 'The tr element represents a row of cells in a table.')), - td: new HTMLTagSpecification( - nls.localize('tags.td', 'The td element represents a data cell in a table.'), - ['colspan', 'rowspan', 'headers']), - th: new HTMLTagSpecification( - nls.localize('tags.th', 'The th element represents a header cell in a table.'), - ['colspan', 'rowspan', 'headers', 'scope:s', 'sorted', 'abbr']), - // Forms - form: new HTMLTagSpecification( - nls.localize('tags.form', 'The form element represents a collection of form-associated elements, some of which can represent editable values that can be submitted to a server for processing.'), - ['accept-charset', 'action', 'autocomplete:o', 'enctype:et', 'method:m', 'name', 'novalidate:v', 'target']), - label: new HTMLTagSpecification( - nls.localize('tags.label', 'The label element represents a caption in a user interface. The caption can be associated with a specific form control, known as the label element\'s labeled control, either using the for attribute, or by putting the form control inside the label element itself.'), - ['form', 'for']), - input: new HTMLTagSpecification( - nls.localize('tags.input', 'The input element represents a typed data field, usually with a form control to allow the user to edit the data.'), - ['accept', 'alt', 'autocomplete:inputautocomplete', 'autofocus:v', 'checked:v', 'dirname', 'disabled:v', 'form', 'formaction', 'formenctype:et', 'formmethod:fm', 'formnovalidate:v', 'formtarget', 'height', 'inputmode:im', 'list', 'max', 'maxlength', 'min', 'minlength', 'multiple:v', 'name', 'pattern', 'placeholder', 'readonly:v', 'required:v', 'size', 'src', 'step', 'type:t', 'value', 'width']), - button: new HTMLTagSpecification( - nls.localize('tags.button', 'The button element represents a button labeled by its contents.'), - ['autofocus:v', 'disabled:v', 'form', 'formaction', 'formenctype:et', 'formmethod:fm', 'formnovalidate:v', 'formtarget', 'name', 'type:bt', 'value']), - select: new HTMLTagSpecification( - nls.localize('tags.select', 'The select element represents a control for selecting amongst a set of options.'), - ['autocomplete:inputautocomplete', 'autofocus:v', 'disabled:v', 'form', 'multiple:v', 'name', 'required:v', 'size']), - datalist: new HTMLTagSpecification( - nls.localize('tags.datalist', 'The datalist element represents a set of option elements that represent predefined options for other controls. In the rendering, the datalist element represents nothing and it, along with its children, should be hidden.')), - optgroup: new HTMLTagSpecification( - nls.localize('tags.optgroup', 'The optgroup element represents a group of option elements with a common label.'), - ['disabled:v', 'label']), - option: new HTMLTagSpecification( - nls.localize('tags.option', 'The option element represents an option in a select element or as part of a list of suggestions in a datalist element.'), - ['disabled:v', 'label', 'selected:v', 'value']), - textarea: new HTMLTagSpecification( - nls.localize('tags.textarea', 'The textarea element represents a multiline plain text edit control for the element\'s raw value. The contents of the control represent the control\'s default value.'), - ['autocomplete:inputautocomplete', 'autofocus:v', 'cols', 'dirname', 'disabled:v', 'form', 'inputmode:im', 'maxlength', 'minlength', 'name', 'placeholder', 'readonly:v', 'required:v', 'rows', 'wrap:w']), - output: new HTMLTagSpecification( - nls.localize('tags.output', 'The output element represents the result of a calculation performed by the application, or the result of a user action.'), - ['for', 'form', 'name']), - progress: new HTMLTagSpecification( - nls.localize('tags.progress', 'The progress element represents the completion progress of a task. The progress is either indeterminate, indicating that progress is being made but that it is not clear how much more work remains to be done before the task is complete (e.g. because the task is waiting for a remote host to respond), or the progress is a number in the range zero to a maximum, giving the fraction of work that has so far been completed.'), - ['value', 'max']), - meter: new HTMLTagSpecification( - nls.localize('tags.meter', 'The meter element represents a scalar measurement within a known range, or a fractional value; for example disk usage, the relevance of a query result, or the fraction of a voting population to have selected a particular candidate.'), - ['value', 'min', 'max', 'low', 'high', 'optimum']), - fieldset: new HTMLTagSpecification( - nls.localize('tags.fieldset', 'The fieldset element represents a set of form controls optionally grouped under a common name.'), - ['disabled:v', 'form', 'name']), - legend: new HTMLTagSpecification( - nls.localize('tags.legend', 'The legend element represents a caption for the rest of the contents of the legend element\'s parent fieldset element, if any.')), - // Interactive elements - details: new HTMLTagSpecification( - nls.localize('tags.details', 'The details element represents a disclosure widget from which the user can obtain additional information or controls.'), - ['open:v']), - summary: new HTMLTagSpecification( - nls.localize('tags.summary', 'The summary element represents a summary, caption, or legend for the rest of the contents of the summary element\'s parent details element, if any.')), - // and are not yet supported by 2+ browsers - //menu: new HTMLTagSpecification( - // nls.localize('tags.menu', 'The menu element represents a list of commands.'), - // ['type:mt', 'label']), - //menuitem: new HTMLTagSpecification( - // nls.localize('tags.menuitem', 'The menuitem element represents a command that the user can invoke from a popup menu (either a context menu or the menu of a menu button).')), - dialog: new HTMLTagSpecification( - nls.localize('tags.dialog', 'The dialog element represents a part of an application that a user interacts with to perform a task, for example a dialog box, inspector, or window.')), - // Scripting - script: new HTMLTagSpecification( - nls.localize('tags.script', 'The script element allows authors to include dynamic script and data blocks in their documents. The element does not represent content for the user.'), - ['src', 'type', 'charset', 'async:v', 'defer:v', 'crossorigin:xo', 'nonce']), - noscript: new HTMLTagSpecification( - nls.localize('tags.noscript', 'The noscript element represents nothing if scripting is enabled, and represents its children if scripting is disabled. It is used to present different markup to user agents that support scripting and those that don\'t support scripting, by affecting how the document is parsed.')), - template: new HTMLTagSpecification( - nls.localize('tags.template', 'The template element is used to declare fragments of HTML that can be cloned and inserted in the document by script.')), - canvas: new HTMLTagSpecification( - nls.localize('tags.canvas', 'The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, art, or other visual images on the fly.'), - ['width', 'height']) -}; - -// Ionic tag information sourced from Ionic main website (https://github.com/driftyco/ionic-site) -export const IONIC_TAGS: ITagSet = { - 'ion-checkbox': new HTMLTagSpecification(nls.localize('tags.ion.checkbox', 'The checkbox is no different than the HTML checkbox input, except it\'s styled differently. The checkbox behaves like any AngularJS checkbox.'), - ['name', 'ng-false-value', 'ng-model', 'ng-true-value']), - 'ion-content': new HTMLTagSpecification(nls.localize('tags.ion.content', 'The ionContent directive provides an easy to use content area that can be configured to use Ionic\'s custom Scroll View, or the built-in overflow scrolling of the browser.'), - ['delegate-handle', 'direction:scrolldir', 'has-bouncing:b', 'locking:b', 'on-scroll', 'on-scroll-complete', 'overflow-scroll:b', 'padding:b', 'scroll:b', 'scrollbar-x:b', 'scrollbar-y:b', 'start-x', 'start-y']), - 'ion-delete-button': new HTMLTagSpecification(nls.localize('tags.ion.deletebutton', 'Child of ionItem'), - []), - 'ion-footer-bar': new HTMLTagSpecification(nls.localize('tags.ion.footerbar', 'Adds a fixed footer bar below some content. Can also be a subfooter (higher up) if the "bar-subfooter" class is applied.'), - ['align-title:align', 'keyboard-attach:v']), - 'ion-header-bar': new HTMLTagSpecification(nls.localize('tags.ion.headerbar', 'Adds a fixed header bar above some content. Can also be a subheader (lower down) if the "bar-subheader" class is applied.'), - ['align-title:align', 'no-tap-scroll:b']), - 'ion-infinite-scroll': new HTMLTagSpecification(nls.localize('tags.ion.infinitescroll', 'Child of ionContent or ionScroll. The ionInfiniteScroll directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page.'), - ['distance', 'icon', 'immediate-check:b', 'on-infinite', 'spinner']), - 'ion-input': new HTMLTagSpecification(nls.localize('tags.ion.input', 'ionInput is meant for text type inputs only. Ionic uses an actual HTML element within the component, with Ionic wrapping to better handle the user experience and interactivity.'), - ['type:inputtype', 'clearInput:v']), - 'ion-item': new HTMLTagSpecification(nls.localize('tags.ion.item', 'Child of ionList.'), - []), - 'ion-list': new HTMLTagSpecification(nls.localize('tags.ion.list', 'The List is a widely used interface element in almost any mobile app, and can include content ranging from basic text all the way to buttons, toggles, icons, and thumbnails.'), - ['can-swipe:b', 'delegate-handle', 'show-delete:b', 'show-reorder:b', 'type:listtype']), - 'ion-modal-view': new HTMLTagSpecification(nls.localize('tags.ion.modalview', 'The Modal is a content pane that can go over the user\'s main view temporarily. Usually used for making a choice or editing an item.'), - []), - 'ion-nav-back-button': new HTMLTagSpecification(nls.localize('tags.ion.navbackbutton', 'Child of ionNavBar. Creates a back button inside an ionNavBar. The back button will appear when the user is able to go back in the current navigation stack.'), - []), - 'ion-nav-bar': new HTMLTagSpecification(nls.localize('tags.ion.navbar', 'If you have an ionNavView directive, you can also create an , which will create a topbar that updates as the application state changes.'), - ['align-title:align', 'delegate-handle', 'no-tap-scroll:b']), - 'ion-nav-buttons': new HTMLTagSpecification(nls.localize('tags.ion.navbuttons', 'Child of ionNavView. Use ionNavButtons to set the buttons on your ionNavBar from within an ionView.'), - ['side:navsides']), - 'ion-nav-title': new HTMLTagSpecification(nls.localize('tags.ion.navtitle', 'Child of ionNavView. The ionNavTitle directive replaces an ionNavBar title text with custom HTML from within an ionView template.'), - []), - 'ion-nav-view': new HTMLTagSpecification(nls.localize('tags.ion.navview', 'The ionNavView directive is used to render templates in your application. Each template is part of a state. States are usually mapped to a url, and are defined programatically using angular-ui-router.'), - ['name']), - 'ion-option-button': new HTMLTagSpecification(nls.localize('tags.ion.optionbutton', 'Child of ionItem. Creates an option button inside a list item, that is visible when the item is swiped to the left by the user.'), - []), - 'ion-pane': new HTMLTagSpecification(nls.localize('tags.ion.pane', 'A simple container that fits content, with no side effects. Adds the "pane" class to the element.'), - []), - 'ion-popover-view': new HTMLTagSpecification(nls.localize('tags.ion.popoverview', 'The Popover is a view that floats above an app\'s content. Popovers provide an easy way to present or gather information from the user.'), - []), - 'ion-radio': new HTMLTagSpecification(nls.localize('tags.ion.radio', 'The radio ionRirective is no different than the HTML radio input, except it\'s styled differently. The ionRadio behaves like AngularJS radio input.'), - ['disabled:b', 'icon', 'name', 'ng-disabled:b', 'ng-model', 'ng-value', 'value']), - 'ion-refresher': new HTMLTagSpecification(nls.localize('tags.ion.refresher', 'Child of ionContent or ionScroll. Allows you to add pull-to-refresh to a scrollView. Place it as the first child of your ionContent or ionScroll element.'), - ['disable-pulling-rotation:b', 'on-pulling', 'on-refresh', 'pulling-icon', 'pulling-text', 'refreshing-icon', 'spinner']), - 'ion-reorder-button': new HTMLTagSpecification(nls.localize('tags.ion.reorderbutton', 'Child of ionItem.'), - ['on-reorder']), - 'ion-scroll': new HTMLTagSpecification(nls.localize('tags.ion.scroll', 'Creates a scrollable container for all content inside.'), - ['delegate-handle', 'direction:scrolldir', 'has-bouncing:b', 'locking:b', 'max-zoom', 'min-zoom', 'on-refresh', 'on-scroll', 'paging:b', 'scrollbar-x:b', 'scrollbar-y:b', 'zooming:b']), - 'ion-side-menu': new HTMLTagSpecification(nls.localize('tags.ion.sidemenu', 'Child of ionSideMenus. A container for a side menu, sibling to an ionSideMenuContent directive.'), - ['is-enabled:b', 'expose-aside-when', 'side:navsides', 'width']), - 'ion-side-menu-content': new HTMLTagSpecification(nls.localize('tags.ion.sidemenucontent', 'Child of ionSideMenus. A container for the main visible content, sibling to one or more ionSideMenu directives.'), - ['drag-content:b', 'edge-drag-threshold']), - 'ion-side-menus': new HTMLTagSpecification(nls.localize('tags.ion.sidemenus', 'A container element for side menu(s) and the main content. Allows the left and/or right side menu to be toggled by dragging the main content area side to side.'), - ['delegate-handle', 'enable-menu-with-back-views:b']), - 'ion-slide': new HTMLTagSpecification(nls.localize('tags.ion.slide', 'Child of ionSlideBox. Displays a slide inside of a slidebox.'), - []), - 'ion-slide-box': new HTMLTagSpecification(nls.localize('tags.ion.slidebox', 'The Slide Box is a multi-page container where each page can be swiped or dragged between.'), - ['active-slide', 'auto-play:b', 'delegate-handle', 'does-continue:b', 'on-slide-changed', 'pager-click', 'show-pager:b', 'slide-interval']), - 'ion-spinner': new HTMLTagSpecification(nls.localize('tags.ion.spinner', 'The ionSpinner directive provides a variety of animated spinners.'), - ['icon']), - 'ion-tab': new HTMLTagSpecification(nls.localize('tags.ion.tab', 'Child of ionTabs. Contains a tab\'s content. The content only exists while the given tab is selected.'), - ['badge', 'badge-style', 'disabled', 'hidden', 'href', 'icon', 'icon-off', 'icon-on', 'ng-click', 'on-deselect', 'on-select', 'title']), - 'ion-tabs': new HTMLTagSpecification(nls.localize('tags.ion.tabs', 'Powers a multi-tabbed interface with a tab bar and a set of "pages" that can be tabbed through.'), - ['delegate-handle']), - 'ion-title': new HTMLTagSpecification(nls.localize('tags.ion.title', 'ion-title is a component that sets the title of the ionNavbar'), - []), - 'ion-toggle': new HTMLTagSpecification(nls.localize('tags.ion.toggle', 'A toggle is an animated switch which binds a given model to a boolean. Allows dragging of the switch\'s nub. The toggle behaves like any AngularJS checkbox otherwise.'), - ['name', 'ng-false-value', 'ng-model', 'ng-true-value', 'toggle-class']), - 'ion-view ': new HTMLTagSpecification(nls.localize('tags.ion.view', 'Child of ionNavView. A container for view content and any navigational and header bar information.'), - ['cache-view:b', 'can-swipe-back:b', 'hide-back-button:b', 'hide-nav-bar:b', 'view-title']) -}; - -export function getHTML5TagProvider(): IHTMLTagProvider { - var globalAttributes = [ - 'aria-activedescendant', 'aria-atomic:b', 'aria-autocomplete:autocomplete', 'aria-busy:b', 'aria-checked:tristate', 'aria-colcount', 'aria-colindex', 'aria-colspan', 'aria-controls', 'aria-current:current', 'aria-describedat', - 'aria-describedby', 'aria-disabled:b', 'aria-dropeffect:dropeffect', 'aria-errormessage', 'aria-expanded:u', 'aria-flowto', 'aria-grabbed:u', 'aria-haspopup:b', 'aria-hidden:b', 'aria-invalid:invalid', 'aria-kbdshortcuts', - 'aria-label', 'aria-labelledby', 'aria-level', 'aria-live:live', 'aria-modal:b', 'aria-multiline:b', 'aria-multiselectable:b', 'aria-orientation:orientation', 'aria-owns', 'aria-placeholder', 'aria-posinset', 'aria-pressed:tristate', - 'aria-readonly:b', 'aria-relevant:relevant', 'aria-required:b', 'aria-roledescription', 'aria-rowcount', 'aria-rowindex', 'aria-rowspan', 'aria-selected:u', 'aria-setsize', 'aria-sort:sort', 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', 'aria-valuetext', - 'accesskey', 'class', 'contenteditable:b', 'contextmenu', 'dir:d', 'draggable:b', 'dropzone', 'hidden:v', 'id', 'itemid', 'itemprop', 'itemref', 'itemscope:v', 'itemtype', 'lang', 'role:roles', 'spellcheck:b', 'style', 'tabindex', - 'title', 'translate:y']; - - var eventHandlers = ['onabort', 'onblur', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'oncontextmenu', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', - 'ondrop', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onfocus', 'onformchange', 'onforminput', 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onloadeddata', 'onloadedmetadata', - 'onloadstart', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onpause', 'onplay', 'onplaying', 'onprogress', 'onratechange', 'onreset', 'onresize', 'onreadystatechange', 'onscroll', - 'onseeked', 'onseeking', 'onselect', 'onshow', 'onstalled', 'onsubmit', 'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting']; - - var valueSets: IValueSets = { - b: ['true', 'false'], - u: ['true', 'false', 'undefined'], - o: ['on', 'off'], - y: ['yes', 'no'], - w: ['soft', 'hard'], - d: ['ltr', 'rtl', 'auto'], - m: ['GET', 'POST', 'dialog'], - fm: ['GET', 'POST'], - s: ['row', 'col', 'rowgroup', 'colgroup'], - t: ['hidden', 'text', 'search', 'tel', 'url', 'email', 'password', 'datetime', 'date', 'month', 'week', 'time', 'datetime-local', 'number', 'range', 'color', 'checkbox', 'radio', 'file', 'submit', 'image', 'reset', 'button'], - im: ['verbatim', 'latin', 'latin-name', 'latin-prose', 'full-width-latin', 'kana', 'kana-name', 'katakana', 'numeric', 'tel', 'email', 'url'], - bt: ['button', 'submit', 'reset', 'menu'], - lt: ['1', 'a', 'A', 'i', 'I'], - mt: ['context', 'toolbar'], - mit: ['command', 'checkbox', 'radio'], - et: ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'], - tk: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata'], - pl: ['none', 'metadata', 'auto'], - sh: ['circle', 'default', 'poly', 'rect'], - xo: ['anonymous', 'use-credentials'], - sb: ['allow-forms', 'allow-modals', 'allow-pointer-lock', 'allow-popups', 'allow-popups-to-escape-sandbox', 'allow-same-origin', 'allow-scripts', 'allow-top-navigation'], - tristate: ['true', 'false', 'mixed', 'undefined'], - inputautocomplete: ['additional-name', 'address-level1', 'address-level2', 'address-level3', 'address-level4', 'address-line1', 'address-line2', 'address-line3', 'bday', 'bday-year', 'bday-day', 'bday-month', 'billing', 'cc-additional-name', 'cc-csc', 'cc-exp', 'cc-exp-month', 'cc-exp-year', 'cc-family-name', 'cc-given-name', 'cc-name', 'cc-number', 'cc-type', 'country', 'country-name', 'current-password', 'email', 'family-name', 'fax', 'given-name', 'home', 'honorific-prefix', 'honorific-suffix', 'impp', 'language', 'mobile', 'name', 'new-password', 'nickname', 'organization', 'organization-title', 'pager', 'photo', 'postal-code', 'sex', 'shipping', 'street-address', 'tel-area-code', 'tel', 'tel-country-code', 'tel-extension', 'tel-local', 'tel-local-prefix', 'tel-local-suffix', 'tel-national', 'transaction-amount', 'transaction-currency', 'url', 'username', 'work'], - autocomplete: ['inline', 'list', 'both', 'none'], - current: ['page', 'step', 'location', 'date', 'time', 'true', 'false'], - dropeffect: ['copy', 'move', 'link', 'execute', 'popup', 'none'], - invalid: ['grammar', 'false', 'spelling', 'true'], - live: ['off', 'polite', 'assertive'], - orientation: ['vertical', 'horizontal', 'undefined'], - relevant: ['additions', 'removals', 'text', 'all', 'additions text'], - sort: ['ascending', 'descending', 'none', 'other'], - roles: ['alert', 'alertdialog', 'button', 'checkbox', 'dialog', 'gridcell', 'link', 'log', 'marquee', 'menuitem', 'menuitemcheckbox', 'menuitemradio', 'option', 'progressbar', 'radio', 'scrollbar', 'searchbox', 'slider', - 'spinbutton', 'status', 'switch', 'tab', 'tabpanel', 'textbox', 'timer', 'tooltip', 'treeitem', 'combobox', 'grid', 'listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid', - 'application', 'article', 'cell', 'columnheader', 'definition', 'directory', 'document', 'feed', 'figure', 'group', 'heading', 'img', 'list', 'listitem', 'math', 'none', 'note', 'presentation', 'region', 'row', 'rowgroup', - 'rowheader', 'separator', 'table', 'term', 'text', 'toolbar', - 'banner', 'complementary', 'contentinfo', 'form', 'main', 'navigation', 'region', 'search'] - }; - - return { - getId: () => 'html5', - collectTags: (collector: (tag: string, label: string) => void) => collectTagsDefault(collector, HTML_TAGS), - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - collectAttributesDefault(tag, collector, HTML_TAGS, globalAttributes); - eventHandlers.forEach(handler => { - collector(handler, 'event'); - }); - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => collectValuesDefault(tag, attribute, collector, HTML_TAGS, globalAttributes, valueSets) - }; -} - - -export function getAngularTagProvider(): IHTMLTagProvider { - var customTags: { [tag: string]: string[] } = { - input: ['ng-model', 'ng-required', 'ng-minlength', 'ng-maxlength', 'ng-pattern', 'ng-trim'], - select: ['ng-model'], - textarea: ['ng-model', 'ng-required', 'ng-minlength', 'ng-maxlength', 'ng-pattern', 'ng-trim'] - }; - - var globalAttributes = ['ng-app', 'ng-bind', 'ng-bind-html', 'ng-bind-template', 'ng-blur', 'ng-change', 'ng-checked', 'ng-class', 'ng-class-even', 'ng-class-odd', - 'ng-click', 'ng-cloak', 'ng-controller', 'ng-copy', 'ng-csp', 'ng-cut', 'ng-dblclick', 'ng-disabled', 'ng-focus', 'ng-form', 'ng-hide', 'ng-href', 'ng-if', - 'ng-include', 'ng-init', 'ng-jq', 'ng-keydown', 'ng-keypress', 'ng-keyup', 'ng-list', 'ng-model-options', 'ng-mousedown', 'ng-mouseenter', 'ng-mouseleave', - 'ng-mousemove', 'ng-mouseover', 'ng-mouseup', 'ng-non-bindable', 'ng-open', 'ng-options', 'ng-paste', 'ng-pluralize', 'ng-readonly', 'ng-repeat', 'ng-selected', - 'ng-show', 'ng-src', 'ng-srcset', 'ng-style', 'ng-submit', 'ng-switch', 'ng-transclude', 'ng-value' - ]; - - return { - getId: () => 'angular1', - collectTags: (collector: (tag: string) => void) => { - // no extra tags - }, - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - if (tag) { - var attributes = customTags[tag]; - if (attributes) { - attributes.forEach((a) => { - collector(a, null); - collector('data-' + a, null); - }); - } - } - globalAttributes.forEach((a) => { - collector(a, null); - collector('data-' + a, null); - }); - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => { - // no values - } - }; -} - -export function getIonicTagProvider(): IHTMLTagProvider { - var customTags: { [tag: string]: string[] } = { - a: ['nav-direction:navdir', 'nav-transition:trans'], - button: ['menu-toggle:menusides'] - }; - - var globalAttributes = ['collection-repeat', 'force-refresh-images:b', 'ion-stop-event', 'item-height', 'item-render-buffer', 'item-width', 'menu-close:v', - 'on-double-tap', 'on-drag', 'on-drag-down', 'on-drag-left', 'on-drag-right', 'on-drag-up', 'on-hold', 'on-release', 'on-swipe', 'on-swipe-down', 'on-swipe-left', - 'on-swipe-right', 'on-swipe-up', 'on-tap', 'on-touch']; - - var valueSets: IValueSets = { - align: ['center', 'left', 'right'], - b: ['true', 'false'], - inputtype: ['email', 'number', 'password', 'search', 'tel', 'text', 'url'], - listtype: ['card', 'list-inset'], - menusides: ['left', 'right'], - navdir: ['back', 'enter', 'exit', 'forward', 'swap'], - navsides: ['left', 'primary', 'right', 'secondary'], - scrolldir: ['x', 'xy', 'y'], - trans: ['android', 'ios', 'none'] - }; - - return { - getId: () => 'ionic', - collectTags: (collector: (tag: string, label: string) => void) => collectTagsDefault(collector, IONIC_TAGS), - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - collectAttributesDefault(tag, collector, IONIC_TAGS, globalAttributes); - if (tag) { - var attributes = customTags[tag]; - if (attributes) { - attributes.forEach((a) => { - var segments = a.split(':'); - collector(segments[0], segments[1]); - }); - } - } - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => collectValuesDefault(tag, attribute, collector, IONIC_TAGS, globalAttributes, valueSets, customTags) - }; -} - -function collectTagsDefault(collector: (tag: string, label: string) => void, tagSet: ITagSet): void { - for (var tag in tagSet) { - collector(tag, tagSet[tag].label); - } -} - -function collectAttributesDefault(tag: string, collector: (attribute: string, type: string) => void, tagSet: ITagSet, globalAttributes: string[]): void { - globalAttributes.forEach(attr => { - var segments = attr.split(':'); - collector(segments[0], segments[1]); - }); - if (tag) { - var tags = tagSet[tag]; - if (tags) { - var attributes = tags.attributes; - if (attributes) { - attributes.forEach(attr => { - var segments = attr.split(':'); - collector(segments[0], segments[1]); - }); - } - } - } -} - -function collectValuesDefault(tag: string, attribute: string, collector: (value: string) => void, tagSet: ITagSet, globalAttributes: string[], valueSets: IValueSets, customTags?: { [tag: string]: string[] }): void { - var prefix = attribute + ':'; - var processAttributes = (attributes: string[]) => { - attributes.forEach((attr) => { - if (attr.length > prefix.length && strings.startsWith(attr, prefix)) { - var typeInfo = attr.substr(prefix.length); - if (typeInfo === 'v') { - collector(attribute); - } else { - var values = valueSets[typeInfo]; - if (values) { - values.forEach(collector); - } - } - } - }); - }; - if (tag) { - var tags = tagSet[tag]; - if (tags) { - var attributes = tags.attributes; - if (attributes) { - processAttributes(attributes); - } - } - } - processAttributes(globalAttributes); - if (customTags) { - var customTagAttributes = customTags[tag]; - if (customTagAttributes) { - processAttributes(customTagAttributes); - } - } -} -/*! -END THIRD PARTY -*/ \ No newline at end of file diff --git a/src/vs/languages/html/common/htmlTokenTypes.ts b/src/vs/languages/html/common/htmlTokenTypes.ts deleted file mode 100644 index 9fecc05e85bbfddadbc588c1c081b0773ff350fe..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/htmlTokenTypes.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 strings = require('vs/base/common/strings'); - -export const DELIM_END = 'punctuation.definition.meta.tag.end.html'; -export const DELIM_START = 'punctuation.definition.meta.tag.begin.html'; -export const DELIM_ASSIGN = 'meta.tag.assign.html'; -export const ATTRIB_NAME = 'entity.other.attribute-name.html'; -export const ATTRIB_VALUE = 'string.html'; -export const COMMENT = 'comment.html.content'; -export const DELIM_COMMENT = 'comment.html'; -export const DOCTYPE = 'entity.other.attribute-name.html'; -export const DELIM_DOCTYPE = 'entity.name.tag.html'; - -const TAG_PREFIX = 'entity.name.tag.tag-'; - -export function isTag(tokenType: string) { - return strings.startsWith(tokenType, TAG_PREFIX); -} - -export function getTag(name: string) { - return TAG_PREFIX + name; -} \ No newline at end of file diff --git a/src/vs/languages/html/common/htmlWorker.ts b/src/vs/languages/html/common/htmlWorker.ts deleted file mode 100644 index 559c0daf443594d3353bd376d192b4ac7f2d4968..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/common/htmlWorker.ts +++ /dev/null @@ -1,609 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 URI from 'vs/base/common/uri'; -import winjs = require('vs/base/common/winjs.base'); -import beautifyHTML = require('vs/languages/lib/common/beautify-html'); -import htmlTags = require('vs/languages/html/common/htmlTags'); -import network = require('vs/base/common/network'); -import editorCommon = require('vs/editor/common/editorCommon'); -import modes = require('vs/editor/common/modes'); -import strings = require('vs/base/common/strings'); -import {IResourceService, ICompatMirrorModel} from 'vs/editor/common/services/resourceService'; -import {getScanner, IHTMLScanner} from 'vs/languages/html/common/htmlScanner'; -import {isTag, DELIM_END, DELIM_START, DELIM_ASSIGN, ATTRIB_NAME, ATTRIB_VALUE} from 'vs/languages/html/common/htmlTokenTypes'; -import {isEmptyElement} from 'vs/languages/html/common/htmlEmptyTagsShared'; -import {filterSuggestions} from 'vs/editor/common/modes/supports/suggestSupport'; -import paths = require('vs/base/common/paths'); -import {IHTMLConfiguration, IHTMLFormatConfiguration} from 'vs/languages/html/common/html.contribution'; -import {LineTokens} from 'vs/editor/common/core/lineTokens'; - -enum LinkDetectionState { - LOOKING_FOR_HREF_OR_SRC = 1, - AFTER_HREF_OR_SRC = 2 -} - -interface IColorRange { - range:editorCommon.IRange; - value:string; -} - -export class HTMLWorker { - - private resourceService:IResourceService; - private _modeId: string; - private _tagProviders: htmlTags.IHTMLTagProvider[]; - private _formatSettings: IHTMLFormatConfiguration; - private _providerConfiguration: {[providerId:string]:boolean}; - - constructor( - modeId: string, - @IResourceService resourceService: IResourceService - ) { - - this._modeId = modeId; - this.resourceService = resourceService; - - this._tagProviders = []; - this._tagProviders.push(htmlTags.getHTML5TagProvider()); - - this.addCustomTagProviders(this._tagProviders); - - this._providerConfiguration = null; - } - - protected addCustomTagProviders(providers: htmlTags.IHTMLTagProvider[]): void { - providers.push(htmlTags.getAngularTagProvider()); - providers.push(htmlTags.getIonicTagProvider()); - } - - private getTagProviders(): htmlTags.IHTMLTagProvider[] { - if (this._modeId !== 'html' || !this._providerConfiguration) { - return this._tagProviders; - } - return this._tagProviders.filter(p => !!this._providerConfiguration[p.getId()]); - } - - public provideDocumentRangeFormattingEdits(resource: URI, range: editorCommon.IRange, options: modes.FormattingOptions): winjs.TPromise { - return this.formatHTML(resource, range, options); - } - - private formatHTML(resource: URI, range: editorCommon.IRange, options: modes.FormattingOptions): winjs.TPromise { - let model = this.resourceService.get(resource); - let value = range ? model.getValueInRange(range) : model.getValue(); - - let htmlOptions : beautifyHTML.IBeautifyHTMLOptions = { - indent_size: options.insertSpaces ? options.tabSize : 1, - indent_char: options.insertSpaces ? ' ' : '\t', - wrap_line_length: this.getFormatOption('wrapLineLength', 120), - unformatted: this.getTagsFormatOption('unformatted', void 0), - indent_inner_html: this.getFormatOption('indentInnerHtml', false), - preserve_newlines: this.getFormatOption('preserveNewLines', false), - max_preserve_newlines: this.getFormatOption('maxPreserveNewLines', void 0), - indent_handlebars: this.getFormatOption('indentHandlebars', false), - end_with_newline: this.getFormatOption('endWithNewline', false), - extra_liners: this.getTagsFormatOption('extraLiners', void 0), - }; - - let result = beautifyHTML.html_beautify(value, htmlOptions); - - return winjs.TPromise.as([{ - range: range, - text: result - }]); - } - - private getFormatOption(key: string, dflt: any): any { - if (this._formatSettings && this._formatSettings.hasOwnProperty(key)) { - let value = this._formatSettings[key]; - if (value !== null) { - return value; - } - } - return dflt; - } - - private getTagsFormatOption(key: string, dflt: string[]): string[] { - let list = this.getFormatOption(key, null); - if (typeof list === 'string') { - if (list.length > 0) { - return list.split(',').map(t => t.trim().toLowerCase()); - } - return []; - } - return dflt; - } - - _doConfigure(options: IHTMLConfiguration): winjs.TPromise { - this._formatSettings = options && options.format; - if (options && options.suggest) { - this._providerConfiguration = options.suggest; - } - return winjs.TPromise.as(null); - } - - private findMatchingOpenTag(scanner: IHTMLScanner) : string { - let closedTags : { [name:string]: number } = {}; - let tagClosed = false; - while (scanner.scanBack()) { - if (isTag(scanner.getTokenType()) && !tagClosed) { - let tag = scanner.getTokenContent(); - scanner.scanBack(); - if (scanner.getTokenType() === DELIM_END) { - closedTags[tag] = (closedTags[tag] || 0) + 1; - } else if (!isEmptyElement(tag)) { - if (closedTags[tag]) { - closedTags[tag]--; - } else { - return tag; - } - } - } else if (scanner.getTokenType() === DELIM_START) { - tagClosed = scanner.getTokenContent() === '/>'; - } - } - return null; - } - - private collectTagSuggestions(scanner: IHTMLScanner, position: editorCommon.IPosition, suggestions: modes.ISuggestResult): void { - let model = scanner.getModel(); - let currentLine = model.getLineContent(position.lineNumber); - let contentAfter = currentLine.substr(position.column - 1); - let closeTag = isWhiteSpace(contentAfter) || strings.startsWith(contentAfter, '<') ? '>' : ''; - - let collectClosingTagSuggestion = (overwriteBefore: number) => { - let endPosition = scanner.getTokenPosition(); - let matchingTag = this.findMatchingOpenTag(scanner); - if (matchingTag) { - let suggestion : modes.ISuggestion = { - label: '/' + matchingTag, - insertText: '/' + matchingTag + closeTag, - overwriteBefore: overwriteBefore, - type: 'property' - }; - suggestions.suggestions.push(suggestion); - - // use indent from start tag - let startPosition = scanner.getTokenPosition(); - if (endPosition.lineNumber !== startPosition.lineNumber) { - let startIndent = model.getLineContent(startPosition.lineNumber).substring(0, startPosition.column - 1); - let endIndent = model.getLineContent(endPosition.lineNumber).substring(0, endPosition.column - 1); - if (isWhiteSpace(startIndent) && isWhiteSpace(endIndent)) { - suggestion.overwriteBefore = position.column - 1; // replace from start of line - suggestion.insertText = startIndent + ' { - provider.collectTags((tag, label) => { - suggestions.suggestions.push({ - label: '/' + tag, - overwriteBefore: suggestions.currentWord.length + 1, - insertText: '/' + tag + closeTag, - type: 'property', - documentation: label, - filterText: ' { - provider.collectTags((tag, label) => { - suggestions.suggestions.push({ - label: tag, - insertText: tag, - type: 'property', - documentation: label, - overwriteBefore: suggestions.currentWord.length - }); - }); - }); - } - - } - - private collectContentSuggestions(suggestions: modes.ISuggestResult): void { - // disable the simple snippets in favor of the emmet templates - } - - private collectAttributeSuggestions(scanner: IHTMLScanner, suggestions: modes.ISuggestResult): void { - let parentTag: string = null; - do { - if (isTag(scanner.getTokenType())) { - parentTag = scanner.getTokenContent(); - break; - } - if (scanner.getTokenType() === DELIM_START) { - break; - } - } while (scanner.scanBack()); - - this.getTagProviders().forEach((provider) => { - provider.collectAttributes(parentTag,(attribute, type) => { - let codeSnippet = attribute; - if (type !== 'v') { - codeSnippet = codeSnippet + '="{{}}"'; - } - suggestions.suggestions.push({ - label: attribute, - insertText: codeSnippet, - type: type === 'handler' ? 'function' : 'value', - overwriteBefore: suggestions.currentWord.length - }); - }); - }); - } - - private collectAttributeValueSuggestions(scanner: IHTMLScanner, suggestions: modes.ISuggestResult): void { - let needsQuotes = scanner.getTokenType() === DELIM_ASSIGN; - - let attribute: string = null; - let parentTag: string = null; - while (scanner.scanBack()) { - if (scanner.getTokenType() === ATTRIB_NAME) { - attribute = scanner.getTokenContent(); - break; - } - } - while (scanner.scanBack()) { - if (isTag(scanner.getTokenType())) { - parentTag = scanner.getTokenContent(); - break; - } - if (scanner.getTokenType() === DELIM_START) { - return; - } - } - - this.getTagProviders().forEach((provider) => { - provider.collectValues(parentTag, attribute,(value) => { - suggestions.suggestions.push({ - label: value, - insertText: needsQuotes ? '"' + value + '"' : value, - type: 'unit', - overwriteBefore: suggestions.currentWord.length - }); - }); - }); - } - - public provideCompletionItems(resource:URI, position:editorCommon.IPosition):winjs.TPromise { - let model = this.resourceService.get(resource); - let modeIdAtPosition = model.getModeIdAtPosition(position.lineNumber, position.column); - if (modeIdAtPosition === this._modeId) { - return this.suggestHTML(resource, position); - } - } - - private suggestHTML(resource:URI, position:editorCommon.IPosition):winjs.TPromise { - return this.doSuggest(resource, position).then(value => filterSuggestions(value)); - } - - private doSuggest(resource: URI, position: editorCommon.IPosition): winjs.TPromise { - - let model = this.resourceService.get(resource), - currentWord = model.getWordUntilPosition(position).word; - - let suggestions: modes.ISuggestResult = { - currentWord: currentWord, - suggestions: [], - }; - - let scanner = getScanner(model, position); - switch (scanner.getTokenType()) { - case DELIM_START: - case DELIM_END: - if (scanner.isOpenBrace()) { - this.collectTagSuggestions(scanner, position, suggestions); - } else { - this.collectContentSuggestions(suggestions); - } - break; - case ATTRIB_NAME: - this.collectAttributeSuggestions(scanner, suggestions); - break; - case ATTRIB_VALUE: - this.collectAttributeValueSuggestions(scanner, suggestions); - break; - case DELIM_ASSIGN: - if (scanner.isAtTokenEnd()) { - this.collectAttributeValueSuggestions(scanner, suggestions); - } - break; - case '': - if (isWhiteSpace(scanner.getTokenContent()) && scanner.scanBack()) { // go one back - switch (scanner.getTokenType()) { - case ATTRIB_VALUE: - case ATTRIB_NAME: - this.collectAttributeSuggestions(scanner, suggestions); - break; - case DELIM_ASSIGN: - this.collectAttributeValueSuggestions(scanner, suggestions); - break; - case DELIM_START: - case DELIM_END: - if (scanner.isOpenBrace()) { - this.collectTagSuggestions(scanner, position, suggestions); - } else { - this.collectContentSuggestions(suggestions); - } - break; - default: - if (isTag(scanner.getTokenType())) { - this.collectAttributeSuggestions(scanner, suggestions); - } - } - } else { - this.collectContentSuggestions(suggestions); - } - break; - default: - if (isTag(scanner.getTokenType())) { - scanner.scanBack(); // one back to the end/start bracket - this.collectTagSuggestions(scanner, position, suggestions); - } - } - return winjs.TPromise.as(suggestions); - } - - private findMatchingBracket(tagname: string, scanner: IHTMLScanner) : editorCommon.IRange { - if (isEmptyElement(tagname)) { - return null; - } - let tagCount = 0; - scanner.scanBack(); // one back to the end/start bracket - if (scanner.getTokenType() === DELIM_END) { - // find the opening tag - let tagClosed = false; - while (scanner.scanBack()) { - if (isTag(scanner.getTokenType()) && scanner.getTokenContent() === tagname && !tagClosed) { - let range = scanner.getTokenRange(); - scanner.scanBack(); // one back to the end/start bracket - if (scanner.getTokenType() === DELIM_START) { - if (tagCount === 0) { - return range; - } else { - tagCount--; - } - } else { - tagCount++; - } - } else if (scanner.getTokenType() === DELIM_START) { - tagClosed = scanner.getTokenContent() === '/>'; - } - } - } else { - let isTagEnd = false; - while (scanner.scanForward()) { - if (isTag(scanner.getTokenType()) && scanner.getTokenContent() === tagname) { - if (!isTagEnd) { - scanner.scanForward(); - if (scanner.getTokenType() === DELIM_START && scanner.getTokenContent() === '/>') { - if (tagCount <= 0) { - return null; - } - } else { - tagCount++; - } - } else { - tagCount--; - if (tagCount <= 0) { - return scanner.getTokenRange(); - } - } - } else if (scanner.getTokenType() === DELIM_START) { - isTagEnd = false; - } else if (scanner.getTokenType() === DELIM_END) { - isTagEnd = true; - } - } - } - return null; - - } - - public provideDocumentHighlights(resource:URI, position:editorCommon.IPosition, strict:boolean = false): winjs.TPromise { - let model = this.resourceService.get(resource), - wordAtPosition = model.getWordAtPosition(position), - result:modes.DocumentHighlight[] = []; - - - let scanner = getScanner(model, position); - if (isTag(scanner.getTokenType())) { - let tagname = scanner.getTokenContent(); - result.push({ - range: scanner.getTokenRange(), - kind: modes.DocumentHighlightKind.Read - }); - let range = this.findMatchingBracket(tagname, scanner); - if (range) { - result.push({ - range: range, - kind: modes.DocumentHighlightKind.Read - }); - } - } else { - if (wordAtPosition) { - let results = model.findMatches(wordAtPosition.word, false, false, true, true); - for (let i = 0, len = results.length; i < len; i++) { - result.push({ - range: results[i], - kind: modes.DocumentHighlightKind.Read - }); - } - } - } - return winjs.TPromise.as(result); - } - - private static _stripQuotes(url: string): string { - return url - .replace(/^'([^']+)'$/,(substr, match1) => match1) - .replace(/^"([^"]+)"$/,(substr, match1) => match1); - } - - public static _getWorkspaceUrl(modelAbsoluteUri: URI, rootAbsoluteUri: URI, tokenContent: string): string { - tokenContent = HTMLWorker._stripQuotes(tokenContent); - - if (/^\s*javascript\:/i.test(tokenContent) || /^\s*\#/i.test(tokenContent)) { - return null; - } - - if (/^\s*https?:\/\//i.test(tokenContent) || /^\s*file:\/\//i.test(tokenContent)) { - // Absolute link that needs no treatment - return tokenContent.replace(/^\s*/g, ''); - } - - if (/^\s*\/\//i.test(tokenContent)) { - // Absolute link (that does not name the protocol) - let pickedScheme = network.Schemas.http; - if (modelAbsoluteUri.scheme === network.Schemas.https) { - pickedScheme = network.Schemas.https; - } - return pickedScheme + ':' + tokenContent.replace(/^\s*/g, ''); - } - - let modelPath = paths.dirname(modelAbsoluteUri.path); - let alternativeResultPath: string = null; - if (tokenContent.length > 0 && tokenContent.charAt(0) === '/') { - alternativeResultPath = tokenContent; - } else { - alternativeResultPath = paths.join(modelPath, tokenContent); - alternativeResultPath = alternativeResultPath.replace(/^(\/\.\.)+/, ''); - } - let potentialResult = modelAbsoluteUri.with({ path: alternativeResultPath }).toString(); - - let rootAbsoluteUrlStr = (rootAbsoluteUri ? rootAbsoluteUri.toString() : null); - if (rootAbsoluteUrlStr && strings.startsWith(modelAbsoluteUri.toString(), rootAbsoluteUrlStr)) { - // The `rootAbsoluteUrl` is set and matches our current model - // We need to ensure that this `potentialResult` does not escape `rootAbsoluteUrl` - - let commonPrefixLength = strings.commonPrefixLength(rootAbsoluteUrlStr, potentialResult); - if (strings.endsWith(rootAbsoluteUrlStr, '/')) { - commonPrefixLength = potentialResult.lastIndexOf('/', commonPrefixLength) + 1; - } - return rootAbsoluteUrlStr + potentialResult.substr(commonPrefixLength); - } - - return potentialResult; - } - - private createLink(modelAbsoluteUrl: URI, rootAbsoluteUrl: URI, tokenContent: string, lineNumber: number, startColumn: number, endColumn: number): modes.ILink { - let workspaceUrl = HTMLWorker._getWorkspaceUrl(modelAbsoluteUrl, rootAbsoluteUrl, tokenContent); - if (!workspaceUrl) { - return null; - } - // console.info('workspaceUrl: ' + workspaceUrl); - - return { - range: { - startLineNumber: lineNumber, - startColumn: startColumn, - endLineNumber: lineNumber, - endColumn: endColumn - }, - url: workspaceUrl - }; - } - - private _computeHTMLLinks(model: ICompatMirrorModel, modelAbsoluteUrl:URI, workspaceResource:URI): modes.ILink[] { - let lineCount = model.getLineCount(), - newLinks: modes.ILink[] = [], - state: LinkDetectionState = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC, - lineNumber: number, - lineContent: string, - lineContentLength: number, - tokens: LineTokens, - tokenType: string, - tokensLength: number, - i: number, - nextTokenEndIndex: number, - tokenContent: string, - link: modes.ILink; - - let rootAbsoluteUrl: URI = null; - if (workspaceResource) { - // The workspace can be null in the no folder opened case - let strRootAbsoluteUrl = String(workspaceResource); - if (strRootAbsoluteUrl.charAt(strRootAbsoluteUrl.length - 1) === '/') { - rootAbsoluteUrl = URI.parse(strRootAbsoluteUrl); - } else { - rootAbsoluteUrl = URI.parse(strRootAbsoluteUrl + '/'); - } - } - - for (lineNumber = 1; lineNumber <= lineCount; lineNumber++) { - lineContent = model.getLineContent(lineNumber); - lineContentLength = lineContent.length; - tokens = model.getLineTokens(lineNumber); - - for (i = 0, tokensLength = tokens.getTokenCount(); i < tokensLength; i++) { - - tokenType = tokens.getTokenType(i); - - switch (tokenType) { - case DELIM_ASSIGN: - case '': - break; - - case ATTRIB_NAME: - nextTokenEndIndex = tokens.getTokenEndOffset(i); - tokenContent = lineContent.substring(tokens.getTokenStartOffset(i), nextTokenEndIndex).toLowerCase(); - - if (tokenContent === 'src' || tokenContent === 'href') { - state = LinkDetectionState.AFTER_HREF_OR_SRC; - } else { - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } - break; - - case ATTRIB_VALUE: - if (state === LinkDetectionState.AFTER_HREF_OR_SRC) { - nextTokenEndIndex = tokens.getTokenEndOffset(i); - tokenContent = lineContent.substring(tokens.getTokenStartOffset(i), nextTokenEndIndex); - - link = this.createLink(modelAbsoluteUrl, rootAbsoluteUrl, tokenContent, lineNumber, tokens.getTokenStartOffset(i) + 2, nextTokenEndIndex); - if (link) { - newLinks.push(link); - } - - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } - - default: - if (isTag(tokenType)) { - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } else if (state === LinkDetectionState.AFTER_HREF_OR_SRC) { - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } - } - } - } - - return newLinks; - } - - public provideLinks(resource: URI, workspaceResource:URI): winjs.TPromise { - let model = this.resourceService.get(resource); - return winjs.TPromise.as(this._computeHTMLLinks(model, resource, workspaceResource)); - } -} - -function isWhiteSpace(s:string) : boolean { - return /^\s*$/.test(s); -} diff --git a/src/vs/languages/html/test/common/html-worker.test.ts b/src/vs/languages/html/test/common/html-worker.test.ts deleted file mode 100644 index 51b6039de8d1b7c4993d2c3d2e5815f6244f3391..0000000000000000000000000000000000000000 --- a/src/vs/languages/html/test/common/html-worker.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 assert = require('assert'); -import mm = require('vs/editor/common/model/compatMirrorModel'); -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import URI from 'vs/base/common/uri'; -import ResourceService = require('vs/editor/common/services/resourceServiceImpl'); -import Modes = require('vs/editor/common/modes'); -import WinJS = require('vs/base/common/winjs.base'); -import {HTMLMode} from 'vs/languages/html/common/html'; -import {MockModeService} from 'vs/editor/test/common/mocks/mockModeService'; -import {TextModel} from 'vs/editor/common/model/textModel'; - -function createTestMirrorModelFromString(value:string, mode:Modes.IMode, associatedResource:URI): mm.CompatMirrorModel { - return new mm.CompatMirrorModel(0, TextModel.toRawText(value, TextModel.DEFAULT_CREATION_OPTIONS), mode.getId(), associatedResource); -} - -suite('HTML - worker', () => { - - var mode: Modes.IMode; - - (function() { - mode = new HTMLMode( - { id: 'html' }, - null, - new MockModeService(), - null, - null, - null - ); - })(); - - var mockHtmlWorkerEnv = function (url: URI, content: string): { worker: htmlWorker.HTMLWorker; model: mm.CompatMirrorModel; } { - var resourceService = new ResourceService.ResourceService(); - - var model = createTestMirrorModelFromString(content, mode, url); - resourceService.insert(url, model); - - var worker = new htmlWorker.HTMLWorker(mode.getId(), resourceService); - - return { worker: worker, model: model }; - }; - - var testSuggestionsFor = function(value:string):WinJS.TPromise { - - var idx = value.indexOf('|'); - var content = value.substr(0, idx) + value.substr(idx + 1); - - var url = URI.parse('test://1'); - var env = mockHtmlWorkerEnv(url, content); - - var position = env.model.getPositionAt(idx); - return env.worker.provideCompletionItems(url, position); - }; - - var assertSuggestion = function(completion: Modes.ISuggestResult, label: string, type?: string, codeSnippet?: string) { - var proposalsFound = completion.suggestions.filter(function(suggestion: Modes.ISuggestion) { - return suggestion.label === label && (!type || suggestion.type === type) && (!codeSnippet || suggestion.insertText === codeSnippet); - }); - if (proposalsFound.length !== 1) { - assert.fail('Suggestion not found: ' + label + ', has ' + completion.suggestions.map(s => s.label).join(', ')); - } - }; - - test('Intellisense', function(testDone): any { - WinJS.Promise.join([ - testSuggestionsFor('<|').then((completion) => { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'iframe'); - assertSuggestion(completion, 'h1'); - assertSuggestion(completion, 'div'); - }), - - testSuggestionsFor('< |').then((completion) => { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'iframe'); - assertSuggestion(completion, 'h1'); - assertSuggestion(completion, 'div'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'h'); - assertSuggestion(completion, 'html'); - assertSuggestion(completion, 'h1'); - assertSuggestion(completion, 'header'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'input'); - assertSuggestion(completion, 'input'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'type'); - assertSuggestion(completion, 'style'); - assertSuggestion(completion, 'onmousemove'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 't'); - assertSuggestion(completion, 'type'); - assertSuggestion(completion, 'tabindex'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'style'); - assertSuggestion(completion, 'type'); - assertSuggestion(completion, 'size'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 's'); - assertSuggestion(completion, 'style'); - assertSuggestion(completion, 'src'); - assertSuggestion(completion, 'size'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'di'); - assertSuggestion(completion, 'disabled', null, 'disabled'); - assertSuggestion(completion, 'dir', null, 'dir="{{}}"'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'dir', null, 'dir="{{}}"'); - assertSuggestion(completion, 'style'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'text', null, '"text"'); - assertSuggestion(completion, 'checkbox', null, '"checkbox"'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'color'); - assertSuggestion(completion, 'color', null, 'color'); - }), - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'color'); - assertSuggestion(completion, 'color', null, 'color'); - }), - testSuggestionsFor('
').then((completion) => { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'ltr', null, '"ltr"'); - assertSuggestion(completion, 'rtl', null, '"rtl"'); - }), - testSuggestionsFor('