diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index 3ff950f8732..45069658999 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -73,7 +73,7 @@ declare module monaco.editor { declare module monaco.languages { #includeAll(vs/editor/browser/standalone/standaloneLanguages;modes.=>;editorCommon.=>editor.): -#include(vs/editor/common/modes/supports/richEditSupport): CommentRule, IRichLanguageConfiguration +#include(vs/editor/common/modes/languageConfigurationRegistry): CommentRule, IRichLanguageConfiguration #include(vs/editor/common/modes/supports/onEnter): IIndentationRules, IOnEnterRegExpRules #include(vs/editor/common/modes/supports/electricCharacter): IBracketElectricCharacterContribution, IDocComment #includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.;IToken2=>IToken;ILineTokens2=>ILineTokens;IState2=>IState): diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 76f1ff18155..590bc6a7ddc 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -10,6 +10,7 @@ const extensions = [ 'vscode-api-tests', 'vscode-colorize-tests', 'json', + 'configuration-editing', 'typescript', 'php', 'javascript' diff --git a/extensions/configuration-editing/OSSREADME.json b/extensions/configuration-editing/OSSREADME.json new file mode 100644 index 00000000000..4744d2b3f24 --- /dev/null +++ b/extensions/configuration-editing/OSSREADME.json @@ -0,0 +1,9 @@ +// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: + +[{ + "name": "Microsoft/node-jsonc-parser", + "version": "0.0.0", + "license": "MIT", + "isProd": true, + "repositoryURL": "https://github.com/Microsoft/node-jsonc-parser" +}] diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json new file mode 100644 index 00000000000..60ca2473717 --- /dev/null +++ b/extensions/configuration-editing/package.json @@ -0,0 +1,25 @@ +{ + "name": "configuration-editing", + "version": "0.0.1", + "publisher": "vscode", + "engines": { + "vscode": "^1.0.0" + }, + "categories": [ + "Languages", "Other" + ], + "activationEvents": [ + "onLanguage:json" + ], + "main": "./out/extension", + "scripts": { + "compile": "gulp compile-extension:configuration-editing", + "watch": "gulp watch-extension:configuration-editing" + }, + "devDependencies": { + "vscode": "^0.11.0" + }, + "dependencies": { + "jsonc-parser": "^0.2.1" + } +} diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts new file mode 100644 index 00000000000..71a11ba355f --- /dev/null +++ b/extensions/configuration-editing/src/extension.ts @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * 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 vscode from 'vscode'; +import {getLocation} from 'jsonc-parser'; + +export function activate(context) { + + const commands = vscode.commands.getCommands(true); + + //keybindings.json command-suggestions + const disposable = vscode.languages.registerCompletionItemProvider({ pattern: '**/keybindings.json' }, { + + provideCompletionItems(document, position, token) { + const location = getLocation(document.getText(), document.offsetAt(position)); + if (location.path[1] === 'command') { + return commands.then(ids => ids.map(id => { + let item = new vscode.CompletionItem(id); + item.kind = vscode.CompletionItemKind.Value; + return item; + })); + } + } + }); + + context.subscriptions.push(disposable); +} diff --git a/extensions/configuration-editing/src/typings/ref.d.ts b/extensions/configuration-editing/src/typings/ref.d.ts new file mode 100644 index 00000000000..7f4835e6747 --- /dev/null +++ b/extensions/configuration-editing/src/typings/ref.d.ts @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/extensions/configuration-editing/tsconfig.json b/extensions/configuration-editing/tsconfig.json new file mode 100644 index 00000000000..8cb16334377 --- /dev/null +++ b/extensions/configuration-editing/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "noLib": true, + "target": "es5", + "module": "commonjs", + "outDir": "./out" + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 5ab4f70c634..98c256c04fd 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -10,10 +10,6 @@ import {workspace, languages, ExtensionContext, extensions, Uri} from 'vscode'; import {LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType} from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; -namespace TelemetryNotification { - export const type: NotificationType<{ key: string, data: any }> = { get method() { return 'telemetry'; } }; -} - namespace VSCodeContentRequest { export const type: RequestType = { get method() { return 'vscode/content'; } }; } @@ -68,7 +64,7 @@ export function activate(context: ExtensionContext) { // Create the language client and start the client. let client = new LanguageClient('JSON Server', serverOptions, clientOptions); - client.onNotification(TelemetryNotification.type, e => { + client.onTelemetry(e => { if (telemetryReporter) { telemetryReporter.sendTelemetryEvent(e.key, e.data); } diff --git a/extensions/json/package.json b/extensions/json/package.json index 3f38671cc12..cca25933dc6 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -128,7 +128,7 @@ } }, "dependencies": { - "vscode-languageclient": "^1.3.1", + "vscode-languageclient": "^2.2.1", "vscode-extension-telemetry": "^0.0.5" } } \ No newline at end of file diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 5afc0268f70..ab47aa2efc5 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -10,7 +10,7 @@ "dependencies": { "request-light": "^0.1.0", "jsonc-parser": "^0.2.0", - "vscode-languageserver": "^1.3.0", + "vscode-languageserver": "^2.2.0", "vscode-nls": "^1.0.4" }, "scripts": { diff --git a/extensions/json/server/src/jsonCompletion.ts b/extensions/json/server/src/jsonCompletion.ts index 103869f3fdb..7cb9f3925a6 100644 --- a/extensions/json/server/src/jsonCompletion.ts +++ b/extensions/json/server/src/jsonCompletion.ts @@ -10,7 +10,7 @@ import SchemaService = require('./jsonSchemaService'); import JsonSchema = require('./jsonSchema'); import {IJSONWorkerContribution} from './jsonContributions'; -import {CompletionItem, CompletionItemKind, CompletionList, ITextDocument, TextDocumentPosition, Range, TextEdit, RemoteConsole} from 'vscode-languageserver'; +import {CompletionItem, CompletionItemKind, CompletionList, TextDocument, Position, Range, TextEdit, RemoteConsole} from 'vscode-languageserver'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -46,9 +46,9 @@ export class JSONCompletion { return Promise.resolve(item); } - public doSuggest(document: ITextDocument, textDocumentPosition: TextDocumentPosition, doc: Parser.JSONDocument): Thenable { + public doSuggest(document: TextDocument, position: Position, doc: Parser.JSONDocument): Thenable { - let offset = document.offsetAt(textDocumentPosition.position); + let offset = document.offsetAt(position); let node = doc.getNodeFromOffsetEndInclusive(offset); let currentWord = this.getCurrentWord(document, offset); @@ -61,7 +61,7 @@ export class JSONCompletion { if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) { overwriteRange = Range.create(document.positionAt(node.start), document.positionAt(node.end)); } else { - overwriteRange = Range.create(document.positionAt(offset - currentWord.length), textDocumentPosition.position); + overwriteRange = Range.create(document.positionAt(offset - currentWord.length), position); } let proposed: { [key: string]: boolean } = {}; @@ -87,7 +87,7 @@ export class JSONCompletion { } }; - return this.schemaService.getSchemaForResource(textDocumentPosition.uri, doc).then((schema) => { + return this.schemaService.getSchemaForResource(document.uri, doc).then((schema) => { let collectionPromises: Thenable[] = []; let addValue = true; @@ -134,7 +134,7 @@ export class JSONCompletion { let location = node.getNodeLocation(); this.contributions.forEach((contribution) => { - let collectPromise = contribution.collectPropertySuggestions(textDocumentPosition.uri, location, currentWord, addValue, isLast, collector); + let collectPromise = contribution.collectPropertySuggestions(document.uri, location, currentWord, addValue, isLast, collector); if (collectPromise) { collectionPromises.push(collectPromise); } @@ -157,7 +157,7 @@ export class JSONCompletion { if (!node) { this.contributions.forEach((contribution) => { - let collectPromise = contribution.collectDefaultSuggestions(textDocumentPosition.uri, collector); + let collectPromise = contribution.collectDefaultSuggestions(document.uri, collector); if (collectPromise) { collectionPromises.push(collectPromise); } @@ -170,7 +170,7 @@ export class JSONCompletion { if (!valueNode || offset <= valueNode.end) { let location = node.parent.getNodeLocation(); this.contributions.forEach((contribution) => { - let collectPromise = contribution.collectValueSuggestions(textDocumentPosition.uri, location, parentKey, collector); + let collectPromise = contribution.collectValueSuggestions(document.uri, location, parentKey, collector); if (collectPromise) { collectionPromises.push(collectPromise); } @@ -230,7 +230,7 @@ export class JSONCompletion { } } - private getSchemaLessValueSuggestions(doc: Parser.JSONDocument, node: Parser.ASTNode, offset: number, document: ITextDocument, collector: ISuggestionsCollector): void { + private getSchemaLessValueSuggestions(doc: Parser.JSONDocument, node: Parser.ASTNode, offset: number, document: TextDocument, collector: ISuggestionsCollector): void { let collectSuggestionsForValues = (value: Parser.ASTNode) => { if (!value.contains(offset)) { let content = this.getTextForMatchingNode(value, document); @@ -449,7 +449,7 @@ export class JSONCompletion { } - private getTextForMatchingNode(node: Parser.ASTNode, document: ITextDocument): string { + private getTextForMatchingNode(node: Parser.ASTNode, document: TextDocument): string { switch (node.type) { case 'array': return '[]'; @@ -513,7 +513,7 @@ export class JSONCompletion { return this.getTextForValue(key); } - private getCurrentWord(document: ITextDocument, offset: number) { + private getCurrentWord(document: TextDocument, offset: number) { var i = offset - 1; var text = document.getText(); while (i >= 0 && ' \t\n\r\v":{[,'.indexOf(text.charAt(i)) === -1) { diff --git a/extensions/json/server/src/jsonDocumentSymbols.ts b/extensions/json/server/src/jsonDocumentSymbols.ts index 54de7054eea..9597fdad830 100644 --- a/extensions/json/server/src/jsonDocumentSymbols.ts +++ b/extensions/json/server/src/jsonDocumentSymbols.ts @@ -7,14 +7,14 @@ import Parser = require('./jsonParser'); import Strings = require('./utils/strings'); -import {SymbolInformation, SymbolKind, ITextDocument, Range, Location} from 'vscode-languageserver'; +import {SymbolInformation, SymbolKind, TextDocument, Range, Location} from 'vscode-languageserver'; export class JSONDocumentSymbols { constructor() { } - public compute(document: ITextDocument, doc: Parser.JSONDocument): Promise { + public compute(document: TextDocument, doc: Parser.JSONDocument): Promise { let root = doc.root; if (!root) { diff --git a/extensions/json/server/src/jsonFormatter.ts b/extensions/json/server/src/jsonFormatter.ts index f64f79c7b51..c95ec714d53 100644 --- a/extensions/json/server/src/jsonFormatter.ts +++ b/extensions/json/server/src/jsonFormatter.ts @@ -5,9 +5,9 @@ 'use strict'; import Json = require('jsonc-parser'); -import {ITextDocument, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver'; +import {TextDocument, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver'; -export function format(document: ITextDocument, range: Range, options: FormattingOptions): TextEdit[] { +export function format(document: TextDocument, range: Range, options: FormattingOptions): TextEdit[] { const documentText = document.getText(); let initialIndentLevel: number; let value: string; @@ -83,7 +83,7 @@ export function format(document: ITextDocument, range: Range, options: Formattin replaceContent = secondToken === Json.SyntaxKind.LineCommentTrivia ? newLineAndIndent() : ''; secondToken = scanNext(); } - + if (secondToken === Json.SyntaxKind.CloseBraceToken) { if (firstToken !== Json.SyntaxKind.OpenBraceToken) { indentLevel--; @@ -163,7 +163,7 @@ function computeIndentLevel(content: string, offset: number, options: Formatting return Math.floor(nChars / tabSize); } -function getEOL(document: ITextDocument): string { +function getEOL(document: TextDocument): string { let text = document.getText(); if (document.lineCount > 1) { let to = document.offsetAt(Position.create(1, 0)); diff --git a/extensions/json/server/src/jsonHover.ts b/extensions/json/server/src/jsonHover.ts index 5aa6cf6e9ae..987e7f4a6a0 100644 --- a/extensions/json/server/src/jsonHover.ts +++ b/extensions/json/server/src/jsonHover.ts @@ -9,7 +9,7 @@ import Parser = require('./jsonParser'); import SchemaService = require('./jsonSchemaService'); import {IJSONWorkerContribution} from './jsonContributions'; -import {Hover, ITextDocument, TextDocumentPosition, Range, MarkedString} from 'vscode-languageserver'; +import {Hover, TextDocument, Position, Range, MarkedString} from 'vscode-languageserver'; export class JSONHover { @@ -21,9 +21,9 @@ export class JSONHover { this.contributions = contributions; } - public doHover(document: ITextDocument, textDocumentPosition: TextDocumentPosition, doc: Parser.JSONDocument): Thenable { + public doHover(document: TextDocument, position: Position, doc: Parser.JSONDocument): Thenable { - let offset = document.offsetAt(textDocumentPosition.position); + let offset = document.offsetAt(position); let node = doc.getNodeFromOffset(offset); // use the property description when hovering over an object key @@ -39,7 +39,7 @@ export class JSONHover { if (!node) { return Promise.resolve(void 0); } - + var createHover = (contents: MarkedString[]) => { let range = Range.create(document.positionAt(node.start), document.positionAt(node.end)); let result: Hover = { @@ -47,18 +47,18 @@ export class JSONHover { range: range }; return result; - }; - + }; + let location = node.getNodeLocation(); for (let i = this.contributions.length - 1; i >= 0; i--) { let contribution = this.contributions[i]; - let promise = contribution.getInfoContribution(textDocumentPosition.uri, location); + let promise = contribution.getInfoContribution(document.uri, location); if (promise) { return promise.then(htmlContent => createHover(htmlContent)); } } - return this.schemaService.getSchemaForResource(textDocumentPosition.uri, doc).then((schema) => { + return this.schemaService.getSchemaForResource(document.uri, doc).then((schema) => { if (schema) { let matchingSchemas: Parser.IApplicableSchema[] = []; doc.validate(schema.schema, matchingSchemas, node.start); diff --git a/extensions/json/server/src/server.ts b/extensions/json/server/src/server.ts index b91d4ca9e12..384aeeea6a8 100644 --- a/extensions/json/server/src/server.ts +++ b/extensions/json/server/src/server.ts @@ -5,11 +5,10 @@ 'use strict'; import { - IPCMessageReader, IPCMessageWriter, - createConnection, IConnection, - TextDocuments, ITextDocument, Diagnostic, DiagnosticSeverity, - InitializeParams, InitializeResult, TextDocumentIdentifier, TextDocumentPosition, CompletionList, - CompletionItem, Hover, SymbolInformation, DocumentFormattingParams, + IPCMessageReader, IPCMessageWriter, createConnection, IConnection, + TextDocuments, TextDocument, Diagnostic, DiagnosticSeverity, + InitializeParams, InitializeResult, TextDocumentPositionParams, CompletionList, + CompletionItem, Hover, SymbolInformation, DocumentFormattingParams, DocumentSymbolParams, DocumentRangeFormattingParams, NotificationType, RequestType } from 'vscode-languageserver'; @@ -33,10 +32,6 @@ import {FileAssociationContribution} from './jsoncontributions/fileAssociationCo import * as nls from 'vscode-nls'; nls.config(process.env['VSCODE_NLS_CONFIG']); -namespace TelemetryNotification { - export const type: NotificationType<{ key: string, data: any }> = { get method() { return 'telemetry'; } }; -} - namespace SchemaAssociationNotification { export const type: NotificationType = { get method() { return 'json/schemaAssociations'; } }; } @@ -89,7 +84,7 @@ let workspaceContext = { let telemetry = { log: (key: string, data: any) => { - connection.sendNotification(TelemetryNotification.type, { key, data }); + connection.telemetry.logEvent({ key, data }); } }; @@ -208,7 +203,7 @@ function updateConfiguration() { } -function validateTextDocument(textDocument: ITextDocument): void { +function validateTextDocument(textDocument: TextDocument): void { if (textDocument.getText().length === 0) { // ignore empty documents connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] }); @@ -268,28 +263,28 @@ connection.onDidChangeWatchedFiles((change) => { } }); -function getJSONDocument(document: ITextDocument): JSONDocument { +function getJSONDocument(document: TextDocument): JSONDocument { return parseJSON(document.getText()); } -connection.onCompletion((textDocumentPosition: TextDocumentPosition): Thenable => { - let document = documents.get(textDocumentPosition.uri); +connection.onCompletion((textDocumentPosition: TextDocumentPositionParams): Thenable => { + let document = documents.get(textDocumentPosition.textDocument.uri); let jsonDocument = getJSONDocument(document); - return jsonCompletion.doSuggest(document, textDocumentPosition, jsonDocument); + return jsonCompletion.doSuggest(document, textDocumentPosition.position, jsonDocument); }); connection.onCompletionResolve((item: CompletionItem) : Thenable => { return jsonCompletion.doResolve(item); }); -connection.onHover((textDocumentPosition: TextDocumentPosition): Thenable => { - let document = documents.get(textDocumentPosition.uri); +connection.onHover((textDocumentPosition: TextDocumentPositionParams): Thenable => { + let document = documents.get(textDocumentPosition.textDocument.uri); let jsonDocument = getJSONDocument(document); - return jsonHover.doHover(document, textDocumentPosition, jsonDocument); + return jsonHover.doHover(document, textDocumentPosition.position, jsonDocument); }); -connection.onDocumentSymbol((textDocumentIdentifier: TextDocumentIdentifier): Thenable => { - let document = documents.get(textDocumentIdentifier.uri); +connection.onDocumentSymbol((documentSymbolParams: DocumentSymbolParams): Thenable => { + let document = documents.get(documentSymbolParams.textDocument.uri); let jsonDocument = getJSONDocument(document); return jsonDocumentSymbols.compute(document, jsonDocument); }); diff --git a/extensions/json/server/src/test/completion.test.ts b/extensions/json/server/src/test/completion.test.ts index a4c92879951..995b23b1fa4 100644 --- a/extensions/json/server/src/test/completion.test.ts +++ b/extensions/json/server/src/test/completion.test.ts @@ -11,7 +11,7 @@ import JsonSchema = require('../jsonSchema'); import {JSONCompletion} from '../jsonCompletion'; import {XHROptions, XHRResponse} from 'request-light'; -import {CompletionItem, CompletionItemKind, CompletionOptions, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver'; +import {CompletionItem, CompletionItemKind, CompletionOptions, TextDocument, TextDocumentIdentifier, Range, Position, TextEdit} from 'vscode-languageserver'; import {applyEdits} from './textEditSupport'; suite('JSON Completion', () => { @@ -20,7 +20,7 @@ suite('JSON Completion', () => { return Promise.reject({ responseText: '', status: 404 }); } - var assertSuggestion = function(completions: CompletionItem[], label: string, documentation?: string, document?: ITextDocument, resultText?: string) { + var assertSuggestion = function(completions: CompletionItem[], label: string, documentation?: string, document?: TextDocument, resultText?: string) { var matches = completions.filter(function(completion: CompletionItem) { return completion.label === label && (!documentation || completion.documentation === documentation); }); @@ -31,7 +31,7 @@ suite('JSON Completion', () => { }; - var testSuggestionsFor = function(value: string, stringAfter: string, schema: JsonSchema.IJSONSchema, test: (items: CompletionItem[], document: ITextDocument) => void) : Thenable { + var testSuggestionsFor = function(value: string, stringAfter: string, schema: JsonSchema.IJSONSchema, test: (items: CompletionItem[], document: TextDocument) => void) : Thenable { var uri = 'test://test.json'; var idx = stringAfter ? value.indexOf(stringAfter) : 0; @@ -42,10 +42,10 @@ suite('JSON Completion', () => { schemaService.registerExternalSchema(id, ["*.json"], schema); } - var document = ITextDocument.create(uri, value); - var textDocumentLocation = TextDocumentPosition.create(uri, Position.create(0, idx)); + var document = TextDocument.create(uri, 'json', 0, value); + var position = Position.create(0, idx); var jsonDoc = Parser.parse(value); - return completionProvider.doSuggest(document, textDocumentLocation, jsonDoc).then(list => list.items).then(completions => { + return completionProvider.doSuggest(document, position, jsonDoc).then(list => list.items).then(completions => { test(completions, document); return null; }) diff --git a/extensions/json/server/src/test/documentSymbols.test.ts b/extensions/json/server/src/test/documentSymbols.test.ts index 6f27e9134e4..2e41c69b852 100644 --- a/extensions/json/server/src/test/documentSymbols.test.ts +++ b/extensions/json/server/src/test/documentSymbols.test.ts @@ -11,7 +11,7 @@ import JsonSchema = require('../jsonSchema'); import {JSONCompletion} from '../jsonCompletion'; import {JSONDocumentSymbols} from '../jsonDocumentSymbols'; -import {SymbolInformation, SymbolKind, TextDocumentIdentifier, ITextDocument, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver'; +import {SymbolInformation, SymbolKind, TextDocumentIdentifier, TextDocument, Range, Position, TextEdit} from 'vscode-languageserver'; suite('JSON Document Symbols', () => { @@ -20,7 +20,7 @@ suite('JSON Document Symbols', () => { var symbolProvider = new JSONDocumentSymbols(); - var document = ITextDocument.create(uri, value); + var document = TextDocument.create(uri, 'json', 0, value); var jsonDoc = Parser.parse(value); return symbolProvider.compute(document, jsonDoc); } diff --git a/extensions/json/server/src/test/formatter.test.ts b/extensions/json/server/src/test/formatter.test.ts index 5254ee88b57..a1e367ecc10 100644 --- a/extensions/json/server/src/test/formatter.test.ts +++ b/extensions/json/server/src/test/formatter.test.ts @@ -5,7 +5,7 @@ 'use strict'; import Json = require('jsonc-parser'); -import {ITextDocument, DocumentFormattingParams, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver'; +import {TextDocument, DocumentFormattingParams, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver'; import Formatter = require('../jsonFormatter'); import assert = require('assert'); import {applyEdits} from './textEditSupport'; @@ -20,14 +20,14 @@ suite('JSON Formatter', () => { let rangeEnd = unformatted.lastIndexOf('|'); if (rangeStart !== -1 && rangeEnd !== -1) { // remove '|' - var unformattedDoc = ITextDocument.create(uri, unformatted); + var unformattedDoc = TextDocument.create(uri, 'json', 0, unformatted); unformatted = unformatted.substring(0, rangeStart) + unformatted.substring(rangeStart + 1, rangeEnd) + unformatted.substring(rangeEnd + 1); let startPos = unformattedDoc.positionAt(rangeStart); let endPos = unformattedDoc.positionAt(rangeEnd); range = Range.create(startPos, endPos); } - var document = ITextDocument.create(uri, unformatted); + var document = TextDocument.create(uri, 'json', 0, unformatted); let edits = Formatter.format(document, range, { tabSize: 2, insertSpaces: insertSpaces }); let formatted = applyEdits(document, edits); assert.equal(formatted, expected); @@ -308,7 +308,7 @@ suite('JSON Formatter', () => { format(content, expected); }); - + test('multiple mixed comments on same line', () => { var content = [ '[ /*comment*/ /*comment*/ // comment ', diff --git a/extensions/json/server/src/test/hover.test.ts b/extensions/json/server/src/test/hover.test.ts index c442801d144..8315e6a5cda 100644 --- a/extensions/json/server/src/test/hover.test.ts +++ b/extensions/json/server/src/test/hover.test.ts @@ -12,7 +12,7 @@ import {JSONCompletion} from '../jsonCompletion'; import {XHROptions, XHRResponse} from 'request-light'; import {JSONHover} from '../jsonHover'; -import {Hover, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver'; +import {Hover, TextDocument, TextDocumentIdentifier, TextDocumentPositionParams, Range, Position, TextEdit} from 'vscode-languageserver'; suite('JSON Hover', () => { @@ -24,10 +24,9 @@ suite('JSON Hover', () => { var id = "http://myschemastore/test1"; schemaService.registerExternalSchema(id, ["*.json"], schema); - var document = ITextDocument.create(uri, value); - var textDocumentLocation = TextDocumentPosition.create(uri, position); + var document = TextDocument.create(uri, 'json', 0, value); var jsonDoc = Parser.parse(value); - return hoverProvider.doHover(document, textDocumentLocation, jsonDoc); + return hoverProvider.doHover(document, position, jsonDoc); } var requestService = function(options: XHROptions): Promise { diff --git a/extensions/json/server/src/test/textEditSupport.ts b/extensions/json/server/src/test/textEditSupport.ts index 5f04be02f3c..9160177f756 100644 --- a/extensions/json/server/src/test/textEditSupport.ts +++ b/extensions/json/server/src/test/textEditSupport.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {ITextDocument, TextEdit} from 'vscode-languageserver'; +import {TextDocument, TextEdit} from 'vscode-languageserver'; import assert = require('assert'); -export function applyEdits(document: ITextDocument, edits: TextEdit[]) : string { +export function applyEdits(document: TextDocument, edits: TextEdit[]) : string { let formatted = document.getText(); let sortedEdits = edits.sort((a, b) => document.offsetAt(b.range.start) - document.offsetAt(a.range.start)); let lastOffset = formatted.length; diff --git a/extensions/typescript/src/features/bufferSyncSupport.ts b/extensions/typescript/src/features/bufferSyncSupport.ts index 1e6e9e60c90..89ade4b5e1a 100644 --- a/extensions/typescript/src/features/bufferSyncSupport.ts +++ b/extensions/typescript/src/features/bufferSyncSupport.ts @@ -2,9 +2,10 @@ * 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 fs from 'fs'; + import { workspace, TextDocument, TextDocumentChangeEvent, TextDocumentContentChangeEvent, Disposable } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; @@ -67,12 +68,17 @@ class SyncedBuffer { } } +export interface Diagnostics { + delete(file: string): void; +} + export default class BufferSyncSupport { private client: ITypescriptServiceClient; private _validate: boolean; private modeIds: Map; + private diagnostics: Diagnostics; private disposables: Disposable[] = []; private syncedBuffers: Map; private closedFiles: Map; @@ -80,10 +86,11 @@ export default class BufferSyncSupport { private pendingDiagnostics: { [key: string]: number; }; private diagnosticDelayer: Delayer; - constructor(client: ITypescriptServiceClient, modeIds: string[], validate: boolean = true) { + constructor(client: ITypescriptServiceClient, modeIds: string[], diagnostics: Diagnostics, validate: boolean = true) { this.client = client; this.modeIds = Object.create(null); modeIds.forEach(modeId => this.modeIds[modeId] = true); + this.diagnostics = diagnostics; this._validate = validate; this.pendingDiagnostics = Object.create(null); @@ -94,10 +101,23 @@ export default class BufferSyncSupport { } public listen(): void { - workspace.onDidOpenTextDocument(this.onDidAddDocument, this, this.disposables); - workspace.onDidCloseTextDocument(this.onDidRemoveDocument, this, this.disposables); - workspace.onDidChangeTextDocument(this.onDidChangeDocument, this, this.disposables); - workspace.textDocuments.forEach(this.onDidAddDocument, this); + workspace.onDidOpenTextDocument(this.onDidOpenTextDocument, this, this.disposables); + workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, this.disposables); + workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, this.disposables); + workspace.textDocuments.forEach(this.onDidOpenTextDocument, this); + workspace.createFileSystemWatcher('**/*', true, true, false).onDidDelete((resource) => { + let filepath = this.client.asAbsolutePath(resource); + if (!filepath) { + return; + } + if (!this.syncedBuffers[filepath]) { + // The file is not synced (open in an editor) and got + // removed from disk. Make sure it is not in the closedFiles + // list since we shouldn't revalidate it. + delete this.closedFiles[filepath]; + this.diagnostics.delete(filepath); + } + }); } public get validate(): boolean { @@ -124,7 +144,7 @@ export default class BufferSyncSupport { } } - private onDidAddDocument(document: TextDocument): void { + private onDidOpenTextDocument(document: TextDocument): void { if (!this.modeIds[document.languageId]) { return; } @@ -143,7 +163,7 @@ export default class BufferSyncSupport { this.requestDiagnostic(filepath); } - private onDidRemoveDocument(document: TextDocument): void { + private onDidCloseTextDocument(document: TextDocument): void { let filepath: string = this.client.asAbsolutePath(document.uri); if (!filepath) { return; @@ -152,12 +172,19 @@ export default class BufferSyncSupport { if (!syncedBuffer) { return; } - this.closedFiles[filepath] = true; + // If the file still exists on disk keep on validating the file. + if (fs.existsSync(filepath)) { + this.closedFiles[filepath] = true; + } else { + // Ensure we don't have the file in the map and clear all errors. + delete this.closedFiles[filepath]; + this.diagnostics.delete(filepath); + } delete this.syncedBuffers[filepath]; syncedBuffer.close(); } - private onDidChangeDocument(e: TextDocumentChangeEvent): void { + private onDidChangeTextDocument(e: TextDocumentChangeEvent): void { let filepath: string = this.client.asAbsolutePath(e.document.uri); if (!filepath) { return; diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 0f88c6beede..57e05ea5ac4 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -98,7 +98,11 @@ class LanguageProvider { this.description = description; this._validate = true; - this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds); + this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds, { + delete: (file: string) => { + this.currentDiagnostics.delete(Uri.file(file)); + } + }); this.syntaxDiagnostics = Object.create(null); this.currentDiagnostics = languages.createDiagnosticCollection(description.id); diff --git a/extensions/vscode-api-tests/src/editor.test.ts b/extensions/vscode-api-tests/src/editor.test.ts index 13388234f78..0dc0bf124e0 100644 --- a/extensions/vscode-api-tests/src/editor.test.ts +++ b/extensions/vscode-api-tests/src/editor.test.ts @@ -6,13 +6,10 @@ 'use strict'; import * as assert from 'assert'; -import * as fs from 'fs'; -import * as os from 'os'; import {workspace, window, Position, Range} from 'vscode'; import {createRandomFile, deleteFile, cleanUp} from './utils'; -import {join} from 'path'; -suite("editor tests", () => { +suite('editor tests', () => { teardown(cleanUp); diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 0c0e944ddf2..68b84190f41 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -572,7 +572,7 @@ export class RunOnceScheduler { */ schedule(delay = this.timeout): void { this.cancel(); - this.timeoutToken = platform.setTimeout(this.timeoutHandler, this.timeout); + this.timeoutToken = platform.setTimeout(this.timeoutHandler, delay); } /** diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts index 908cf68781e..dbba825648e 100644 --- a/src/vs/base/common/paths.ts +++ b/src/vs/base/common/paths.ts @@ -77,139 +77,75 @@ export function extname(path: string): string { return idx ? path.substring(~idx) : ''; } -export function normalize2(path: string, toOSPath: boolean): string { +const _posixBadPath = /(\/\.\.?\/)|(\/\.\.?)$|^(\.\.?\/)|(\/\/+)|(\\)/; +const _winBadPath = /(\\\.\.?\\)|(\\\.\.?)$|^(\.\.?\\)|(\\\\+)|(\/)/; - if (path === null || path === void 0) { - return path; - } - - let len = path.length; - if (len === 0) { - return '.'; - } - - const sep = isWindows && toOSPath ? '\\' : '/'; - const root = getRoot(path, sep); - - let lastCode = -1; - - for (let pos = root.length; pos < len; pos++) { - let code = path.charCodeAt(pos); - if (code === 64/*.*/) { - - if (lastCode === -1 || lastCode === 47 || lastCode === 92) { - - if (pos + 1 < len) { - code = path.charCodeAt(++pos); - if (code === 47 || code === 92) { - - } - } - } - } - } +function _isNormal(path: string, win: boolean): boolean { + return win + ? !_winBadPath.test(path) + : !_posixBadPath.test(path); } -function _isNormal(path: string, badSep: number): boolean { - let lastCode = -1; - for (let pos = 0; pos < path.length; pos++) { - let code = path.charCodeAt(pos); - // bad separator - if (code === badSep) { - return false; - } - // double separator - if ((code === _slash || code === _backslash) - && (lastCode === _slash || lastCode === _backslash)) { - - return false; - } - // ./ ../ segments - if (code === _dot && (lastCode === -1 || lastCode === _slash || lastCode === _backslash)) { - if (pos + 1 >= path.length) { - // /. - return false; - } - code = path.charCodeAt(++pos); - if (code === _slash || code === _backslash) { - // /./ - return false; - - } else if (code === _dot) { - if (pos + 1 >= path.length) { - // /.. - return false; - } - code = path.charCodeAt(++pos); - if (code === _slash || code === _backslash) { - // /../ - return false; - } - } - } - lastCode = code; - } - return true; -} - - export function normalize(path: string, toOSPath?: boolean): string { if (path === null || path === void 0) { return path; } - let len = path.length; + const len = path.length; if (len === 0) { return '.'; } - if (_isNormal(path, isWindows && toOSPath ? _slash : _backslash)) { + const wantsBackslash = isWindows && toOSPath; + if (_isNormal(path, wantsBackslash)) { return path; } - // operate on the 'path-portion' only - const sep = isWindows && toOSPath ? '\\' : '/'; + const sep = wantsBackslash ? '\\' : '/'; const root = getRoot(path, sep); - path = path.slice(root.length); - len -= root.length; + // skip the root-portion of the path + let start = root.length; + let skip = false; let res = ''; - let start = 0; - for (let end = 0; end <= len; end++) { + for (let end = root.length; end <= len; end++) { // either at the end or at a path-separator character if (end === len || path.charCodeAt(end) === _slash || path.charCodeAt(end) === _backslash) { - let part = path.slice(start, end); - start = end + 1; - - if (part === '.' && (root || res || end < len - 1)) { - // skip current (if there is already something or if there is more to come) - continue; - } - - if (part === '..') { + if (streql(path, start, end, '..')) { // skip current and remove parent (if there is already something) let prev_start = res.lastIndexOf(sep); let prev_part = res.slice(prev_start + 1); if ((root || prev_part.length > 0) && prev_part !== '..') { res = prev_start === -1 ? '' : res.slice(0, prev_start); - continue; + skip = true; } + } else if (streql(path, start, end, '.') && (root || res || end < len - 1)) { + // skip current (if there is already something or if there is more to come) + skip = true; } - if (res !== '' && res[res.length - 1] !== sep) { - res += sep; + if (!skip) { + let part = path.slice(start, end); + if (res !== '' && res[res.length - 1] !== sep) { + res += sep; + } + res += part; } - res += part; + start = end + 1; } } return root + res; } +function streql(value: string, start: number, end: number, other: string): boolean { + return start + other.length === end && value.indexOf(other, start) === start; +} + /** * Computes the _root_ this path, like `getRoot('c:\files') === c:\`, * `getRoot('files:///files/path') === files:///`, @@ -374,7 +310,6 @@ export function isRelative(path: string): boolean { const _slash = '/'.charCodeAt(0); const _backslash = '\\'.charCodeAt(0); const _colon = ':'.charCodeAt(0); -const _dot = '.'.charCodeAt(0); const _a = 'a'.charCodeAt(0); const _A = 'A'.charCodeAt(0); const _z = 'z'.charCodeAt(0); diff --git a/src/vs/editor/browser/standalone/standaloneEditor.ts b/src/vs/editor/browser/standalone/standaloneEditor.ts index 3f2d71ec5b9..66a1189da9a 100644 --- a/src/vs/editor/browser/standalone/standaloneEditor.ts +++ b/src/vs/editor/browser/standalone/standaloneEditor.ts @@ -20,8 +20,6 @@ import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService'; import {IModel} from 'vs/editor/common/editorCommon'; -import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; -import {ILanguage} from 'vs/editor/common/modes/monarch/monarchTypes'; import {IModelService} from 'vs/editor/common/services/modelService'; import {ICodeEditor, IDiffEditor} from 'vs/editor/browser/editorBrowser'; import {Colorizer, IColorizerElementOptions, IColorizerOptions} from 'vs/editor/browser/standalone/colorizer'; @@ -208,35 +206,6 @@ export function configureMode(modeId: string, options: any): void { modeService.configureModeById(modeId, options); } -/** - * @internal - */ -export function createCustomMode(language:ILanguage): TPromise { - startup.initStaticServicesIfNecessary(); - let staticPlatformServices = ensureStaticPlatformServices(null); - let modeService = staticPlatformServices.modeService; - let modelService = staticPlatformServices.modelService; - let editorWorkerService = staticPlatformServices.editorWorkerService; - - let modeId = language.name; - let name = language.name; - - ModesRegistry.registerLanguage({ - id: modeId, - aliases: [name] - }); - - let disposable = modeService.onDidCreateMode((mode) => { - if (mode.getId() !== modeId) { - return; - } - modeService.registerMonarchDefinition(modelService, editorWorkerService, modeId, language); - disposable.dispose(); - }); - - return modeService.getOrCreateMode(modeId); -} - interface IMonacoWebWorkerState { myProxy:StandaloneWorker; foreignProxy:T; @@ -345,8 +314,6 @@ export function createMonacoEditorAPI(): typeof monaco.editor { onDidChangeModelLanguage: onDidChangeModelLanguage, - // getOrCreateMode: getOrCreateMode, - // createCustomMode: createCustomMode, createWebWorker: createWebWorker, colorizeElement: colorizeElement, colorize: colorize, diff --git a/src/vs/editor/browser/standalone/standaloneLanguages.ts b/src/vs/editor/browser/standalone/standaloneLanguages.ts index 49e0ca3d876..88bf600d1c4 100644 --- a/src/vs/editor/browser/standalone/standaloneLanguages.ts +++ b/src/vs/editor/browser/standalone/standaloneLanguages.ts @@ -17,12 +17,15 @@ import {ILanguageExtensionPoint} from 'vs/editor/common/services/modeService'; import {ensureStaticPlatformServices} from 'vs/editor/browser/standalone/standaloneServices'; import * as modes from 'vs/editor/common/modes'; import {startup} from './standaloneCodeEditor'; -import {IRichLanguageConfiguration} from 'vs/editor/common/modes/supports/richEditSupport'; +import {IRichLanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {Position} from 'vs/editor/common/core/position'; import {Range} from 'vs/editor/common/core/range'; import {CancellationToken} from 'vs/base/common/cancellation'; import {toThenable} from 'vs/base/common/async'; +import {compile} from 'vs/editor/common/modes/monarch/monarchCompile'; +import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchLexer'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export function register(language:ILanguageExtensionPoint): void { ModesRegistry.registerLanguage(language); @@ -48,9 +51,7 @@ export function onLanguage(languageId:string, callback:()=>void): IDisposable { } export function setLanguageConfiguration(languageId:string, configuration:IRichLanguageConfiguration): IDisposable { - startup.initStaticServicesIfNecessary(); - let staticPlatformServices = ensureStaticPlatformServices(null); - return staticPlatformServices.modeService.registerRichEditSupport(languageId, configuration); + return LanguageConfigurationRegistry.register(languageId, configuration); } export function setTokensProvider(languageId:string, support:modes.TokensProvider): IDisposable { @@ -295,7 +296,7 @@ export function registerMonarchStandaloneLanguage(language:ILanguageExtensionPoi ModesRegistry.registerLanguage(language); ExtensionsRegistry.registerOneTimeActivationEventListener('onLanguage:' + language.id, () => { - require([defModule], (value:{language:ILanguage}) => { + require([defModule], (value:{language:ILanguage;conf:IRichLanguageConfiguration}) => { if (!value.language) { console.error('Expected ' + defModule + ' to export a `language`'); return; @@ -304,10 +305,14 @@ export function registerMonarchStandaloneLanguage(language:ILanguageExtensionPoi startup.initStaticServicesIfNecessary(); let staticPlatformServices = ensureStaticPlatformServices(null); let modeService = staticPlatformServices.modeService; - let modelService = staticPlatformServices.modelService; - let editorWorkerService = staticPlatformServices.editorWorkerService; - modeService.registerMonarchDefinition(modelService, editorWorkerService, language.id, value.language); + let lexer = compile(language.id, value.language); + + modeService.registerTokenizationSupport(language.id, (mode) => { + return createTokenizationSupport(modeService, mode, lexer); + }); + + LanguageConfigurationRegistry.register(language.id, value.conf); }, (err) => { console.error('Cannot find module ' + defModule, err); }); diff --git a/src/vs/editor/common/commands/shiftCommand.ts b/src/vs/editor/common/commands/shiftCommand.ts index 7d5bdbcab7a..63e2e77aee6 100644 --- a/src/vs/editor/common/commands/shiftCommand.ts +++ b/src/vs/editor/common/commands/shiftCommand.ts @@ -9,7 +9,7 @@ import {CursorMoveHelper} from 'vs/editor/common/controller/cursorMoveHelper'; import {Range} from 'vs/editor/common/core/range'; import {Selection} from 'vs/editor/common/core/selection'; import {ICommand, ICursorStateComputerData, IEditOperationBuilder, ITokenizedModel} from 'vs/editor/common/editorCommon'; -import {getRawEnterActionAtPosition} from 'vs/editor/common/modes/supports/onEnter'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface IShiftCommandOpts { isUnshift: boolean; @@ -101,7 +101,7 @@ export class ShiftCommand implements ICommand { if (contentStartVisibleColumn % tabSize !== 0) { // The current line is "miss-aligned", so let's see if this is expected... // This can only happen when it has trailing commas in the indent - let enterAction = getRawEnterActionAtPosition(model, lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)); + let enterAction = LanguageConfigurationRegistry.getRawEnterActionAtPosition(model, lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)); if (enterAction) { extraSpaces = previousLineExtraSpaces; if (enterAction.appendText) { diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index be45e38ff64..4e3265c38f5 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -16,6 +16,7 @@ import {Range} from 'vs/editor/common/core/range'; import {Selection} from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {IColumnSelectResult} from 'vs/editor/common/controller/cursorMoveHelper'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface ITypingListener { (): void; @@ -140,8 +141,8 @@ export class Cursor extends EventEmitter { this.modelUnbinds.push(this.model.onDidChangeMode((e) => { this._onModelModeChanged(); })); - this.modelUnbinds.push(this.model.onDidChangeModeSupport((e) => { - // TODO@Alex: react only if certain supports changed? + this.modelUnbinds.push(LanguageConfigurationRegistry.onDidChange(() => { + // TODO@Alex: react only if certain supports changed? (and if my model's mode changed) this._onModelModeChanged(); })); diff --git a/src/vs/editor/common/controller/cursorCollection.ts b/src/vs/editor/common/controller/cursorCollection.ts index 395273ddfcf..f2f977ffbc5 100644 --- a/src/vs/editor/common/controller/cursorCollection.ts +++ b/src/vs/editor/common/controller/cursorCollection.ts @@ -10,6 +10,7 @@ import {Selection} from 'vs/editor/common/core/selection'; import {IConfiguration, IModel, ISelection} from 'vs/editor/common/editorCommon'; import {IAutoClosingPair} from 'vs/editor/common/modes'; import {Position} from 'vs/editor/common/core/position'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface ICursorCollectionState { primary: IOneCursorState; @@ -326,51 +327,50 @@ export class CursorCollection { surroundingPairs: {} }; - let richEditSupport = this.model.getMode().richEditSupport; - let electricChars: string[]; - if (richEditSupport && richEditSupport.electricCharacter) { + let electricCharSupport = LanguageConfigurationRegistry.getElectricCharacterSupport(this.model.getMode().getId()); + if (electricCharSupport) { + let electricChars: string[] = null; try { - electricChars = richEditSupport.electricCharacter.getElectricCharacters(); + electricChars = electricCharSupport.getElectricCharacters(); } catch(e) { onUnexpectedError(e); electricChars = null; } - } - if (electricChars) { - for (i = 0; i < electricChars.length; i++) { - result.electricChars[electricChars[i]] = true; + if (electricChars) { + for (i = 0; i < electricChars.length; i++) { + result.electricChars[electricChars[i]] = true; + } } } - let autoClosingPairs: IAutoClosingPair[]; - if (richEditSupport && richEditSupport.characterPair) { + let characterPairSupport = LanguageConfigurationRegistry.getCharacterPairSupport(this.model.getMode().getId()); + if (characterPairSupport) { + let autoClosingPairs: IAutoClosingPair[]; try { - autoClosingPairs = richEditSupport.characterPair.getAutoClosingPairs(); + autoClosingPairs = characterPairSupport.getAutoClosingPairs(); } catch(e) { onUnexpectedError(e); autoClosingPairs = null; } - } - if (autoClosingPairs) { - for (i = 0; i < autoClosingPairs.length; i++) { - result.autoClosingPairsOpen[autoClosingPairs[i].open] = autoClosingPairs[i].close; - result.autoClosingPairsClose[autoClosingPairs[i].close] = autoClosingPairs[i].open; + if (autoClosingPairs) { + for (i = 0; i < autoClosingPairs.length; i++) { + result.autoClosingPairsOpen[autoClosingPairs[i].open] = autoClosingPairs[i].close; + result.autoClosingPairsClose[autoClosingPairs[i].close] = autoClosingPairs[i].open; + } } - } - let surroundingPairs: IAutoClosingPair[]; - if (richEditSupport && richEditSupport.characterPair) { + let surroundingPairs: IAutoClosingPair[]; try { - surroundingPairs = richEditSupport.characterPair.getSurroundingPairs(); + surroundingPairs = characterPairSupport.getSurroundingPairs(); } catch(e) { onUnexpectedError(e); surroundingPairs = null; } - } - if (surroundingPairs) { - for (i = 0; i < surroundingPairs.length; i++) { - result.surroundingPairs[surroundingPairs[i].open] = surroundingPairs[i].close; + if (surroundingPairs) { + for (i = 0; i < surroundingPairs.length; i++) { + result.surroundingPairs[surroundingPairs[i].open] = surroundingPairs[i].close; + } } } diff --git a/src/vs/editor/common/controller/oneCursor.ts b/src/vs/editor/common/controller/oneCursor.ts index 1764dc4bbfc..2551c7e4aa3 100644 --- a/src/vs/editor/common/controller/oneCursor.ts +++ b/src/vs/editor/common/controller/oneCursor.ts @@ -15,7 +15,7 @@ import {Range} from 'vs/editor/common/core/range'; import {Selection} from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {IElectricAction, IndentAction} from 'vs/editor/common/modes'; -import {getEnterActionAtPosition} from 'vs/editor/common/modes/supports/onEnter'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface IPostOperationRunnable { (ctx: IOneCursorOperationContext): void; @@ -1196,7 +1196,7 @@ export class OneCursorOp { } ctx.shouldPushStackElementBefore = true; - let r = getEnterActionAtPosition(cursor.model, position.lineNumber, position.column); + let r = LanguageConfigurationRegistry.getEnterActionAtPosition(cursor.model, position.lineNumber, position.column); let enterAction = r.enterAction; let indentation = r.indentation; @@ -1269,9 +1269,9 @@ export class OneCursorOp { return false; } - let richEditSupport = cursor.model.getMode().richEditSupport; + let characterPairSupport = LanguageConfigurationRegistry.getCharacterPairSupport(cursor.model.getMode().getId()); - if(!richEditSupport || !richEditSupport.characterPair) { + if(!characterPairSupport) { return false; } @@ -1297,7 +1297,7 @@ export class OneCursorOp { let shouldAutoClosePair = false; try { - shouldAutoClosePair = richEditSupport.characterPair.shouldAutoClosePair(ch, lineContext, position.column - 1); + shouldAutoClosePair = characterPairSupport.shouldAutoClosePair(ch, lineContext, position.column - 1); } catch(e) { onUnexpectedError(e); } @@ -1380,10 +1380,10 @@ export class OneCursorOp { let lineContext = cursor.model.getLineContext(position.lineNumber); let electricAction:IElectricAction; - let richEditSupport = cursor.model.getMode().richEditSupport; - if(richEditSupport && richEditSupport.electricCharacter) { + let electricCharSupport = LanguageConfigurationRegistry.getElectricCharacterSupport(cursor.model.getMode().getId()); + if (electricCharSupport) { try { - electricAction = richEditSupport.electricCharacter.onElectricCharacter(lineContext, position.column - 2); + electricAction = electricCharSupport.onElectricCharacter(lineContext, position.column - 2); } catch(e) { onUnexpectedError(e); } @@ -1488,7 +1488,7 @@ export class OneCursorOp { return '\t'; } - let r = getEnterActionAtPosition(cursor.model, lastLineNumber, cursor.model.getLineMaxColumn(lastLineNumber)); + let r = LanguageConfigurationRegistry.getEnterActionAtPosition(cursor.model, lastLineNumber, cursor.model.getLineMaxColumn(lastLineNumber)); let indentation: string; if (r.enterAction.indentAction === IndentAction.Outdent) { diff --git a/src/vs/editor/common/core/modeTransition.ts b/src/vs/editor/common/core/modeTransition.ts index 33882fa2084..77cfa4b45b6 100644 --- a/src/vs/editor/common/core/modeTransition.ts +++ b/src/vs/editor/common/core/modeTransition.ts @@ -12,10 +12,12 @@ export class ModeTransition { public startIndex:number; public mode:IMode; + public modeId: string; constructor(startIndex:number, mode:IMode) { this.startIndex = startIndex|0; this.mode = mode; + this.modeId = mode.getId(); } public static findIndexInSegmentsArray(arr:ModeTransition[], desiredIndex: number): number { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 3de5cc1824a..4bab8cced1d 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -10,13 +10,14 @@ import {IHTMLContentElement} from 'vs/base/common/htmlContent'; import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; import {IInstantiationService, IConstructorSignature1, IConstructorSignature2} from 'vs/platform/instantiation/common/instantiation'; -import {ILineContext, IMode, IModeTransition, IToken} from 'vs/editor/common/modes'; +import {ILineContext, IMode, IToken} from 'vs/editor/common/modes'; import {ViewLineToken} from 'vs/editor/common/core/viewLineToken'; import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions'; import {IDisposable} from 'vs/base/common/lifecycle'; import {Position} from 'vs/editor/common/core/position'; import {Range} from 'vs/editor/common/core/range'; import {Selection} from 'vs/editor/common/core/selection'; +import {ModeTransition} from 'vs/editor/common/core/modeTransition'; /** * @internal @@ -953,7 +954,6 @@ export interface IConfigurationChangedEvent { */ export interface IModeSupportChangedEvent { tokenizationSupport:boolean; - richEditSupport: boolean; } /** @@ -1677,7 +1677,7 @@ export interface ITokenizedModel extends ITextModel { /** * @internal */ - _getLineModeTransitions(lineNumber:number): IModeTransition[]; + _getLineModeTransitions(lineNumber:number): ModeTransition[]; /** * Get the current language mode associated with the model. @@ -1702,7 +1702,7 @@ export interface ITokenizedModel extends ITextModel { * Returns the true (inner-most) language mode at a given position. * @internal */ - getModeAtPosition(lineNumber:number, column:number): IMode; + getModeIdAtPosition(lineNumber:number, column:number): string; /** * Get the word under or besides `position`. diff --git a/src/vs/editor/common/languages.common.ts b/src/vs/editor/common/languages.common.ts index 76bf17a9d9b..8268267aea3 100644 --- a/src/vs/editor/common/languages.common.ts +++ b/src/vs/editor/common/languages.common.ts @@ -33,10 +33,9 @@ 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/monarchDefinition'; import 'vs/editor/common/modes/monarch/monarchLexer'; import 'vs/editor/common/modes/monarch/monarchCompile'; -import 'vs/editor/common/modes/supports/richEditSupport'; +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'; diff --git a/src/vs/editor/common/model/mirrorModel.ts b/src/vs/editor/common/model/mirrorModel.ts index f0d67503968..a6772272684 100644 --- a/src/vs/editor/common/model/mirrorModel.ts +++ b/src/vs/editor/common/model/mirrorModel.ts @@ -255,9 +255,9 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi } public getEmbeddedAtPosition(position:editorCommon.IPosition):editorCommon.IMirrorModel { - var modeAtPosition = this.getModeAtPosition(position.lineNumber, position.column); - if (this._embeddedModels.hasOwnProperty(modeAtPosition.getId())) { - return this._embeddedModels[modeAtPosition.getId()]; + var modeIdAtPosition = this.getModeIdAtPosition(position.lineNumber, position.column); + if (this._embeddedModels.hasOwnProperty(modeIdAtPosition)) { + return this._embeddedModels[modeIdAtPosition]; } return null; } @@ -299,7 +299,7 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi for (var i = 0; i < modeTransitions.length; i++) { var modeTransition = modeTransitions[i]; - if (modeTransition.mode.getId() !== currentModeId) { + if (modeTransition.modeId !== currentModeId) { var modeRange = getOrCreateEmbeddedModeRange(currentModeId, currentMode); modeRange.ranges.push({ @@ -309,7 +309,7 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi endColumn: modeTransition.startIndex + 1 }); - currentModeId = modeTransition.mode.getId(); + currentModeId = modeTransition.modeId; currentMode = modeTransition.mode; currentStartLineNumber = lineNumber; currentStartColumn = modeTransition.startIndex + 1; diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index fd8b9739a3f..ff3c5dc9da8 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -25,6 +25,7 @@ import {ModeTransition} from 'vs/editor/common/core/modeTransition'; import {LineToken} from 'vs/editor/common/model/lineToken'; import {TokensInflatorMap} from 'vs/editor/common/model/tokensBinaryEncoding'; import {Position} from 'vs/editor/common/core/position'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; class ModeToModelBinder implements IDisposable { @@ -440,7 +441,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke } } - public getModeAtPosition(_lineNumber:number, _column:number): IMode { + public getModeIdAtPosition(_lineNumber:number, _column:number): string { var validPosition = this.validatePosition({ lineNumber: _lineNumber, column: _column @@ -450,13 +451,13 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke var column = validPosition.column; if (column === 1) { - return this.getStateBeforeLine(lineNumber).getMode(); + return this.getStateBeforeLine(lineNumber).getMode().getId(); } else if (column === this.getLineMaxColumn(lineNumber)) { - return this.getStateAfterLine(lineNumber).getMode(); + return this.getStateAfterLine(lineNumber).getMode().getId(); } else { var modeTransitions = this._getLineModeTransitions(lineNumber); var modeTransitionIndex = ModeTransition.findIndexInSegmentsArray(modeTransitions, column - 1); - return modeTransitions[modeTransitionIndex].mode; + return modeTransitions[modeTransitionIndex].modeId; } } @@ -761,7 +762,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke let modeTransitions = this._lines[position.lineNumber - 1].getModeTransitions(this._mode); let currentModeIndex = ModeTransition.findIndexInSegmentsArray(modeTransitions, position.column - 1); let currentMode = modeTransitions[currentModeIndex]; - let currentModeBrackets = currentMode.mode.richEditSupport ? currentMode.mode.richEditSupport.brackets : null; + let currentModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(currentMode.modeId); if (!currentModeBrackets) { return null; @@ -791,7 +792,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke let modeTransitions = this._lines[lineNumber - 1].getModeTransitions(this._mode); let currentModeIndex = ModeTransition.findIndexInSegmentsArray(modeTransitions, position.column - 1); let currentMode = modeTransitions[currentModeIndex]; - let currentModeBrackets = currentMode.mode.richEditSupport ? currentMode.mode.richEditSupport.brackets : null; + let currentModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(currentMode.modeId); // If position is in between two tokens, try first looking in the previous token if (currentTokenIndex > 0 && currentTokenStart === position.column - 1) { @@ -807,7 +808,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke // check if previous token is in a different mode if (currentModeIndex > 0 && currentMode.startIndex === position.column - 1) { prevMode = modeTransitions[currentModeIndex - 1]; - prevModeBrackets = prevMode.mode.richEditSupport ? prevMode.mode.richEditSupport.brackets : null; + prevModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(prevMode.modeId); } if (prevModeBrackets) { @@ -897,7 +898,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke let modeTransitions = this._lines[lineNumber - 1].getModeTransitions(this._mode); let currentModeIndex = modeTransitions.length - 1; let currentModeStart = modeTransitions[currentModeIndex].startIndex; - let currentModeId = modeTransitions[currentModeIndex].mode.getId(); + let currentModeId = modeTransitions[currentModeIndex].modeId; let tokensLength = lineTokens.getTokenCount() - 1; let currentTokenEnd = lineText.length; @@ -907,7 +908,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke currentModeIndex = ModeTransition.findIndexInSegmentsArray(modeTransitions, position.column - 1); currentModeStart = modeTransitions[currentModeIndex].startIndex; - currentModeId = modeTransitions[currentModeIndex].mode.getId(); + currentModeId = modeTransitions[currentModeIndex].modeId; } for (let tokenIndex = tokensLength; tokenIndex >= 0; tokenIndex--) { @@ -917,7 +918,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke if (currentTokenStart < currentModeStart) { currentModeIndex--; currentModeStart = modeTransitions[currentModeIndex].startIndex; - currentModeId = modeTransitions[currentModeIndex].mode.getId(); + currentModeId = modeTransitions[currentModeIndex].modeId; } if (currentModeId === modeId && !ignoreBracketsInToken(currentTokenType)) { @@ -964,7 +965,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke let modeTransitions = this._lines[lineNumber - 1].getModeTransitions(this._mode); let currentModeIndex = 0; let nextModeStart = (currentModeIndex + 1 < modeTransitions.length ? modeTransitions[currentModeIndex + 1].startIndex : lineText.length + 1); - let currentModeId = modeTransitions[currentModeIndex].mode.getId(); + let currentModeId = modeTransitions[currentModeIndex].modeId; let startTokenIndex = 0; let currentTokenStart = lineTokens.getTokenStartIndex(startTokenIndex); @@ -974,7 +975,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke currentModeIndex = ModeTransition.findIndexInSegmentsArray(modeTransitions, position.column - 1); nextModeStart = (currentModeIndex + 1 < modeTransitions.length ? modeTransitions[currentModeIndex + 1].startIndex : lineText.length + 1); - currentModeId = modeTransitions[currentModeIndex].mode.getId(); + currentModeId = modeTransitions[currentModeIndex].modeId; } for (let tokenIndex = startTokenIndex, tokensLength = lineTokens.getTokenCount(); tokenIndex < tokensLength; tokenIndex++) { @@ -984,7 +985,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke if (currentTokenStart >= nextModeStart) { currentModeIndex++; nextModeStart = (currentModeIndex + 1 < modeTransitions.length ? modeTransitions[currentModeIndex + 1].startIndex : lineText.length + 1); - currentModeId = modeTransitions[currentModeIndex].mode.getId(); + currentModeId = modeTransitions[currentModeIndex].modeId; } if (currentModeId === modeId && !ignoreBracketsInToken(currentTokenType)) { diff --git a/src/vs/editor/common/model/textModelWithTokensHelpers.ts b/src/vs/editor/common/model/textModelWithTokensHelpers.ts index c55991f1d49..63016ce25a4 100644 --- a/src/vs/editor/common/model/textModelWithTokensHelpers.ts +++ b/src/vs/editor/common/model/textModelWithTokensHelpers.ts @@ -8,6 +8,7 @@ import {IPosition, IWordAtPosition} from 'vs/editor/common/editorCommon'; import {IMode, IModeTransition} from 'vs/editor/common/modes'; import {NullMode} from 'vs/editor/common/modes/nullMode'; import {ModeTransition} from 'vs/editor/common/core/modeTransition'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface ITextSource { @@ -27,7 +28,7 @@ export interface INonWordTokenMap { export class WordHelper { private static _safeGetWordDefinition(mode:IMode): RegExp { - return (mode.richEditSupport ? mode.richEditSupport.wordDefinition : null); + return LanguageConfigurationRegistry.getWordDefinition(mode.getId()); } public static ensureValidWordDefinition(wordDefinition?:RegExp): RegExp { diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index f9b7fd283ee..b68ebc3a310 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -180,27 +180,6 @@ export interface ILineContext { findIndexOfOffset(offset:number): number; } -/** - * @internal - */ -export enum MutableSupport { - RichEditSupport = 1, - TokenizationSupport = 2 -} - -/** - * @internal - */ -export function mutableSupportToString(registerableSupport:MutableSupport) { - if (registerableSupport === MutableSupport.RichEditSupport) { - return 'richEditSupport'; - } - if (registerableSupport === MutableSupport.TokenizationSupport) { - return 'tokenizationSupport'; - } - throw new Error('Illegal argument!'); -} - export interface IMode { @@ -221,7 +200,7 @@ export interface IMode { * Register a support by name. Only optional. * @internal */ - registerSupport?(support:MutableSupport, callback:(mode:IMode)=>T): IDisposable; + setTokenizationSupport?(callback:(mode:IMode)=>T): IDisposable; /** * Optional adapter to support tokenization. @@ -246,12 +225,6 @@ export interface IMode { * @internal */ configSupport?:IConfigurationSupport; - - /** - * Optional adapter to support rich editing. - * @internal - */ - richEditSupport?: IRichEditSupport; } /** @@ -787,41 +760,6 @@ export interface IRichEditBrackets { textIsOpenBracket: {[text:string]:boolean;}; } -/** - * @internal - */ -export interface IRichEditSupport { - /** - * Optional adapter for electric characters. - */ - electricCharacter?:IRichEditElectricCharacter; - - /** - * Optional adapter for comment insertion. - */ - comments?:ICommentsConfiguration; - - /** - * Optional adapter for insertion of character pair. - */ - characterPair?:IRichEditCharacterPair; - - /** - * Optional adapter for classification of tokens. - */ - wordDefinition?: RegExp; - - /** - * Optional adapter for custom Enter handling. - */ - onEnter?: IRichEditOnEnter; - - /** - * Optional adapter for brackets. - */ - brackets?: IRichEditBrackets; -} - // --- feature registries ------ /** diff --git a/src/vs/editor/common/modes/abstractMode.ts b/src/vs/editor/common/modes/abstractMode.ts index 9c68600bc5a..cc74556cae1 100644 --- a/src/vs/editor/common/modes/abstractMode.ts +++ b/src/vs/editor/common/modes/abstractMode.ts @@ -102,17 +102,16 @@ export abstract class AbstractMode implements modes.IMode { return this._eventEmitter.addListener2('modeSupportChanged', callback); } - public registerSupport(supportEnum:modes.MutableSupport, callback:(mode:modes.IMode) => T) : IDisposable { - let supportStr = modes.mutableSupportToString(supportEnum); + public setTokenizationSupport(callback:(mode:modes.IMode) => T) : IDisposable { var supportImpl = callback(this); - this[supportStr] = supportImpl; - this._eventEmitter.emit('modeSupportChanged', _createModeSupportChangedEvent(supportEnum)); + this['tokenizationSupport'] = supportImpl; + this._eventEmitter.emit('modeSupportChanged', _createModeSupportChangedEvent()); return { dispose: () => { - if (this[supportStr] === supportImpl) { - delete this[supportStr]; - this._eventEmitter.emit('modeSupportChanged', _createModeSupportChangedEvent(supportEnum)); + if (this['tokenizationSupport'] === supportImpl) { + delete this['tokenizationSupport']; + this._eventEmitter.emit('modeSupportChanged', _createModeSupportChangedEvent()); } } }; @@ -122,7 +121,6 @@ export abstract class AbstractMode implements modes.IMode { class SimplifiedMode implements modes.IMode { tokenizationSupport: modes.ITokenizationSupport; - richEditSupport: modes.IRichEditSupport; private _sourceMode: modes.IMode; private _eventEmitter: EventEmitter; @@ -152,7 +150,6 @@ class SimplifiedMode implements modes.IMode { private _assignSupports(): void { this.tokenizationSupport = this._sourceMode.tokenizationSupport; - this.richEditSupport = this._sourceMode.richEditSupport; } } @@ -235,17 +232,8 @@ export class FrankensteinMode extends AbstractMode { } } -function _createModeSupportChangedEvent(supportEnum:modes.MutableSupport): IModeSupportChangedEvent { - let e:IModeSupportChangedEvent = { - richEditSupport: false, - tokenizationSupport: false +function _createModeSupportChangedEvent(): IModeSupportChangedEvent { + return { + tokenizationSupport: true }; - if (supportEnum === modes.MutableSupport.RichEditSupport) { - e.richEditSupport = true; - return e; - } else if (supportEnum === modes.MutableSupport.TokenizationSupport) { - e.tokenizationSupport = true; - return e; - } - throw new Error('Illegal argument!'); } diff --git a/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts new file mode 100644 index 00000000000..bc629365dbd --- /dev/null +++ b/src/vs/editor/common/modes/languageConfigurationRegistry.ts @@ -0,0 +1,258 @@ +/*--------------------------------------------------------------------------------------------- + * 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 {ICommentsConfiguration, IRichEditBrackets, IRichEditCharacterPair, IAutoClosingPair, + IAutoClosingPairConditional, IRichEditOnEnter, CharacterPair, + IRichEditElectricCharacter, IEnterAction, IndentAction} from 'vs/editor/common/modes'; +import {NullMode} from 'vs/editor/common/modes/nullMode'; +import {CharacterPairSupport} from 'vs/editor/common/modes/supports/characterPair'; +import {BracketElectricCharacterSupport, IBracketElectricCharacterContribution} from 'vs/editor/common/modes/supports/electricCharacter'; +import {IIndentationRules, IOnEnterRegExpRules, IOnEnterSupportOptions, OnEnterSupport} from 'vs/editor/common/modes/supports/onEnter'; +import {RichEditBrackets} from 'vs/editor/common/modes/supports/richEditBrackets'; +import Event, {Emitter} from 'vs/base/common/event'; +import {ITokenizedModel} from 'vs/editor/common/editorCommon'; +import {onUnexpectedError} from 'vs/base/common/errors'; +import {Position} from 'vs/editor/common/core/position'; +import * as strings from 'vs/base/common/strings'; +import {IDisposable} from 'vs/base/common/lifecycle'; + +export interface CommentRule { + lineComment?: string; + blockComment?: CharacterPair; +} + +export interface IRichLanguageConfiguration { + comments?: CommentRule; + brackets?: CharacterPair[]; + wordPattern?: RegExp; + indentationRules?: IIndentationRules; + onEnterRules?: IOnEnterRegExpRules[]; + autoClosingPairs?: IAutoClosingPairConditional[]; + surroundingPairs?: IAutoClosingPair[]; + __electricCharacterSupport?: IBracketElectricCharacterContribution; +} + +export class RichEditSupport { + + private _conf: IRichLanguageConfiguration; + + public electricCharacter: BracketElectricCharacterSupport; + public comments: ICommentsConfiguration; + public characterPair: IRichEditCharacterPair; + public wordDefinition: RegExp; + public onEnter: IRichEditOnEnter; + public brackets: IRichEditBrackets; + + constructor(modeId:string, previous:RichEditSupport, rawConf:IRichLanguageConfiguration) { + + let prev:IRichLanguageConfiguration = null; + if (previous) { + prev = previous._conf; + } + + this._conf = RichEditSupport._mergeConf(prev, rawConf); + + if (this._conf.brackets) { + this.brackets = new RichEditBrackets(modeId, this._conf.brackets); + } + + this._handleOnEnter(modeId, this._conf); + + this._handleComments(modeId, this._conf); + + if (this._conf.autoClosingPairs) { + this.characterPair = new CharacterPairSupport(LanguageConfigurationRegistry, modeId, this._conf); + } + + if (this._conf.__electricCharacterSupport || this._conf.brackets) { + this.electricCharacter = new BracketElectricCharacterSupport(LanguageConfigurationRegistry, modeId, this.brackets, this._conf.__electricCharacterSupport); + } + + this.wordDefinition = this._conf.wordPattern || NullMode.DEFAULT_WORD_REGEXP; + } + + private static _mergeConf(prev:IRichLanguageConfiguration, current:IRichLanguageConfiguration): IRichLanguageConfiguration { + return { + comments: (prev ? current.comments || prev.comments : current.comments), + brackets: (prev ? current.brackets || prev.brackets : current.brackets), + wordPattern: (prev ? current.wordPattern || prev.wordPattern : current.wordPattern), + indentationRules: (prev ? current.indentationRules || prev.indentationRules : current.indentationRules), + onEnterRules: (prev ? current.onEnterRules || prev.onEnterRules : current.onEnterRules), + autoClosingPairs: (prev ? current.autoClosingPairs || prev.autoClosingPairs : current.autoClosingPairs), + surroundingPairs: (prev ? current.surroundingPairs || prev.surroundingPairs : current.surroundingPairs), + __electricCharacterSupport: (prev ? current.__electricCharacterSupport || prev.__electricCharacterSupport : current.__electricCharacterSupport), + }; + } + + private _handleOnEnter(modeId:string, conf:IRichLanguageConfiguration): void { + // on enter + let onEnter: IOnEnterSupportOptions = {}; + let empty = true; + + if (conf.brackets) { + empty = false; + onEnter.brackets = conf.brackets; + } + if (conf.indentationRules) { + empty = false; + onEnter.indentationRules = conf.indentationRules; + } + if (conf.onEnterRules) { + empty = false; + onEnter.regExpRules = conf.onEnterRules; + } + + if (!empty) { + this.onEnter = new OnEnterSupport(LanguageConfigurationRegistry, modeId, onEnter); + } + } + + private _handleComments(modeId:string, conf:IRichLanguageConfiguration): void { + let commentRule = conf.comments; + + // comment configuration + if (commentRule) { + this.comments = {}; + + if (commentRule.lineComment) { + this.comments.lineCommentToken = commentRule.lineComment; + } + if (commentRule.blockComment) { + let [blockStart, blockEnd] = commentRule.blockComment; + this.comments.blockCommentStartToken = blockStart; + this.comments.blockCommentEndToken = blockEnd; + } + } + } + +} + +export class LanguageConfigurationRegistryImpl { + + private _entries: {[languageId:string]:RichEditSupport;}; + + private _onDidChange: Emitter = new Emitter(); + public onDidChange: Event = this._onDidChange.event; + + constructor() { + this._entries = Object.create(null); + } + + public register(languageId:string, configuration:IRichLanguageConfiguration): IDisposable { + let previous = this._entries[languageId] || null; + this._entries[languageId] = new RichEditSupport(languageId, previous, configuration); + this._onDidChange.fire(void 0); + return { + dispose: () => {} + }; + } + + private _getRichEditSupport(modeId:string): RichEditSupport { + return this._entries[modeId]; + } + + public getElectricCharacterSupport(modeId:string): IRichEditElectricCharacter { + let value = this._getRichEditSupport(modeId); + if (!value) { + return null; + } + return value.electricCharacter || null; + } + + public getComments(modeId:string): ICommentsConfiguration { + let value = this._getRichEditSupport(modeId); + if (!value) { + return null; + } + return value.comments || null; + } + + public getCharacterPairSupport(modeId:string): IRichEditCharacterPair { + let value = this._getRichEditSupport(modeId); + if (!value) { + return null; + } + return value.characterPair || null; + } + + public getWordDefinition(modeId:string): RegExp { + let value = this._getRichEditSupport(modeId); + if (!value) { + return null; + } + return value.wordDefinition || null; + } + + public getOnEnterSupport(modeId:string): IRichEditOnEnter { + let value = this._getRichEditSupport(modeId); + if (!value) { + return null; + } + return value.onEnter || null; + } + + public getRawEnterActionAtPosition(model:ITokenizedModel, lineNumber:number, column:number): IEnterAction { + let result:IEnterAction; + + let onEnterSupport = this.getOnEnterSupport(model.getMode().getId()); + + if (onEnterSupport) { + try { + result = onEnterSupport.onEnter(model, new Position(lineNumber, column)); + } catch (e) { + onUnexpectedError(e); + } + } + + return result; + } + + public getEnterActionAtPosition(model:ITokenizedModel, lineNumber:number, column:number): { enterAction: IEnterAction; indentation: string; } { + let lineText = model.getLineContent(lineNumber); + let indentation = strings.getLeadingWhitespace(lineText); + if (indentation.length > column - 1) { + indentation = indentation.substring(0, column - 1); + } + + let enterAction = this.getRawEnterActionAtPosition(model, lineNumber, column); + if (!enterAction) { + enterAction = { + indentAction: IndentAction.None, + appendText: '', + }; + } else { + if(!enterAction.appendText) { + if ( + (enterAction.indentAction === IndentAction.Indent) || + (enterAction.indentAction === IndentAction.IndentOutdent) + ) { + enterAction.appendText = '\t'; + } else { + enterAction.appendText = ''; + } + } + } + + if (enterAction.removeText) { + indentation = indentation.substring(0, indentation.length - 1); + } + + return { + enterAction: enterAction, + indentation: indentation + }; + } + + public getBracketsSupport(modeId:string): IRichEditBrackets { + let value = this._getRichEditSupport(modeId); + if (!value) { + return null; + } + return value.brackets || null; + } +} + +export const LanguageConfigurationRegistry = new LanguageConfigurationRegistryImpl(); diff --git a/src/vs/editor/common/modes/monarch/monarchCommon.ts b/src/vs/editor/common/modes/monarch/monarchCommon.ts index d4762e29cd0..a6eb7879559 100644 --- a/src/vs/editor/common/modes/monarch/monarchCommon.ts +++ b/src/vs/editor/common/modes/monarch/monarchCommon.ts @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {CharacterPair, IAutoClosingPairConditional} from 'vs/editor/common/modes'; - /* * This module exports common types and functionality shared between * the Monarch compiler that compiles JSON to ILexer, and the Monarch @@ -24,10 +22,9 @@ export enum MonarchBracket { } export interface ILexerMin { + languageId: string; noThrow: boolean; ignoreCase: boolean; - displayName: string; - name: string; usesEmbedded: boolean; defaultToken: string; stateNames: Object; @@ -37,30 +34,10 @@ export interface ILexer extends ILexerMin { maxStack: number; start: string; ignoreCase: boolean; - lineComment: string; - blockCommentStart: string; - blockCommentEnd: string; tokenPostfix: string; tokenizer: IRule[][]; brackets: IBracket[]; - wordDefinition: RegExp; - autoClosingPairs: IAutoClosingPairConditional[]; - - standardBrackets: CharacterPair[]; - // enhancedBrackets: IRegexBracketPair[]; - outdentTriggers: string; -} - -export interface IAutoIndent { - match: RegExp; - matchAfter: RegExp; -} - -export interface IAutoComplete { - triggers: string; - match: RegExp; - complete: string; } export interface IBracket { @@ -130,7 +107,7 @@ export function sanitize(s: string) { * Logs a message. */ export function log(lexer: ILexerMin, msg: string) { - console.log(`${lexer.name}: ${msg}`); + console.log(`${lexer.languageId}: ${msg}`); } // Throwing errors @@ -139,7 +116,7 @@ export function log(lexer: ILexerMin, msg: string) { * Throws error. May actually just log the error and continue. */ export function throwError(lexer: ILexerMin, msg: string) { - throw new Error(`${lexer.name}: ${msg}`); + throw new Error(`${lexer.languageId}: ${msg}`); } // Helper functions for rule finding and substitution diff --git a/src/vs/editor/common/modes/monarch/monarchCompile.ts b/src/vs/editor/common/modes/monarch/monarchCompile.ts index b363ff200ae..913651b60d1 100644 --- a/src/vs/editor/common/modes/monarch/monarchCompile.ts +++ b/src/vs/editor/common/modes/monarch/monarchCompile.ts @@ -10,7 +10,6 @@ */ import * as objects from 'vs/base/common/objects'; -import {IAutoClosingPairConditional, CharacterPair} from 'vs/editor/common/modes'; import * as monarchCommon from 'vs/editor/common/modes/monarch/monarchCommon'; import {ILanguage, ILanguageBracket} from 'vs/editor/common/modes/monarch/monarchTypes'; @@ -387,20 +386,14 @@ class Rule implements monarchCommon.IRule { * (Currently we have no samples that need this so perhaps we should always have * jsonStrict to true). */ -export function compile(json: ILanguage): monarchCommon.ILexer { +export function compile(languageId:string, json: ILanguage): monarchCommon.ILexer { if (!json || typeof (json) !== 'object') { throw new Error('Monarch: expecting a language definition object'); } - // Get names - if (typeof (json.name) !== 'string') { - throw new Error('Monarch: a language definition must include a string \'name\' attribute'); - } - // Create our lexer var lexer: monarchCommon.ILexer = {}; - lexer.name = json.name; - lexer.displayName = string(json.displayName, lexer.name); + lexer.languageId = languageId; lexer.noThrow = false; // raise exceptions during compilation lexer.maxStack = 100; @@ -408,29 +401,14 @@ export function compile(json: ILanguage): monarchCommon.ILexer { lexer.start = string(json.start); lexer.ignoreCase = bool(json.ignoreCase, false); - lexer.lineComment = string(json.lineComment, '//'); - lexer.blockCommentStart = string(json.blockCommentStart, '/*'); - lexer.blockCommentEnd = string(json.blockCommentEnd, '*/'); - lexer.tokenPostfix = string(json.tokenPostfix, '.' + lexer.name); + lexer.tokenPostfix = string(json.tokenPostfix, '.' + lexer.languageId); lexer.defaultToken = string(json.defaultToken, 'source', function () { monarchCommon.throwError(lexer, 'the \'defaultToken\' must be a string'); }); lexer.usesEmbedded = false; // becomes true if we find a nextEmbedded action - lexer.wordDefinition = json.wordDefinition || undefined; - - // COMPAT: with earlier monarch versions - if (!lexer.lineComment && (json).lineComments) { - if (typeof ((json).lineComments) === 'string') { - lexer.lineComment = (json).lineComments; - } - else if (typeof ((json).lineComments[0]) === 'string') { - lexer.lineComment = (json).lineComments[0]; - } - } // For calling compileAction later on var lexerMin: monarchCommon.ILexerMin = json; - lexerMin.name = lexer.name; - lexerMin.displayName = lexer.displayName; + lexerMin.languageId = languageId; lexerMin.ignoreCase = lexer.ignoreCase; lexerMin.noThrow = lexer.noThrow; lexerMin.usesEmbedded = lexer.usesEmbedded; @@ -559,105 +537,6 @@ export function compile(json: ILanguage): monarchCommon.ILexer { } lexer.brackets = brackets; - // Set default auto closing pairs - var autoClosingPairs: any/*string[][]*/; - if (json.autoClosingPairs) { - if (!(Array.isArray(json.autoClosingPairs))) { - monarchCommon.throwError(lexer, 'the \'autoClosingPairs\' attribute must be an array of string pairs (as arrays)'); - } - autoClosingPairs = json.autoClosingPairs.slice(0); - } - else { - autoClosingPairs = [['"', '"'], ['\'', '\''], ['@brackets']]; - } - - // set auto closing pairs - lexer.autoClosingPairs = []; - if (autoClosingPairs) { - for (var autoClosingPairIdx in autoClosingPairs) { - if (autoClosingPairs.hasOwnProperty(autoClosingPairIdx)) { - var pair = autoClosingPairs[autoClosingPairIdx]; - var openClose: IAutoClosingPairConditional; - if (pair === '@brackets' || pair[0] === '@brackets') { - var bidx: string; - for (bidx in brackets) { - if (brackets.hasOwnProperty(bidx)) { - if (brackets[bidx].open && brackets[bidx].open.length === 1 && - brackets[bidx].close && brackets[bidx].close.length === 1) { - openClose = { open: brackets[bidx].open, close: brackets[bidx].close, notIn:['string', 'comment'] }; - lexer.autoClosingPairs.push(openClose); - } - } - } - } - else if (Array.isArray(pair) && pair.length === 2 && - typeof (pair[0]) === 'string' && pair[0].length === 1 && - typeof (pair[1]) === 'string' && pair[1].length === 1) { - openClose = { open: monarchCommon.fixCase(lexer, pair[0]), close: monarchCommon.fixCase(lexer, pair[1]), notIn:['string', 'comment'] }; - lexer.autoClosingPairs.push(openClose); - } - else if (typeof (pair.open) === 'string' && pair.open.length === 1 && - typeof (pair.close) === 'string' && pair.close.length === 1) { - openClose = { open: monarchCommon.fixCase(lexer, pair.open[0]), close: monarchCommon.fixCase(lexer, pair.close[0]), notIn:['string', 'comment'] }; - lexer.autoClosingPairs.push(openClose); - } - else { - monarchCommon.throwError(lexer, 'every element in an \'autoClosingPairs\' array must be a pair of 1 character strings, or a \'@brackets\' directive'); - } - } - } - } - - // Set enhanced brackets - // var enhancedBrackets : IRegexBracketPair[] = []; - // if (json.enhancedBrackets) { - // if (!(Array.isArray(json.enhancedBrackets))) { - // monarchCommon.throwError(lexer, 'the \'enhancedBrackets\' attribute must be defined as an array'); - // } - - // for (var bracketIdx in json.enhancedBrackets) { - // if (json.enhancedBrackets.hasOwnProperty(bracketIdx)) { - // var desc = json.enhancedBrackets[bracketIdx]; - // if (desc.hasOwnProperty('openTrigger') && typeof (desc.openTrigger) !== 'string') { - // monarchCommon.throwError(lexer, 'openTrigger in the \'enhancedBrackets\' array must be a string'); - // } - // if (desc.hasOwnProperty('open') && !(desc.open instanceof RegExp)) { - // monarchCommon.throwError(lexer, 'open in the \'enhancedBrackets\' array must be a regex'); - // } - // if (desc.hasOwnProperty('closeComplete') && typeof (desc.closeComplete) !== 'string') { - // monarchCommon.throwError(lexer, 'closeComplete in the \'enhancedBrackets\' array must be a string'); - // } - // if (desc.hasOwnProperty('matchCase') && typeof (desc.matchCase) !== 'boolean') { - // monarchCommon.throwError(lexer, 'matchCase in the \'enhancedBrackets\' array must be a boolean'); - // } - // if (desc.hasOwnProperty('closeTrigger') && typeof (desc.closeTrigger) !== 'string') { - // monarchCommon.throwError(lexer, 'closeTrigger in the \'enhancedBrackets\' array must be a string'); - // } - // if (desc.hasOwnProperty('close') && !(desc.close instanceof RegExp)) { - // monarchCommon.throwError(lexer, 'close in the \'enhancedBrackets\' array must be a regex'); - // } - // if (desc.hasOwnProperty('tokenType')) { - // if (typeof (desc.tokenType) !== 'string') { - // monarchCommon.throwError(lexer, 'tokenType in the \'enhancedBrackets\' array must be a string'); - // } - // else { - // desc.tokenType += lexer.tokenPostfix; - // } - // } - // enhancedBrackets.push(desc); - // } - // } - // } - // lexer.enhancedBrackets = enhancedBrackets; - - var standardBrackets: CharacterPair[] = []; - for (var i = 0; i < brackets.length; ++i) { - standardBrackets.push([brackets[i].open, brackets[i].close]); - } - lexer.standardBrackets = standardBrackets; - - lexer.outdentTriggers = string(json.outdentTriggers, ''); - // Disable throw so the syntax highlighter goes, no matter what lexer.noThrow = true; return lexer; diff --git a/src/vs/editor/common/modes/monarch/monarchDefinition.ts b/src/vs/editor/common/modes/monarch/monarchDefinition.ts deleted file mode 100644 index bc47b51531f..00000000000 --- a/src/vs/editor/common/modes/monarch/monarchDefinition.ts +++ /dev/null @@ -1,36 +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'; - -/** - * Create a syntax highighter with a fully declarative JSON style lexer description - * using regular expressions. - */ - -import {ILexer} from 'vs/editor/common/modes/monarch/monarchCommon'; -import {IRichLanguageConfiguration} from 'vs/editor/common/modes/supports/richEditSupport'; - -export function createRichEditSupport(lexer: ILexer): IRichLanguageConfiguration { - - return { - - wordPattern: lexer.wordDefinition, - - comments: { - lineComment: lexer.lineComment, - blockComment: [lexer.blockCommentStart, lexer.blockCommentEnd] - }, - - brackets: lexer.standardBrackets, - - autoClosingPairs: lexer.autoClosingPairs, - - __electricCharacterSupport: { - // regexBrackets: lexer.enhancedBrackets, - caseInsensitive: lexer.ignoreCase, - embeddedElectricCharacters: lexer.outdentTriggers.split('') - } - }; -} diff --git a/src/vs/editor/common/modes/monarch/monarchLexer.ts b/src/vs/editor/common/modes/monarch/monarchLexer.ts index 2ac624182f7..3bd663a24ef 100644 --- a/src/vs/editor/common/modes/monarch/monarchLexer.ts +++ b/src/vs/editor/common/modes/monarch/monarchLexer.ts @@ -72,7 +72,7 @@ export class MonarchLexer extends AbstractState { return false; } var otherm: MonarchLexer = other; - if ((this.stack.length !== otherm.stack.length) || (this.lexer.name !== otherm.lexer.name) || + if ((this.stack.length !== otherm.stack.length) || (this.lexer.languageId !== otherm.lexer.languageId) || (this.embeddedMode !== otherm.embeddedMode)) { return false; } @@ -288,7 +288,7 @@ export class MonarchLexer extends AbstractState { } if (action.log && typeof (action.log) === 'string') { - monarchCommon.log(this.lexer, this.lexer.displayName + ': ' + monarchCommon.substituteMatches(this.lexer, action.log, matched, matches, state)); + monarchCommon.log(this.lexer, this.lexer.languageId + ': ' + monarchCommon.substituteMatches(this.lexer, action.log, matched, matches, state)); } } diff --git a/src/vs/editor/common/modes/monarch/monarchTypes.ts b/src/vs/editor/common/modes/monarch/monarchTypes.ts index 2e818456203..5473b804fa8 100644 --- a/src/vs/editor/common/modes/monarch/monarchTypes.ts +++ b/src/vs/editor/common/modes/monarch/monarchTypes.ts @@ -14,35 +14,14 @@ * A Monarch language definition */ export interface ILanguage { - /** - * unique name to identify the language. - */ - name: string; /** * map from string to ILanguageRule[] */ tokenizer: Object; - - /** - * nice display name - */ - displayName?: string; /** * is the language case insensitive? */ ignoreCase?: boolean; - /** - * used to insert/delete line comments in the editor - */ - lineComment?: string; - /** - * used to insert/delete block comments in the editor - */ - blockCommentStart?: string; - /** - * used to insert/delete block comments in the editor - */ - blockCommentEnd?: string; /** * if no match in the tokenizer assign this token class (default 'source') */ @@ -51,8 +30,6 @@ export interface ILanguage { * for example [['{','}','delimiter.curly']] */ brackets?: ILanguageBracket[]; - - // advanced /** * start symbol in the tokenizer (by default the first entry is used) */ @@ -60,23 +37,7 @@ export interface ILanguage { /** * attach this to every token class (by default '.' + name) */ - tokenPostfix?: string; - /** - * for example [['"','"']] - */ - autoClosingPairs?: string[][]; - /** - * word definition regular expression - */ - wordDefinition?: RegExp; - /** - * characters that could potentially cause outdentation - */ - outdentTriggers?: string; - // /** - // * Advanced auto completion, auto indenting, and bracket matching - // */ - // enhancedBrackets?: IRegexBracketPair[]; + tokenPostfix: string; } /** diff --git a/src/vs/editor/common/modes/nullMode.ts b/src/vs/editor/common/modes/nullMode.ts index daaec7053cf..f27f72c6a54 100644 --- a/src/vs/editor/common/modes/nullMode.ts +++ b/src/vs/editor/common/modes/nullMode.ts @@ -81,12 +81,7 @@ export class NullMode implements modes.IMode { public static ID = 'vs.editor.modes.nullMode'; - public richEditSupport: modes.IRichEditSupport; - constructor() { - this.richEditSupport = { - wordDefinition: NullMode.DEFAULT_WORD_REGEXP - }; } public getId():string { diff --git a/src/vs/editor/common/modes/supports.ts b/src/vs/editor/common/modes/supports.ts index ad60086e7c6..62f69a3ba33 100644 --- a/src/vs/editor/common/modes/supports.ts +++ b/src/vs/editor/common/modes/supports.ts @@ -45,10 +45,10 @@ export class LineTokens implements modes.ILineTokens { } } -export function handleEvent(context:modes.ILineContext, offset:number, runner:(mode:modes.IMode, newContext:modes.ILineContext, offset:number)=>T):T { +export function handleEvent(context:modes.ILineContext, offset:number, runner:(modeId:string, newContext:modes.ILineContext, offset:number)=>T):T { var modeTransitions = context.modeTransitions; if (modeTransitions.length === 1) { - return runner(modeTransitions[0].mode, context, offset); + return runner(modeTransitions[0].modeId, context, offset); } var modeIndex = ModeTransition.findIndexInSegmentsArray(modeTransitions, offset); @@ -68,7 +68,7 @@ export function handleEvent(context:modes.ILineContext, offset:number, runner var firstTokenCharacterOffset = context.getTokenStartIndex(firstTokenInModeIndex); var newCtx = new FilteredLineContext(context, nestedMode, firstTokenInModeIndex, nextTokenAfterMode, firstTokenCharacterOffset, nextCharacterAfterModeIndex); - return runner(nestedMode, newCtx, offset - firstTokenCharacterOffset); + return runner(nestedMode.getId(), newCtx, offset - firstTokenCharacterOffset); } export class FilteredLineContext implements modes.ILineContext { diff --git a/src/vs/editor/common/modes/supports/characterPair.ts b/src/vs/editor/common/modes/supports/characterPair.ts index cc49392b049..5ec20e82c0b 100644 --- a/src/vs/editor/common/modes/supports/characterPair.ts +++ b/src/vs/editor/common/modes/supports/characterPair.ts @@ -4,16 +4,19 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IAutoClosingPair, IAutoClosingPairConditional, ILineContext, IMode, IRichEditCharacterPair, CharacterPair} from 'vs/editor/common/modes'; +import {IAutoClosingPair, IAutoClosingPairConditional, ILineContext, IRichEditCharacterPair, CharacterPair} from 'vs/editor/common/modes'; import {handleEvent} from 'vs/editor/common/modes/supports'; +import {LanguageConfigurationRegistryImpl} from 'vs/editor/common/modes/languageConfigurationRegistry'; export class CharacterPairSupport implements IRichEditCharacterPair { + private _registry: LanguageConfigurationRegistryImpl; private _modeId: string; private _autoClosingPairs: IAutoClosingPairConditional[]; private _surroundingPairs: IAutoClosingPair[]; - constructor(modeId: string, config: { brackets?: CharacterPair[]; autoClosingPairs?: IAutoClosingPairConditional[], surroundingPairs?: IAutoClosingPair[]}) { + constructor(registry: LanguageConfigurationRegistryImpl, modeId: string, config: { brackets?: CharacterPair[]; autoClosingPairs?: IAutoClosingPairConditional[], surroundingPairs?: IAutoClosingPair[]}) { + this._registry = registry; this._modeId = modeId; this._autoClosingPairs = config.autoClosingPairs; if (!this._autoClosingPairs) { @@ -27,8 +30,8 @@ export class CharacterPairSupport implements IRichEditCharacterPair { } public shouldAutoClosePair(character:string, context:ILineContext, offset:number): boolean { - return handleEvent(context, offset, (nestedMode:IMode, context:ILineContext, offset:number) => { - if (this._modeId === nestedMode.getId()) { + return handleEvent(context, offset, (nestedModeId:string, context:ILineContext, offset:number) => { + if (this._modeId === nestedModeId) { // Always complete on empty line if (context.getTokenCount() === 0) { @@ -52,11 +55,14 @@ export class CharacterPairSupport implements IRichEditCharacterPair { } return true; - } else if (nestedMode.richEditSupport && nestedMode.richEditSupport.characterPair) { - return nestedMode.richEditSupport.characterPair.shouldAutoClosePair(character, context, offset); - } else { - return null; } + + let characterPairSupport = this._registry.getCharacterPairSupport(nestedModeId); + if (characterPairSupport) { + return characterPairSupport.shouldAutoClosePair(character, context, offset); + } + + return null; }); } diff --git a/src/vs/editor/common/modes/supports/electricCharacter.ts b/src/vs/editor/common/modes/supports/electricCharacter.ts index 674f10c47ec..0cc1f70a177 100644 --- a/src/vs/editor/common/modes/supports/electricCharacter.ts +++ b/src/vs/editor/common/modes/supports/electricCharacter.ts @@ -8,6 +8,7 @@ import * as strings from 'vs/base/common/strings'; import * as modes from 'vs/editor/common/modes'; import {handleEvent, ignoreBracketsInToken} from 'vs/editor/common/modes/supports'; import {BracketsUtils} from 'vs/editor/common/modes/supports/richEditBrackets'; +import {LanguageConfigurationRegistryImpl} from 'vs/editor/common/modes/languageConfigurationRegistry'; /** * Definition of documentation comments (e.g. Javadoc/JSdoc) @@ -21,20 +22,21 @@ export interface IDocComment { export interface IBracketElectricCharacterContribution { docComment?: IDocComment; - caseInsensitive?: boolean; embeddedElectricCharacters?: string[]; } export class BracketElectricCharacterSupport implements modes.IRichEditElectricCharacter { + private _registry: LanguageConfigurationRegistryImpl; private _modeId: string; private contribution: IBracketElectricCharacterContribution; private brackets: Brackets; - constructor(modeId: string, brackets: modes.IRichEditBrackets, contribution: IBracketElectricCharacterContribution) { + constructor(registry:LanguageConfigurationRegistryImpl, modeId: string, brackets: modes.IRichEditBrackets, contribution: IBracketElectricCharacterContribution) { + this._registry = registry; this._modeId = modeId; this.contribution = contribution || {}; - this.brackets = new Brackets(modeId, brackets, this.contribution.docComment, this.contribution.caseInsensitive); + this.brackets = new Brackets(modeId, brackets, this.contribution.docComment); } public getElectricCharacters(): string[]{ @@ -45,14 +47,15 @@ export class BracketElectricCharacterSupport implements modes.IRichEditElectricC } public onElectricCharacter(context:modes.ILineContext, offset:number): modes.IElectricAction { - return handleEvent(context, offset, (nestedMode:modes.IMode, context:modes.ILineContext, offset:number) => { - if (this._modeId === nestedMode.getId()) { + return handleEvent(context, offset, (nestedModeId:string, context:modes.ILineContext, offset:number) => { + if (this._modeId === nestedModeId) { return this.brackets.onElectricCharacter(context, offset); - } else if (nestedMode.richEditSupport && nestedMode.richEditSupport.electricCharacter) { - return nestedMode.richEditSupport.electricCharacter.onElectricCharacter(context, offset); - } else { - return null; } + let electricCharacterSupport = this._registry.getElectricCharacterSupport(nestedModeId); + if (electricCharacterSupport) { + return electricCharacterSupport.onElectricCharacter(context, offset); + } + return null; }); } } @@ -65,7 +68,7 @@ export class Brackets { private _richEditBrackets: modes.IRichEditBrackets; private _docComment: IDocComment; - constructor(modeId: string, richEditBrackets: modes.IRichEditBrackets, docComment: IDocComment = null, caseInsensitive: boolean = false) { + constructor(modeId: string, richEditBrackets: modes.IRichEditBrackets, docComment: IDocComment = null) { this._modeId = modeId; this._richEditBrackets = richEditBrackets; this._docComment = docComment ? docComment : null; diff --git a/src/vs/editor/common/modes/supports/onEnter.ts b/src/vs/editor/common/modes/supports/onEnter.ts index 72bb27cc6b7..b82d2c02e3f 100644 --- a/src/vs/editor/common/modes/supports/onEnter.ts +++ b/src/vs/editor/common/modes/supports/onEnter.ts @@ -6,10 +6,10 @@ import {onUnexpectedError} from 'vs/base/common/errors'; import * as strings from 'vs/base/common/strings'; -import {Position} from 'vs/editor/common/core/position'; import {IPosition, ITextModel, ITokenizedModel} from 'vs/editor/common/editorCommon'; -import {IEnterAction, ILineContext, IMode, IRichEditOnEnter, IndentAction, CharacterPair} from 'vs/editor/common/modes'; +import {IEnterAction, ILineContext, IRichEditOnEnter, IndentAction, CharacterPair} from 'vs/editor/common/modes'; import {handleEvent} from 'vs/editor/common/modes/supports'; +import {LanguageConfigurationRegistryImpl} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface IIndentationRules { decreaseIndentPattern: RegExp; @@ -43,12 +43,14 @@ export class OnEnterSupport implements IRichEditOnEnter { private static _INDENT_OUTDENT: IEnterAction = { indentAction: IndentAction.IndentOutdent }; private static _OUTDENT: IEnterAction = { indentAction: IndentAction.Outdent }; + private _registry: LanguageConfigurationRegistryImpl; private _modeId: string; private _brackets: IProcessedBracketPair[]; private _indentationRules: IIndentationRules; private _regExpRules: IOnEnterRegExpRules[]; - constructor(modeId: string, opts?:IOnEnterSupportOptions) { + constructor(registry: LanguageConfigurationRegistryImpl, modeId: string, opts?:IOnEnterSupportOptions) { + this._registry = registry; opts = opts || {}; opts.brackets = opts.brackets || [ ['(', ')'], @@ -72,14 +74,17 @@ export class OnEnterSupport implements IRichEditOnEnter { public onEnter(model:ITokenizedModel, position: IPosition): IEnterAction { var context = model.getLineContext(position.lineNumber); - return handleEvent(context, position.column - 1, (nestedMode:IMode, context:ILineContext, offset:number) => { - if (this._modeId === nestedMode.getId()) { + return handleEvent(context, position.column - 1, (nestedModeId:string, context:ILineContext, offset:number) => { + if (this._modeId === nestedModeId) { return this._onEnter(model, position); - } else if (nestedMode.richEditSupport && nestedMode.richEditSupport.onEnter) { - return nestedMode.richEditSupport.onEnter.onEnter(model, position); - } else { - return null; } + + let onEnterSupport = this._registry.getOnEnterSupport(nestedModeId); + if (onEnterSupport) { + return onEnterSupport.onEnter(model, position); + } + + return null; }); } @@ -178,53 +183,3 @@ export class OnEnterSupport implements IRichEditOnEnter { } } -export function getRawEnterActionAtPosition(model:ITokenizedModel, lineNumber:number, column:number): IEnterAction { - let result:IEnterAction; - let richEditSupport = model.getMode().richEditSupport; - - if (richEditSupport && richEditSupport.onEnter) { - try { - result = richEditSupport.onEnter.onEnter(model, new Position(lineNumber, column)); - } catch (e) { - onUnexpectedError(e); - } - } - - return result; -} - -export function getEnterActionAtPosition(model:ITokenizedModel, lineNumber:number, column:number): { enterAction: IEnterAction; indentation: string; } { - let lineText = model.getLineContent(lineNumber); - let indentation = strings.getLeadingWhitespace(lineText); - if (indentation.length > column - 1) { - indentation = indentation.substring(0, column - 1); - } - - let enterAction = getRawEnterActionAtPosition(model, lineNumber, column); - if (!enterAction) { - enterAction = { - indentAction: IndentAction.None, - appendText: '', - }; - } else { - if(!enterAction.appendText) { - if ( - (enterAction.indentAction === IndentAction.Indent) || - (enterAction.indentAction === IndentAction.IndentOutdent) - ) { - enterAction.appendText = '\t'; - } else { - enterAction.appendText = ''; - } - } - } - - if (enterAction.removeText) { - indentation = indentation.substring(0, indentation.length - 1); - } - - return { - enterAction: enterAction, - indentation: indentation - }; -} diff --git a/src/vs/editor/common/modes/supports/richEditBrackets.ts b/src/vs/editor/common/modes/supports/richEditBrackets.ts index a684e74f3d6..cfe3e9c713a 100644 --- a/src/vs/editor/common/modes/supports/richEditBrackets.ts +++ b/src/vs/editor/common/modes/supports/richEditBrackets.ts @@ -7,14 +7,14 @@ import * as strings from 'vs/base/common/strings'; import {Range} from 'vs/editor/common/core/range'; import {IRichEditBracket} from 'vs/editor/common/editorCommon'; -import * as modes from 'vs/editor/common/modes'; +import {IRichEditBrackets, CharacterPair} from 'vs/editor/common/modes'; interface ISimpleInternalBracket { open: string; close: string; } -export class RichEditBrackets implements modes.IRichEditBrackets { +export class RichEditBrackets implements IRichEditBrackets { public brackets: IRichEditBracket[]; public forwardRegex: RegExp; @@ -23,7 +23,7 @@ export class RichEditBrackets implements modes.IRichEditBrackets { public textIsBracket: {[text:string]:IRichEditBracket;}; public textIsOpenBracket: {[text:string]:boolean;}; - constructor(modeId: string, brackets: modes.CharacterPair[]) { + constructor(modeId: string, brackets: CharacterPair[]) { this.brackets = brackets.map((b) => { return { modeId: modeId, diff --git a/src/vs/editor/common/modes/supports/richEditSupport.ts b/src/vs/editor/common/modes/supports/richEditSupport.ts deleted file mode 100644 index 301a4cafb41..00000000000 --- a/src/vs/editor/common/modes/supports/richEditSupport.ts +++ /dev/null @@ -1,124 +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 {ICommentsConfiguration, IRichEditBrackets, IRichEditCharacterPair, IAutoClosingPair, - IAutoClosingPairConditional, IRichEditOnEnter, IRichEditSupport, CharacterPair} from 'vs/editor/common/modes'; -import {NullMode} from 'vs/editor/common/modes/nullMode'; -import {CharacterPairSupport} from 'vs/editor/common/modes/supports/characterPair'; -import {BracketElectricCharacterSupport, IBracketElectricCharacterContribution} from 'vs/editor/common/modes/supports/electricCharacter'; -import {IIndentationRules, IOnEnterRegExpRules, IOnEnterSupportOptions, OnEnterSupport} from 'vs/editor/common/modes/supports/onEnter'; -import {RichEditBrackets} from 'vs/editor/common/modes/supports/richEditBrackets'; - -export interface CommentRule { - lineComment?: string; - blockComment?: CharacterPair; -} - -export interface IRichLanguageConfiguration { - comments?: CommentRule; - brackets?: CharacterPair[]; - wordPattern?: RegExp; - indentationRules?: IIndentationRules; - onEnterRules?: IOnEnterRegExpRules[]; - autoClosingPairs?: IAutoClosingPairConditional[]; - surroundingPairs?: IAutoClosingPair[]; - __electricCharacterSupport?: IBracketElectricCharacterContribution; -} - -export class RichEditSupport implements IRichEditSupport { - - private _conf: IRichLanguageConfiguration; - - public electricCharacter: BracketElectricCharacterSupport; - public comments: ICommentsConfiguration; - public characterPair: IRichEditCharacterPair; - public wordDefinition: RegExp; - public onEnter: IRichEditOnEnter; - public brackets: IRichEditBrackets; - - constructor(modeId:string, previous:IRichEditSupport, rawConf:IRichLanguageConfiguration) { - - let prev:IRichLanguageConfiguration = null; - if (previous instanceof RichEditSupport) { - prev = previous._conf; - } - - this._conf = RichEditSupport._mergeConf(prev, rawConf); - - if (this._conf.brackets) { - this.brackets = new RichEditBrackets(modeId, this._conf.brackets); - } - - this._handleOnEnter(modeId, this._conf); - - this._handleComments(modeId, this._conf); - - if (this._conf.autoClosingPairs) { - this.characterPair = new CharacterPairSupport(modeId, this._conf); - } - - if (this._conf.__electricCharacterSupport || this._conf.brackets) { - this.electricCharacter = new BracketElectricCharacterSupport(modeId, this.brackets, this._conf.__electricCharacterSupport); - } - - this.wordDefinition = this._conf.wordPattern || NullMode.DEFAULT_WORD_REGEXP; - } - - private static _mergeConf(prev:IRichLanguageConfiguration, current:IRichLanguageConfiguration): IRichLanguageConfiguration { - return { - comments: (prev ? current.comments || prev.comments : current.comments), - brackets: (prev ? current.brackets || prev.brackets : current.brackets), - wordPattern: (prev ? current.wordPattern || prev.wordPattern : current.wordPattern), - indentationRules: (prev ? current.indentationRules || prev.indentationRules : current.indentationRules), - onEnterRules: (prev ? current.onEnterRules || prev.onEnterRules : current.onEnterRules), - autoClosingPairs: (prev ? current.autoClosingPairs || prev.autoClosingPairs : current.autoClosingPairs), - surroundingPairs: (prev ? current.surroundingPairs || prev.surroundingPairs : current.surroundingPairs), - __electricCharacterSupport: (prev ? current.__electricCharacterSupport || prev.__electricCharacterSupport : current.__electricCharacterSupport), - }; - } - - private _handleOnEnter(modeId:string, conf:IRichLanguageConfiguration): void { - // on enter - let onEnter: IOnEnterSupportOptions = {}; - let empty = true; - - if (conf.brackets) { - empty = false; - onEnter.brackets = conf.brackets; - } - if (conf.indentationRules) { - empty = false; - onEnter.indentationRules = conf.indentationRules; - } - if (conf.onEnterRules) { - empty = false; - onEnter.regExpRules = conf.onEnterRules; - } - - if (!empty) { - this.onEnter = new OnEnterSupport(modeId, onEnter); - } - } - - private _handleComments(modeId:string, conf:IRichLanguageConfiguration): void { - let commentRule = conf.comments; - - // comment configuration - if (commentRule) { - this.comments = {}; - - if (commentRule.lineComment) { - this.comments.lineCommentToken = commentRule.lineComment; - } - if (commentRule.blockComment) { - let [blockStart, blockEnd] = commentRule.blockComment; - this.comments.blockCommentStartToken = blockStart; - this.comments.blockCommentEndToken = blockEnd; - } - } - } - -} diff --git a/src/vs/editor/common/modes/supports/tokenizationSupport.ts b/src/vs/editor/common/modes/supports/tokenizationSupport.ts index a4eb4543602..695a9092b57 100644 --- a/src/vs/editor/common/modes/supports/tokenizationSupport.ts +++ b/src/vs/editor/common/modes/supports/tokenizationSupport.ts @@ -85,7 +85,7 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa this.supportsNestedModes = supportsNestedModes; this._embeddedModesListeners = {}; if (this.supportsNestedModes) { - if (!this._mode.registerSupport) { + if (!this._mode.setTokenizationSupport) { throw new Error('Cannot be a mode with nested modes unless I can emit a tokenizationSupport changed event!'); } } @@ -239,7 +239,7 @@ export class TokenizationSupport implements modes.ITokenizationSupport, IDisposa } if (e.tokenizationSupport) { emitting = true; - this._mode.registerSupport(modes.MutableSupport.TokenizationSupport, (mode) => { + this._mode.setTokenizationSupport((mode) => { return mode.tokenizationSupport; }); emitting = false; diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index ccaaeb52c72..123098a7a34 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -32,7 +32,7 @@ export class EditorWorkerServiceImpl implements IEditorWorkerService { private _workerManager:WorkerManager; - constructor(modelService:IModelService) { + constructor(@IModelService modelService:IModelService) { this._workerManager = new WorkerManager(modelService); } diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index 8679b09bc72..95aca6a6743 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -9,10 +9,6 @@ import {IDisposable} from 'vs/base/common/lifecycle'; import {TPromise} from 'vs/base/common/winjs.base'; import {ServiceIdentifier, createDecorator} from 'vs/platform/instantiation/common/instantiation'; import * as modes from 'vs/editor/common/modes'; -import {ILanguage} from 'vs/editor/common/modes/monarch/monarchTypes'; -import {IRichLanguageConfiguration} from 'vs/editor/common/modes/supports/richEditSupport'; -import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; -import {IModelService} from 'vs/editor/common/services/modelService'; export var IModeService = createDecorator('modeService'); @@ -73,8 +69,6 @@ export interface IModeService { getOrCreateModeByLanguageName(languageName: string): TPromise; getOrCreateModeByFilenameOrFirstLine(filename: string, firstLine?:string): TPromise; - registerRichEditSupport(modeId: string, support: IRichLanguageConfiguration): IDisposable; registerTokenizationSupport(modeId: string, callback: (mode: modes.IMode) => modes.ITokenizationSupport): IDisposable; registerTokenizationSupport2(modeId: string, support: modes.TokensProvider): IDisposable; - registerMonarchDefinition(modelService: IModelService, editorWorkerService: IEditorWorkerService, modeId:string, language:ILanguage): IDisposable; } diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index 7a5e3acc1c1..8b08c71f2a6 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import {onUnexpectedError} from 'vs/base/common/errors'; import Event, {Emitter} from 'vs/base/common/event'; -import {IDisposable, combinedDisposable, empty as EmptyDisposable} from 'vs/base/common/lifecycle'; // TODO@Alex +import {IDisposable, empty as EmptyDisposable} from 'vs/base/common/lifecycle'; // TODO@Alex import * as objects from 'vs/base/common/objects'; import * as paths from 'vs/base/common/paths'; import {TPromise} from 'vs/base/common/winjs.base'; @@ -20,16 +20,8 @@ import {IThreadService, Remotable, ThreadAffinity} from 'vs/platform/thread/comm import * as modes from 'vs/editor/common/modes'; import {FrankensteinMode} from 'vs/editor/common/modes/abstractMode'; import {ILegacyLanguageDefinition, ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; -import {ILexer} from 'vs/editor/common/modes/monarch/monarchCommon'; -import {compile} from 'vs/editor/common/modes/monarch/monarchCompile'; -import {createRichEditSupport} from 'vs/editor/common/modes/monarch/monarchDefinition'; -import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchLexer'; -import {ILanguage} from 'vs/editor/common/modes/monarch/monarchTypes'; -import {IRichLanguageConfiguration, RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; -import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; import {LanguagesRegistry} from 'vs/editor/common/services/languagesRegistry'; import {ILanguageExtensionPoint, IValidLanguageExtensionPoint, IModeLookupResult, IModeService} from 'vs/editor/common/services/modeService'; -import {IModelService} from 'vs/editor/common/services/modelService'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {AbstractState} from 'vs/editor/common/modes/abstractState'; import {Token} from 'vs/editor/common/modes/supports'; @@ -395,18 +387,18 @@ export class ModeServiceImpl implements IModeService { }; } - private _registerModeSupport(mode:modes.IMode, support: modes.MutableSupport, callback: (mode: modes.IMode) => T): IDisposable { - if (mode.registerSupport) { - return mode.registerSupport(support, callback); + private _registerTokenizationSupport(mode:modes.IMode, callback: (mode: modes.IMode) => T): IDisposable { + if (mode.setTokenizationSupport) { + return mode.setTokenizationSupport(callback); } else { - console.warn('Cannot register support ' + modes.mutableSupportToString(support) + ' on mode ' + mode.getId() + ' because it does not support it.'); + console.warn('Cannot register tokenizationSupport on mode ' + mode.getId() + ' because it does not support it.'); return EmptyDisposable; } } - protected registerModeSupport(modeId: string, support: modes.MutableSupport, callback: (mode: modes.IMode) => T): IDisposable { + private registerModeSupport(modeId: string, callback: (mode: modes.IMode) => T): IDisposable { if (this._instantiatedModes.hasOwnProperty(modeId)) { - return this._registerModeSupport(this._instantiatedModes[modeId], support, callback); + return this._registerTokenizationSupport(this._instantiatedModes[modeId], callback); } let cc: (disposable:IDisposable)=>void; @@ -417,7 +409,7 @@ export class ModeServiceImpl implements IModeService { return; } - cc(this._registerModeSupport(mode, support, callback)); + cc(this._registerTokenizationSupport(mode, callback)); disposable.dispose(); }); @@ -428,31 +420,12 @@ export class ModeServiceImpl implements IModeService { }; } - protected doRegisterMonarchDefinition(modeId:string, lexer: ILexer): IDisposable { - return combinedDisposable( - this.registerTokenizationSupport(modeId, (mode: modes.IMode) => { - return createTokenizationSupport(this, mode, lexer); - }), - - this.registerRichEditSupport(modeId, createRichEditSupport(lexer)) - ); - } - - public registerMonarchDefinition(modelService: IModelService, editorWorkerService:IEditorWorkerService, modeId:string, language:ILanguage): IDisposable { - var lexer = compile(objects.clone(language)); - return this.doRegisterMonarchDefinition(modeId, lexer); - } - - public registerRichEditSupport(modeId: string, support: IRichLanguageConfiguration): IDisposable { - return this.registerModeSupport(modeId, modes.MutableSupport.RichEditSupport, (mode) => new RichEditSupport(modeId, mode.richEditSupport, support)); - } - public registerTokenizationSupport(modeId: string, callback: (mode: modes.IMode) => modes.ITokenizationSupport): IDisposable { - return this.registerModeSupport(modeId, modes.MutableSupport.TokenizationSupport, callback); + return this.registerModeSupport(modeId, callback); } public registerTokenizationSupport2(modeId: string, support: modes.TokensProvider): IDisposable { - return this.registerModeSupport(modeId, modes.MutableSupport.TokenizationSupport, (mode) => { + return this.registerModeSupport(modeId, (mode) => { return new TokenizationSupport2Adapter(mode, support); }); } @@ -550,9 +523,9 @@ export class MainThreadModeServiceImpl extends ModeServiceImpl { private _onReadyPromise: TPromise; constructor( - threadService:IThreadService, - extensionService:IExtensionService, - configurationService: IConfigurationService + @IThreadService threadService:IThreadService, + @IExtensionService extensionService:IExtensionService, + @IConfigurationService configurationService:IConfigurationService ) { super(threadService, extensionService); this._configurationService = configurationService; @@ -648,12 +621,6 @@ export class MainThreadModeServiceImpl extends ModeServiceImpl { this._getModeServiceWorkerHelper().instantiateMode(modeId); return super._createMode(modeId); } - - public registerMonarchDefinition(modelService: IModelService, editorWorkerService:IEditorWorkerService, modeId:string, language:ILanguage): IDisposable { - this._getModeServiceWorkerHelper().registerMonarchDefinition(modeId, language); - var lexer = compile(objects.clone(language)); - return super.doRegisterMonarchDefinition(modeId, lexer); - } } export interface IWorkerInitData { @@ -689,8 +656,4 @@ export class ModeServiceWorkerHelper { public configureModeById(modeId:string, options:any):void { this._modeService.configureMode(modeId, options); } - - public registerMonarchDefinition(modeId:string, language:ILanguage): void { - this._modeService.registerMonarchDefinition(null, null, modeId, language); - } } diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 977946b6f24..d3bdb5cf9d8 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -210,11 +210,11 @@ export class ModelServiceImpl implements IModelService { private _models: { [modelId: string]: ModelData; }; constructor( - threadService: IThreadService, - markerService: IMarkerService, - modeService: IModeService, - configurationService: IConfigurationService, - messageService: IMessageService + @IThreadService threadService: IThreadService, + @IMarkerService markerService: IMarkerService, + @IModeService modeService: IModeService, + @IConfigurationService configurationService: IConfigurationService, + @IMessageService messageService: IMessageService ) { this._modelCreationOptions = { tabSize: DEFAULT_INDENTATION.tabSize, diff --git a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts index 30d6bd41cfc..36b24d4f79b 100644 --- a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts @@ -10,6 +10,7 @@ import {Range} from 'vs/editor/common/core/range'; import {Selection} from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {ICommentsConfiguration} from 'vs/editor/common/modes'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export class BlockCommentCommand implements editorCommon.ICommand { @@ -121,8 +122,8 @@ export class BlockCommentCommand implements editorCommon.ICommand { var endLineNumber = this._selection.endLineNumber; var endColumn = this._selection.endColumn; - let richEditSupport = model.getModeAtPosition(startLineNumber, startColumn).richEditSupport; - let config = richEditSupport ? richEditSupport.comments : null; + let modeId = model.getModeIdAtPosition(startLineNumber, startColumn); + let config = LanguageConfigurationRegistry.getComments(modeId); if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) { // Mode does not support block comments return; diff --git a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts index 57cb19c4942..9997968a87a 100644 --- a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts @@ -10,8 +10,9 @@ import {Position} from 'vs/editor/common/core/position'; import {Range} from 'vs/editor/common/core/range'; import {Selection} from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import {ICommentsConfiguration, IMode} from 'vs/editor/common/modes'; +import {ICommentsConfiguration} from 'vs/editor/common/modes'; import {BlockCommentCommand} from './blockCommentCommand'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface IInsertionPoint { ignore: boolean; @@ -69,19 +70,17 @@ export class LineCommentCommand implements editorCommon.ICommand { i:number, lineCount:number, lineNumber:number, - mode: IMode, modeId: string; for (i = 0, lineCount = endLineNumber - startLineNumber + 1; i < lineCount; i++) { lineNumber = startLineNumber + i; - mode = model.getModeAtPosition(lineNumber, 1); - modeId = mode.getId(); + modeId = model.getModeIdAtPosition(lineNumber, 1); // Find the commentStr for this line, if none is found then bail out: we cannot do line comments if (seenModes[modeId]) { commentStr = seenModes[modeId]; } else { - config = (mode.richEditSupport ? mode.richEditSupport.comments : null); + config = LanguageConfigurationRegistry.getComments(modeId); commentStr = (config ? config.lineCommentToken : null); if (!commentStr) { // Mode does not support line comments @@ -273,8 +272,8 @@ export class LineCommentCommand implements editorCommon.ICommand { * Given an unsuccessful analysis, delegate to the block comment command */ private _executeBlockComment(model:editorCommon.ITokenizedModel, builder:editorCommon.IEditOperationBuilder, s:Selection): void { - let richEditSupport = model.getModeAtPosition(s.startLineNumber, s.startColumn).richEditSupport; - let config = richEditSupport ? richEditSupport.comments : null; + let modeId = model.getModeIdAtPosition(s.startLineNumber, s.startColumn); + let config = LanguageConfigurationRegistry.getComments(modeId); if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) { // Mode does not support block comments return; diff --git a/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts index b821b9ad6c2..f9c436feadc 100644 --- a/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts @@ -10,7 +10,7 @@ import {testCommand} from 'vs/editor/test/common/commands/commandTestUtils'; import {CommentMode} from 'vs/editor/test/common/testModes'; function testBlockCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { - var mode = new CommentMode({ lineCommentToken: '!@#', blockCommentStartToken: '<0', blockCommentEndToken: '0>' }); + var mode = new CommentMode({ lineComment: '!@#', blockComment: ['<0', '0>'] }); testCommand(lines, mode, selection, (sel) => new BlockCommentCommand(sel), expectedLines, expectedSelection); } diff --git a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts index 7d022fdcf4b..3374bd80401 100644 --- a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts @@ -13,12 +13,12 @@ import {CommentMode} from 'vs/editor/test/common/testModes'; suite('Editor Contrib - Line Comment Command', () => { function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { - var mode = new CommentMode({ lineCommentToken: '!@#', blockCommentStartToken: '' }); + var mode = new CommentMode({ lineComment: '!@#', blockComment: [''] }); testCommand(lines, mode, selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection); } function testAddLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { - var mode = new CommentMode({ lineCommentToken: '!@#', blockCommentStartToken: '' }); + var mode = new CommentMode({ lineComment: '!@#', blockComment: [''] }); testCommand(lines, mode, selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd), expectedLines, expectedSelection); } @@ -520,7 +520,7 @@ suite('Editor Contrib - Line Comment Command', () => { suite('Editor Contrib - Line Comment As Block Comment', () => { function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { - var mode = new CommentMode({ lineCommentToken: '', blockCommentStartToken: '(', blockCommentEndToken: ')' }); + var mode = new CommentMode({ lineComment: '', blockComment: ['(', ')'] }); testCommand(lines, mode, selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection); } @@ -630,7 +630,7 @@ suite('Editor Contrib - Line Comment As Block Comment', () => { suite('Editor Contrib - Line Comment As Block Comment 2', () => { function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { - var mode = new CommentMode({ lineCommentToken: null, blockCommentStartToken: '' }); + var mode = new CommentMode({ lineComment: null, blockComment: [''] }); testCommand(lines, mode, selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection); } diff --git a/src/vs/editor/contrib/smartSelect/common/tokenTree.ts b/src/vs/editor/contrib/smartSelect/common/tokenTree.ts index 6df50038259..6d542e4015e 100644 --- a/src/vs/editor/contrib/smartSelect/common/tokenTree.ts +++ b/src/vs/editor/contrib/smartSelect/common/tokenTree.ts @@ -7,9 +7,11 @@ import {Position} from 'vs/editor/common/core/position'; import {Range} from 'vs/editor/common/core/range'; import {ILineTokens, IModel, IPosition, IRange, IRichEditBracket} from 'vs/editor/common/editorCommon'; -import {IModeTransition, IRichEditBrackets} from 'vs/editor/common/modes'; +import {IRichEditBrackets} from 'vs/editor/common/modes'; import {ignoreBracketsInToken} from 'vs/editor/common/modes/supports'; import {BracketsUtils} from 'vs/editor/common/modes/supports/richEditBrackets'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; +import {ModeTransition} from 'vs/editor/common/core/modeTransition'; export enum TokenTreeBracket { None = 0, @@ -117,7 +119,7 @@ class TokenScanner { private _currentTokenIndex: number; private _currentTokenStart: number; private _currentLineTokens: ILineTokens; - private _currentLineModeTransitions: IModeTransition[]; + private _currentLineModeTransitions: ModeTransition[]; private _currentModeIndex: number; private _nextModeStart: number; private _currentModeBrackets: IRichEditBrackets; @@ -159,7 +161,7 @@ class TokenScanner { this._currentModeIndex++; this._nextModeStart = (this._currentModeIndex + 1 < this._currentLineModeTransitions.length ? this._currentLineModeTransitions[this._currentModeIndex + 1].startIndex : this._currentLineText.length + 1); let mode = (this._currentModeIndex < this._currentLineModeTransitions.length ? this._currentLineModeTransitions[this._currentModeIndex] : null); - this._currentModeBrackets = (mode && mode.mode.richEditSupport ? mode.mode.richEditSupport.brackets : null); + this._currentModeBrackets = (mode ? LanguageConfigurationRegistry.getBracketsSupport(mode.modeId) : null); } let tokenType = this._currentLineTokens.getTokenType(this._currentTokenIndex); diff --git a/src/vs/editor/contrib/smartSelect/test/common/tokenSelectionSupport.test.ts b/src/vs/editor/contrib/smartSelect/test/common/tokenSelectionSupport.test.ts index 2c60be0d67a..5027d748740 100644 --- a/src/vs/editor/contrib/smartSelect/test/common/tokenSelectionSupport.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/common/tokenSelectionSupport.test.ts @@ -7,20 +7,18 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; import {Range} from 'vs/editor/common/core/range'; -import {IMode, IRichEditSupport, IndentAction} from 'vs/editor/common/modes'; +import {IMode, IndentAction} from 'vs/editor/common/modes'; import {TokenSelectionSupport} from 'vs/editor/contrib/smartSelect/common/tokenSelectionSupport'; import {createMockModelService} from 'vs/editor/test/common/servicesTestUtils'; import {MockTokenizingMode} from 'vs/editor/test/common/mocks/mockMode'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; class MockJSMode extends MockTokenizingMode { - public richEditSupport: IRichEditSupport; - constructor() { - super('js', 'mock-js'); + super('js-tokenSelectionSupport', 'mock-js'); - this.richEditSupport = new RichEditSupport(this.getId(), null, { + LanguageConfigurationRegistry.register(this.getId(), { brackets: [ ['(', ')'], ['{', '}'], diff --git a/src/vs/editor/node/languageConfiguration.ts b/src/vs/editor/node/languageConfiguration.ts index ee164b73212..b036c4cd5b2 100644 --- a/src/vs/editor/node/languageConfiguration.ts +++ b/src/vs/editor/node/languageConfiguration.ts @@ -7,9 +7,10 @@ import * as nls from 'vs/nls'; import {parse} from 'vs/base/common/json'; import {readFile} from 'vs/base/node/pfs'; -import {IRichLanguageConfiguration} from 'vs/editor/common/modes/supports/richEditSupport'; +import {IRichLanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IAutoClosingPair} from 'vs/editor/common/modes'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; type CharacterPair = [string, string]; @@ -88,7 +89,7 @@ export class LanguageConfigurationFileHandler { richEditConfig.surroundingPairs = this._mapCharacterPairs(configuration.surroundingPairs); } - this._modeService.registerRichEditSupport(modeId, richEditConfig); + LanguageConfigurationRegistry.register(modeId, richEditConfig); } private _mapCharacterPairs(pairs:CharacterPair[]): IAutoClosingPair[] { diff --git a/src/vs/editor/standalone-languages/bat.ts b/src/vs/editor/standalone-languages/bat.ts index f4467fc2c9a..9d178571e5f 100644 --- a/src/vs/editor/standalone-languages/bat.ts +++ b/src/vs/editor/standalone-languages/bat.ts @@ -5,24 +5,19 @@ 'use strict'; -import {ILanguage} from './types'; - -export var language = { - displayName: 'Batch', - name: 'bat', - defaultToken: '', - ignoreCase: true, - - lineComment: 'REM', - - autoClosingPairs: [ ['{','}' ], ['[',']' ], ['(',')' ], ['"','"' ]], // Exclude ' - - brackets: [ - { token: 'punctuation.bracket', open: '{', close: '}' }, - { token: 'punctuation.parenthesis', open: '(', close: ')' }, - { token: 'punctuation.square', open: '[', close: ']' } - ], +import {ILanguage, IRichLanguageConfiguration} from './types'; +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: 'REM' + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] // enhancedBrackets: [ // { // openTrigger: 'l', @@ -34,6 +29,18 @@ export var language = { // tokenType: 'keyword.tag-setlocal' // } // ], +}; + +export var language = { + defaultToken: '', + ignoreCase: true, + tokenPostfix: '.bat', + + brackets: [ + { token: 'punctuation.bracket', open: '{', close: '}' }, + { token: 'punctuation.parenthesis', open: '(', close: ')' }, + { token: 'punctuation.square', open: '[', close: ']' } + ], keywords: /call|defined|echo|errorlevel|exist|for|goto|if|pause|set|shift|start|title|not|pushd|popd/, diff --git a/src/vs/editor/standalone-languages/coffee.ts b/src/vs/editor/standalone-languages/coffee.ts index fa4e845f713..87dd292ab73 100644 --- a/src/vs/editor/standalone-languages/coffee.ts +++ b/src/vs/editor/standalone-languages/coffee.ts @@ -5,17 +5,33 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\$\-\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + blockComment: ['###', '###'], + lineComment: '#' + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] + // enhancedBrackets: [ + // { open: /for$/ }, { open: /while$/ }, { open: /loop$/ }, { open: /if$/ }, { open: /unless$/ }, + // { open: /else$/ }, { open: /switch$/ }, { open: /try$/ }, { open: /catch$/ }, { open: /finally$/ }, + // { open: /class$/ }, { open: /->$/ } + // ], +}; export var language = { - displayName: 'CoffeeScript', - name: 'coffee', defaultToken: '', ignoreCase: true, - - lineComment: '#', - blockCommentStart: '###', - blockCommentEnd: '###', + tokenPostfix: '.coffee', brackets: [ { open:'{', close:'}', token:'delimiter.curly'}, @@ -23,14 +39,6 @@ export var language = { { open:'(', close:')', token:'delimiter.parenthesis'} ], - // enhancedBrackets: [ - // { open: /for$/ }, { open: /while$/ }, { open: /loop$/ }, { open: /if$/ }, { open: /unless$/ }, - // { open: /else$/ }, { open: /switch$/ }, { open: /try$/ }, { open: /catch$/ }, { open: /finally$/ }, - // { open: /class$/ }, { open: /->$/ } - // ], - - // the default separators - wordDefinition: /(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\$\-\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, regEx: /\/(?!\/\/)(?:[^\/\\]|\\.)*\/[igm]*/, keywords: [ diff --git a/src/vs/editor/standalone-languages/cpp.ts b/src/vs/editor/standalone-languages/cpp.ts index 1012ac3602d..ed3a5382700 100644 --- a/src/vs/editor/standalone-languages/cpp.ts +++ b/src/vs/editor/standalone-languages/cpp.ts @@ -5,16 +5,25 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'C++', - name: 'cpp', defaultToken: '', - - lineComment: '//', - blockCommentStart: '/*', - blockCommentEnd: '*/', + tokenPostfix: '.cpp', brackets: [ { token: 'delimiter.curly', open: '{', close: '}' }, @@ -23,8 +32,6 @@ export var language = { { token: 'delimiter.angle', open: '<', close: '>' } ], - autoClosingPairs: [ ['{', '}'], ['[', ']'], ['(', ')'], ['"', '"']], // Skip < > which would be there by default. - keywords: [ 'abstract', 'amp', diff --git a/src/vs/editor/standalone-languages/csharp.ts b/src/vs/editor/standalone-languages/csharp.ts index 3134a172f67..1c097ad6e36 100644 --- a/src/vs/editor/standalone-languages/csharp.ts +++ b/src/vs/editor/standalone-languages/csharp.ts @@ -5,28 +5,27 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: '', - name: 'cs', defaultToken: '', - - // used in the editor to insert comments (ctrl+/ or shift+alt+A) - lineComment: '// ', - blockCommentStart: '/*', - blockCommentEnd: '*/', - - // the default separators except `@` - wordDefinition: /(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, - - autoClosingPairs: [ - ['"', '"'], - ['\'', '\''], - ['{', '}'], - ['[', ']'], - ['(', ')'], - ], + tokenPostfix: '.cs', brackets: [ { open: '{', close: '}', token: 'delimiter.curly' }, diff --git a/src/vs/editor/standalone-languages/dockerfile.ts b/src/vs/editor/standalone-languages/dockerfile.ts index af3530fc548..2516932d878 100644 --- a/src/vs/editor/standalone-languages/dockerfile.ts +++ b/src/vs/editor/standalone-languages/dockerfile.ts @@ -5,12 +5,23 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '<', close: '>', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Dockerfile', - name: 'dockerfile', defaultToken: '', + tokenPostfix: '.dockerfile', instructions: /FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|LABEL|USER|WORKDIR|COPY|CMD|ENTRYPOINT/, diff --git a/src/vs/editor/standalone-languages/fsharp.ts b/src/vs/editor/standalone-languages/fsharp.ts index d9c226423f2..82605e111f4 100644 --- a/src/vs/editor/standalone-languages/fsharp.ts +++ b/src/vs/editor/standalone-languages/fsharp.ts @@ -5,18 +5,25 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['(*', '*)'], + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string', 'comment'] } + ] +}; export var language = { - displayName: 'F#', - name: 'fs', defaultToken: '', - - lineComment: '//', - blockCommentStart: '(*', - blockCommentEnd: '*)', - - autoClosingPairs: [ ['{', '}'], ['[', ']'], ['(', ')'], ['"', '"']], // Skip < > which would be there by default. + tokenPostfix: '.fs', keywords: [ 'abstract', 'and', 'atomic', 'as', diff --git a/src/vs/editor/standalone-languages/go.ts b/src/vs/editor/standalone-languages/go.ts index 687ca733e90..77d2eaabd57 100644 --- a/src/vs/editor/standalone-languages/go.ts +++ b/src/vs/editor/standalone-languages/go.ts @@ -5,19 +5,26 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string', 'comment'] } + ] +}; export var language = { - displayName: 'Go', - name: 'go', defaultToken: '', - - lineComment: '//', - blockCommentStart: '/*', - blockCommentEnd: '*/', - - autoClosingPairs: [ ['{', '}'], ['[', ']'], ['(', ')'], ['"', '"']], // Skip < > which would be there by default. + tokenPostfix: '.go', keywords: [ 'break', diff --git a/src/vs/editor/standalone-languages/ini.ts b/src/vs/editor/standalone-languages/ini.ts index e7924706fd9..b36bf454daf 100644 --- a/src/vs/editor/standalone-languages/ini.ts +++ b/src/vs/editor/standalone-languages/ini.ts @@ -5,16 +5,26 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '#' + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '<', close: '>', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Ini', - name: 'ini', defaultToken: '', - - lineComment: '#', - blockCommentStart: '#', - blockCommentEnd: ' ', + tokenPostfix: '.ini', // we include these common regular expressions escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/, diff --git a/src/vs/editor/standalone-languages/jade.ts b/src/vs/editor/standalone-languages/jade.ts index bcc0a419c10..aefe907764e 100644 --- a/src/vs/editor/standalone-languages/jade.ts +++ b/src/vs/editor/standalone-languages/jade.ts @@ -5,17 +5,28 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '//' + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Jade', - name: 'jade', - defaultToken: '', + defaultToken: '', + tokenPostfix: '.jade', ignoreCase: true, - lineComment: '//', - brackets: [ { token:'delimiter.curly', open: '{', close: '}' }, { token:'delimiter.array', open: '[', close: ']' }, diff --git a/src/vs/editor/standalone-languages/java.ts b/src/vs/editor/standalone-languages/java.ts index e9f75b8325b..24653f8c653 100644 --- a/src/vs/editor/standalone-languages/java.ts +++ b/src/vs/editor/standalone-languages/java.ts @@ -5,19 +5,29 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + // the default separators except `@$` + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '<', close: '>', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Java', - name: 'java', defaultToken: '', - - lineComment: '//', - blockCommentStart: '/*', - blockCommentEnd: '*/', - - // the default separators except `@$` - wordDefinition: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + tokenPostfix: '.java', keywords: [ 'abstract', 'continue', 'for', 'new', 'switch', 'assert', 'default', diff --git a/src/vs/editor/standalone-languages/lua.ts b/src/vs/editor/standalone-languages/lua.ts index fca9794696c..51250f1d5f0 100644 --- a/src/vs/editor/standalone-languages/lua.ts +++ b/src/vs/editor/standalone-languages/lua.ts @@ -5,34 +5,44 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '--', + blockComment: ['--[[', ']]'], + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Lua', - name: 'lua', defaultToken: '', - - lineComment: '--', - blockCommentStart: '--[[', - blockCommentEnd: ']]', + tokenPostfix: '.lua', keywords: [ 'and', 'break', 'do', 'else', 'elseif', - 'end', 'false', 'for', 'function', 'goto', 'if', - 'in', 'local', 'nil', 'not', 'or', - 'repeat', 'return', 'then', 'true', 'until', - 'while' + 'end', 'false', 'for', 'function', 'goto', 'if', + 'in', 'local', 'nil', 'not', 'or', + 'repeat', 'return', 'then', 'true', 'until', + 'while' ], brackets: [ - { token: 'delimiter.bracket', open: '{', close: '}'}, - { token: 'delimiter.array', open: '[', close: ']'}, - { token: 'delimiter.parenthesis', open: '(', close: ')'} + { token: 'delimiter.bracket', open: '{', close: '}'}, + { token: 'delimiter.array', open: '[', close: ']'}, + { token: 'delimiter.parenthesis', open: '(', close: ')'} ], operators: [ '+', '-', '*', '/', '%', '^', '#', '==', '~=', '<=', '>=', '<', '>', '=', - ';', ':', ',', '.', '..', '...' + ';', ':', ',', '.', '..', '...' ], // we include these common regular expressions @@ -44,7 +54,7 @@ export var language = { root: [ // identifiers and keywords [/[a-zA-Z_]\w*/, { cases: { '@keywords': {token:'keyword.$0'}, - '@default': 'identifier' } }], + '@default': 'identifier' } }], // whitespace { include: '@whitespace' }, @@ -55,7 +65,7 @@ export var language = { // delimiters and operators [/[{}()\[\]]/, '@brackets'], [/@symbols/, { cases: { '@operators': 'delimiter', - '@default' : '' } } ], + '@default' : '' } } ], // numbers [/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'], @@ -89,7 +99,7 @@ export var language = { [/@escapes/, 'string.escape'], [/\\./, 'string.escape.invalid'], [/["']/, { cases: { '$#==$S2' : { token: 'string', next: '@pop' }, - '@default': 'string' }} ] + '@default': 'string' }} ] ], }, diff --git a/src/vs/editor/standalone-languages/objective-c.ts b/src/vs/editor/standalone-languages/objective-c.ts index 86c5e50f4a5..ceeea41e8aa 100644 --- a/src/vs/editor/standalone-languages/objective-c.ts +++ b/src/vs/editor/standalone-languages/objective-c.ts @@ -5,16 +5,27 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{','}'], ['[',']'], ['(',')'], ['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '<', close: '>', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Objective-C', - name: 'objective-c', defaultToken: '', - - lineComment: '//', - blockCommentStart: '/*', - blockCommentEnd: '*/', + tokenPostfix: '.objective-c', keywords: [ '#import', diff --git a/src/vs/editor/standalone-languages/powershell.ts b/src/vs/editor/standalone-languages/powershell.ts index 1921efa51e7..72432bc0645 100644 --- a/src/vs/editor/standalone-languages/powershell.ts +++ b/src/vs/editor/standalone-languages/powershell.ts @@ -5,36 +5,39 @@ 'use strict'; -import {ILanguage} from './types'; - -export var language = { - displayName: 'PowerShell', - name: 'ps1', - defaultToken: '', - ignoreCase: true, - - lineComment: '#', - blockCommentStart: '<#', - blockCommentEnd: '#>', +import {ILanguage, IRichLanguageConfiguration} from './types'; +export var conf:IRichLanguageConfiguration = { // the default separators except `$-` - wordDefinition: /(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, - - brackets: [ - { token: 'delimiter.curly', open: '{', close: '}' }, - { token: 'delimiter.square', open: '[', close: ']' }, - { token: 'delimiter.parenthesis', open: '(', close: ')' }], - + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '#', + blockComment: ['<#', '#>'], + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] // enhancedBrackets: [ // { tokenType:'string', openTrigger: '"', open: /@"$/, closeComplete: '"@' }, // { tokenType:'string', openTrigger: '\'', open: /@'$/, closeComplete: '\'@' }, // { tokenType:'string', openTrigger: '"', open: /"$/, closeComplete: '"' }, // { tokenType: 'string', openTrigger: '\'', open: /'$/, closeComplete: '\'' } // ], +}; - autoClosingPairs: [['{', '}'], ['[', ']'], ['(', ')']], // Defined explicitly, to suppress the - // default auto-closing of ' and " which is - // override above by enhancedBrackets +export var language = { + defaultToken: '', + ignoreCase: true, + tokenPostfix: '.ps1', + + brackets: [ + { token: 'delimiter.curly', open: '{', close: '}' }, + { token: 'delimiter.square', open: '[', close: ']' }, + { token: 'delimiter.parenthesis', open: '(', close: ')' } + ], keywords: [ 'begin', 'break', 'catch', 'class', 'continue', 'data', diff --git a/src/vs/editor/standalone-languages/python.ts b/src/vs/editor/standalone-languages/python.ts index 0f77fcda89f..239c9855f10 100644 --- a/src/vs/editor/standalone-languages/python.ts +++ b/src/vs/editor/standalone-languages/python.ts @@ -5,16 +5,28 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '#', + blockComment: ['\'\'\'', '\'\'\''], + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] + // Cause an automatic indent to occur after lines ending in :. + // enhancedBrackets: [ { open: /.*:\s*$/, closeComplete: 'else:' } ], +}; export var language = { - displayName: '', - name: 'python', defaultToken: '', - - lineComment: '#', - blockCommentStart: '\'\'\'', - blockCommentEnd: '\'\'\'', + tokenPostfix: '.python', keywords: [ 'and', @@ -155,9 +167,6 @@ export var language = { { open: '(', close: ')', token: 'delimiter.parenthesis' } ], - // Cause an automatic indent to occur after lines ending in :. - // enhancedBrackets: [ { open: /.*:\s*$/, closeComplete: 'else:' } ], - tokenizer: { root: [ { include: '@whitespace' }, diff --git a/src/vs/editor/standalone-languages/r.ts b/src/vs/editor/standalone-languages/r.ts index f8200fb07ac..d4af395dc9b 100644 --- a/src/vs/editor/standalone-languages/r.ts +++ b/src/vs/editor/standalone-languages/r.ts @@ -5,16 +5,25 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '#' + }, + brackets: [['{','}'], ['[',']'], ['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'R', - name: 'r', defaultToken: '', - - lineComment: '#', - blockCommentStart: '', - blockCommentEnd: '', + tokenPostfix: '.r', roxygen: [ '@param', diff --git a/src/vs/editor/standalone-languages/ruby.ts b/src/vs/editor/standalone-languages/ruby.ts index 7ad7eaa2961..6434fb7d196 100644 --- a/src/vs/editor/standalone-languages/ruby.ts +++ b/src/vs/editor/standalone-languages/ruby.ts @@ -5,7 +5,26 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '#', + blockComment: ['=begin', '=end'], + }, + brackets: [['(',')'],['{','}'], ['[',']']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + ], + __electricCharacterSupport: { + // trigger outdenting on 'end' + embeddedElectricCharacters: ['d'] + } +}; /* * Ruby language definition @@ -57,12 +76,7 @@ import {ILanguage} from './types'; */ export var language = { - displayName: '', - name: 'ruby', - - lineComment: '#', - blockCommentStart: '=begin', - blockCommentEnd: '=end', + tokenPostfix: '.ruby', keywords: [ '__LINE__', '__ENCODING__', '__FILE__', 'BEGIN', 'END', 'alias', 'and', 'begin', @@ -102,9 +116,6 @@ export var language = { { open: '[', close: ']', token: 'delimiter.square'} ], - // trigger outdenting on 'end' - outdentTriggers: 'd', - // we include these common regular expressions symbols: /[=> { - displayName: 'SQL', - name: 'sql', - defaultToken: '', - ignoreCase: true, - brackets: [ - { open: '[', close: ']', token: 'delimiter.square' }, - { open: '(', close: ')', token: 'delimiter.parenthesis' } - ], +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '--', + blockComment: ['/*', '*/'], + }, + brackets: [['[',']'],['(',')']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + ] // enhancedBrackets:[ // { openTrigger: 'n', open: /begin$/i, closeComplete: 'end', matchCase: true }, // { openTrigger: 'e', open: /case$/i, closeComplete: 'end', matchCase: true }, // { openTrigger: 'n', open: /when$/i, closeComplete: 'then', matchCase: true } // ], - noindentBrackets: '()', - lineComment: '--', - blockCommentStart: '/*', - blockCommentEnd: '*/', +}; + +export var language = { + defaultToken: '', + tokenPostfix: '.sql', + ignoreCase: true, + + brackets: [ + { open: '[', close: ']', token: 'delimiter.square' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' } + ], + keywords: [ 'ABORT_AFTER_WAIT', 'ABSENT', diff --git a/src/vs/editor/standalone-languages/swift.ts b/src/vs/editor/standalone-languages/swift.ts index c88abece100..f229db1afb4 100644 --- a/src/vs/editor/standalone-languages/swift.ts +++ b/src/vs/editor/standalone-languages/swift.ts @@ -4,16 +4,27 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [['{','}'],['[',']'],['(',')'],['<','>']], + autoClosingPairs: [ + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '<', close: '>', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'Swift', - name: 'swift', defaultToken: '', - - lineComment: '//', - blockCommentStart: '/*', - blockCommentEnd: '*/', + tokenPostfix: '.swift', // TODO(owensd): Support the full range of unicode valid identifiers. identifier: /[a-zA-Z_][\w$]*/, diff --git a/src/vs/editor/standalone-languages/test/bat.test.ts b/src/vs/editor/standalone-languages/test/bat.test.ts index d27e58552be..e534d2cc022 100644 --- a/src/vs/editor/standalone-languages/test/bat.test.ts +++ b/src/vs/editor/standalone-languages/test/bat.test.ts @@ -5,7 +5,7 @@ 'use strict'; -import {language} from 'vs/editor/standalone-languages/bat'; +import {language, conf} from 'vs/editor/standalone-languages/bat'; import {testOnEnter, testTokenization} from 'vs/editor/standalone-languages/test/testUtil'; testTokenization('bat', language, [ @@ -333,7 +333,7 @@ testTokenization('bat', language, [ ]}] ]); -testOnEnter('bat', language, (assertOnEnter) => { +testOnEnter('bat', conf, (assertOnEnter) => { assertOnEnter.nothing('', ' a', ''); assertOnEnter.indents('', ' {', ''); assertOnEnter.indents('', '( ', ''); diff --git a/src/vs/editor/standalone-languages/test/coffee.test.ts b/src/vs/editor/standalone-languages/test/coffee.test.ts index 0155005fcc9..e8c2a6b74a5 100644 --- a/src/vs/editor/standalone-languages/test/coffee.test.ts +++ b/src/vs/editor/standalone-languages/test/coffee.test.ts @@ -5,10 +5,10 @@ 'use strict'; -import {language} from 'vs/editor/standalone-languages/coffee'; +import {language, conf} from 'vs/editor/standalone-languages/coffee'; import {testOnEnter, testTokenization} from 'vs/editor/standalone-languages/test/testUtil'; -testOnEnter('coffeescript', language, (assertOnEnter) => { +testOnEnter('coffeescript', conf, (assertOnEnter) => { assertOnEnter.nothing('', ' a', ''); assertOnEnter.indents('', ' {', ''); assertOnEnter.indents('', '( ', ''); diff --git a/src/vs/editor/standalone-languages/test/cpp.test.ts b/src/vs/editor/standalone-languages/test/cpp.test.ts index b0388ebb60e..9566afd9f62 100644 --- a/src/vs/editor/standalone-languages/test/cpp.test.ts +++ b/src/vs/editor/standalone-languages/test/cpp.test.ts @@ -5,10 +5,10 @@ 'use strict'; -import {language} from 'vs/editor/standalone-languages/cpp'; +import {language, conf} from 'vs/editor/standalone-languages/cpp'; import {testOnEnter, testTokenization} from 'vs/editor/standalone-languages/test/testUtil'; -testOnEnter('cpp', language, (assertOnEnter) => { +testOnEnter('cpp', conf, (assertOnEnter) => { assertOnEnter.nothing('', ' a', ''); assertOnEnter.indents('', ' <', ''); assertOnEnter.indents('', ' {', ''); diff --git a/src/vs/editor/standalone-languages/test/java.test.ts b/src/vs/editor/standalone-languages/test/java.test.ts index afc102b87da..21ffd379b7c 100644 --- a/src/vs/editor/standalone-languages/test/java.test.ts +++ b/src/vs/editor/standalone-languages/test/java.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import {language} from 'vs/editor/standalone-languages/java'; +import {language, conf} from 'vs/editor/standalone-languages/java'; import {testTokenization} from 'vs/editor/standalone-languages/test/testUtil'; testTokenization('java', language, [ @@ -605,7 +605,7 @@ testTokenization('java', language, [ suite('java', () => { test('word definition', () => { - var wordDefinition = language.wordDefinition; + var wordDefinition = conf.wordPattern; assert.deepEqual('a b cde'.match(wordDefinition), ['a', 'b', 'cde']); assert.deepEqual('public static void main(String[] args) {'.match(wordDefinition), diff --git a/src/vs/editor/standalone-languages/test/powershell.test.ts b/src/vs/editor/standalone-languages/test/powershell.test.ts index 7347cecff8c..dc166d39087 100644 --- a/src/vs/editor/standalone-languages/test/powershell.test.ts +++ b/src/vs/editor/standalone-languages/test/powershell.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import {language} from 'vs/editor/standalone-languages/powershell'; +import {language, conf} from 'vs/editor/standalone-languages/powershell'; import {testTokenization} from 'vs/editor/standalone-languages/test/testUtil'; testTokenization('powershell', language, [ @@ -738,7 +738,7 @@ testTokenization('powershell', language, [ suite('powershell', () => { test('word definition', () => { - var wordDefinition = language.wordDefinition; + var wordDefinition = conf.wordPattern; assert.deepEqual('a b cde'.match(wordDefinition), ['a', 'b', 'cde']); assert.deepEqual('if ($parameterSet["class"] -eq "blank")'.match(wordDefinition), ['if', '$parameterSet', 'class', '-eq', 'blank']); diff --git a/src/vs/editor/standalone-languages/test/testUtil.ts b/src/vs/editor/standalone-languages/test/testUtil.ts index a5e2453079c..2f8f506a65d 100644 --- a/src/vs/editor/standalone-languages/test/testUtil.ts +++ b/src/vs/editor/standalone-languages/test/testUtil.ts @@ -5,11 +5,8 @@ 'use strict'; -import {compile} from 'vs/editor/common/modes/monarch/monarchCompile'; -import {createRichEditSupport} from 'vs/editor/common/modes/monarch/monarchDefinition'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; import {createOnEnterAsserter, executeMonarchTokenizationTests} from 'vs/editor/test/common/modesUtil'; -import {ILanguage} from '../types'; +import {ILanguage, IRichLanguageConfiguration} from '../types'; export interface IRelaxedToken { startIndex: number; @@ -28,19 +25,17 @@ export interface IOnEnterAsserter { } export function testTokenization(name:string, language: ILanguage, tests:ITestItem[][]): void { - suite(language.displayName || name, () => { + suite(name, () => { test('Tokenization', () => { executeMonarchTokenizationTests(name, language, tests); }); }); } -export function testOnEnter(name:string, language: ILanguage, callback:(assertOnEnter: IOnEnterAsserter)=>void): void { - suite(language.displayName || name, () => { +export function testOnEnter(name:string, conf: IRichLanguageConfiguration, callback:(assertOnEnter: IOnEnterAsserter)=>void): void { + suite(name, () => { test('onEnter', () => { - var lexer = compile(language); - var richEditSupport = new RichEditSupport('test', null, createRichEditSupport(lexer)); - callback(createOnEnterAsserter('test', richEditSupport)); + callback(createOnEnterAsserter('test', conf)); }); }); } diff --git a/src/vs/editor/standalone-languages/types.ts b/src/vs/editor/standalone-languages/types.ts index 0039d16eb4c..7c9293c936a 100644 --- a/src/vs/editor/standalone-languages/types.ts +++ b/src/vs/editor/standalone-languages/types.ts @@ -17,63 +17,87 @@ export interface ILanguageDef { export interface ILanguage { // required - name: string; // unique name to identify the language tokenizer: Object; // map from string to ILanguageRule[] + tokenPostfix: string; // attach this to every token class (by default '.' + name) // optional - displayName?: string; // nice display name ignoreCase?: boolean; // is the language case insensitive? - lineComment?: string; // used to insert/delete line comments in the editor - blockCommentStart?: string; // used to insert/delete block comments in the editor - blockCommentEnd?: string; defaultToken?: string; // if no match in the tokenizer assign this token class (default 'source') brackets?: ILanguageBracket[]; // for example [['{','}','delimiter.curly']] // advanced start?: string; // start symbol in the tokenizer (by default the first entry is used) - tokenPostfix?: string; // attach this to every token class (by default '.' + name) - autoClosingPairs?: string[][]; // for example [['"','"']] - wordDefinition?: RegExp; // word definition regular expression - outdentTriggers?: string; // characters that could potentially cause outdentation - // enhancedBrackets?: IRegexBracketPair[]; // Advanced auto completion, auto indenting, and bracket matching } /** - * This interface can be shortened as an array, ie. ['{','}','delimiter.curly'] - */ + * This interface can be shortened as an array, ie. ['{','}','delimiter.curly'] + */ export interface ILanguageBracket { open: string; // open bracket close: string; // closeing bracket token: string; // token class } -// export interface ILanguageAutoComplete { -// triggers: string; // characters that trigger auto completion rules -// match: string|RegExp; // autocomplete if this matches -// complete: string; // complete with this string -// } +export type CharacterPair = [string, string]; -// export interface ILanguageAutoIndent { -// match: string|RegExp; // auto indent if this matches on enter -// matchAfter: string|RegExp; // and auto-outdent if this matches on the next line -// } +export interface CommentRule { + lineComment?: string; + blockComment?: CharacterPair; +} -// /** -// * Regular expression based brackets. These are always electric. -// */ -// export interface IRegexBracketPair { -// // openTrigger?: string; // The character that will trigger the evaluation of 'open'. -// open: RegExp; // The definition of when an opening brace is detected. This regex is matched against the entire line upto, and including the last typed character (the trigger character). -// closeComplete?: string; // How to complete a matching open brace. Matches from 'open' will be expanded, e.g. '' -// matchCase?: boolean; // If set to true, the case of the string captured in 'open' will be detected an applied also to 'closeComplete'. -// // This is useful for cases like BEGIN/END or begin/end where the opening and closing phrases are unrelated. -// // For identical phrases, use the $1 replacement syntax above directly in closeComplete, as it will -// // include the proper casing from the captured string in 'open'. -// // Upper/Lower/Camel cases are detected. Camel case dection uses only the first two characters and assumes -// // that 'closeComplete' contains wors separated by spaces (e.g. 'End Loop') +export interface IIndentationRules { + decreaseIndentPattern: RegExp; + increaseIndentPattern: RegExp; + indentNextLinePattern?: RegExp; + unIndentedLinePattern?: RegExp; +} -// // closeTrigger?: string; // The character that will trigger the evaluation of 'close'. -// close?: RegExp; // The definition of when a closing brace is detected. This regex is matched against the entire line upto, and including the last typed character (the trigger character). -// tokenType?: string; // The type of the token. Matches from 'open' or 'close' will be expanded, e.g. 'keyword.$1'. -// // Only used to auto-(un)indent a closing bracket. -// } +export interface IOnEnterRegExpRules { + beforeText: RegExp; + afterText?: RegExp; + action: IEnterAction; +} + +export interface IEnterAction { + indentAction:IndentAction; + appendText?:string; + removeText?:number; +} + +export enum IndentAction { + None, + Indent, + IndentOutdent, + Outdent +} +export interface IAutoClosingPair { + open:string; + close:string; +} + +export interface IAutoClosingPairConditional extends IAutoClosingPair { + notIn?: string[]; +} + +export interface IDocComment { + scope: string; // What tokens should be used to detect a doc comment (e.g. 'comment.documentation'). + open: string; // The string that starts a doc comment (e.g. '/**') + lineStart: string; // The string that appears at the start of each line, except the first and last (e.g. ' * '). + close?: string; // The string that appears on the last line and closes the doc comment (e.g. ' */'). +} + +export interface IBracketElectricCharacterContribution { + docComment?: IDocComment; + embeddedElectricCharacters?: string[]; +} + +export interface IRichLanguageConfiguration { + comments?: CommentRule; + brackets?: CharacterPair[]; + wordPattern?: RegExp; + indentationRules?: IIndentationRules; + onEnterRules?: IOnEnterRegExpRules[]; + autoClosingPairs?: IAutoClosingPairConditional[]; + surroundingPairs?: IAutoClosingPair[]; + __electricCharacterSupport?: IBracketElectricCharacterContribution; +} diff --git a/src/vs/editor/standalone-languages/vb.ts b/src/vs/editor/standalone-languages/vb.ts index 2bada8d0fa2..a24004fcb89 100644 --- a/src/vs/editor/standalone-languages/vb.ts +++ b/src/vs/editor/standalone-languages/vb.ts @@ -5,57 +5,92 @@ 'use strict'; -import {ILanguage} from './types'; +import {ILanguage, IRichLanguageConfiguration} from './types'; + +export var conf:IRichLanguageConfiguration = { + comments: { + lineComment: '\'', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['{','}'],['[',']'],['(',')'],['<','>'], + ['addhandler','end addhandler'], + ['class','end class'], + ['enum','end enum'], + ['event','end event'], + ['function','end function'], + ['get','end get'], + ['if','end if'], + ['interface','end interface'], + ['module','end module'], + ['namespace','end namespace'], + ['operator','end operator'], + ['property','end property'], + ['raiseevent','end raiseevent'], + ['removehandler','end removehandler'], + ['select','end select'], + ['set','end set'], + ['structure','end structure'], + ['sub','end sub'], + ['synclock','end synclock'], + ['try','end try'], + ['while','end while'], + ['with','end with'], + ['using','end using'], + ['do','loop'], + ['for','next'] + ], + autoClosingPairs: [ + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: '<', close: '>', notIn: ['string', 'comment'] }, + ] +}; export var language = { - displayName: 'VB', - name: 'vb', defaultToken: '', + tokenPostfix: '.vb', ignoreCase: true, brackets: [ - { token:'delimiter.bracket', open: '{', close: '}'}, - { token:'delimiter.array', open: '[', close: ']'}, - { token:'delimiter.parenthesis', open: '(', close: ')'}, - { token:'delimiter.angle', open: '<', close: '>'}, + { token:'delimiter.bracket', open: '{', close: '}'}, + { token:'delimiter.array', open: '[', close: ']'}, + { token:'delimiter.parenthesis', open: '(', close: ')'}, + { token:'delimiter.angle', open: '<', close: '>'}, - // Special bracket statement pairs - // according to https://msdn.microsoft.com/en-us/library/tsw2a11z.aspx - { token: 'keyword.tag-addhandler', open: 'addhandler', close: 'end addhandler'}, - { token: 'keyword.tag-class', open: 'class', close: 'end class'}, - { token: 'keyword.tag-enum', open: 'enum', close: 'end enum'}, - { token: 'keyword.tag-event', open: 'event', close: 'end event'}, - { token: 'keyword.tag-function', open: 'function', close: 'end function'}, - { token: 'keyword.tag-get', open: 'get', close: 'end get'}, - { token: 'keyword.tag-if', open: 'if', close: 'end if'}, - { token: 'keyword.tag-interface', open: 'interface', close: 'end interface'}, - { token: 'keyword.tag-module', open: 'module', close: 'end module'}, - { token: 'keyword.tag-namespace', open: 'namespace', close: 'end namespace'}, - { token: 'keyword.tag-operator', open: 'operator', close: 'end operator'}, - { token: 'keyword.tag-property', open: 'property', close: 'end property'}, - { token: 'keyword.tag-raiseevent', open: 'raiseevent', close: 'end raiseevent'}, - { token: 'keyword.tag-removehandler', open: 'removehandler', close: 'end removehandler'}, - { token: 'keyword.tag-select', open: 'select', close: 'end select'}, - { token: 'keyword.tag-set', open: 'set', close: 'end set'}, - { token: 'keyword.tag-structure', open: 'structure', close: 'end structure'}, - { token: 'keyword.tag-sub', open: 'sub', close: 'end sub'}, - { token: 'keyword.tag-synclock', open: 'synclock', close: 'end synclock'}, - { token: 'keyword.tag-try', open: 'try', close: 'end try'}, - { token: 'keyword.tag-while', open: 'while', close: 'end while'}, - { token: 'keyword.tag-with', open: 'with', close: 'end with'}, + // Special bracket statement pairs + // according to https://msdn.microsoft.com/en-us/library/tsw2a11z.aspx + { token: 'keyword.tag-addhandler', open: 'addhandler', close: 'end addhandler'}, + { token: 'keyword.tag-class', open: 'class', close: 'end class'}, + { token: 'keyword.tag-enum', open: 'enum', close: 'end enum'}, + { token: 'keyword.tag-event', open: 'event', close: 'end event'}, + { token: 'keyword.tag-function', open: 'function', close: 'end function'}, + { token: 'keyword.tag-get', open: 'get', close: 'end get'}, + { token: 'keyword.tag-if', open: 'if', close: 'end if'}, + { token: 'keyword.tag-interface', open: 'interface', close: 'end interface'}, + { token: 'keyword.tag-module', open: 'module', close: 'end module'}, + { token: 'keyword.tag-namespace', open: 'namespace', close: 'end namespace'}, + { token: 'keyword.tag-operator', open: 'operator', close: 'end operator'}, + { token: 'keyword.tag-property', open: 'property', close: 'end property'}, + { token: 'keyword.tag-raiseevent', open: 'raiseevent', close: 'end raiseevent'}, + { token: 'keyword.tag-removehandler', open: 'removehandler', close: 'end removehandler'}, + { token: 'keyword.tag-select', open: 'select', close: 'end select'}, + { token: 'keyword.tag-set', open: 'set', close: 'end set'}, + { token: 'keyword.tag-structure', open: 'structure', close: 'end structure'}, + { token: 'keyword.tag-sub', open: 'sub', close: 'end sub'}, + { token: 'keyword.tag-synclock', open: 'synclock', close: 'end synclock'}, + { token: 'keyword.tag-try', open: 'try', close: 'end try'}, + { token: 'keyword.tag-while', open: 'while', close: 'end while'}, + { token: 'keyword.tag-with', open: 'with', close: 'end with'}, - // Other pairs - { token: 'keyword.tag-using', open: 'using', close: 'end using' }, - { token: 'keyword.tag-do', open: 'do', close: 'loop' }, - { token: 'keyword.tag-for', open: 'for', close: 'next' } + // Other pairs + { token: 'keyword.tag-using', open: 'using', close: 'end using' }, + { token: 'keyword.tag-do', open: 'do', close: 'loop' }, + { token: 'keyword.tag-for', open: 'for', close: 'next' } ], - autoClosingPairs: [ ['{', '}'], ['[', ']'], ['(', ')'], ['"', '"'], ['<', '>'], ], - - lineComment: '\'', - blockCommentStart: '/*', - blockCommentEnd: '*/', - keywords: [ 'AddHandler', 'AddressOf', 'Alias', 'And', 'AndAlso', 'As', 'Async', 'Boolean', 'ByRef', 'Byte', 'ByVal', 'Call', 'Case', 'Catch', 'CBool', 'CByte', 'CChar', 'CDate', 'CDbl', 'CDec', 'Char', 'CInt', 'Class', 'CLng', diff --git a/src/vs/editor/standalone-languages/xml.ts b/src/vs/editor/standalone-languages/xml.ts index 5e530c28110..22ebfae022b 100644 --- a/src/vs/editor/standalone-languages/xml.ts +++ b/src/vs/editor/standalone-languages/xml.ts @@ -5,22 +5,17 @@ 'use strict'; -import {ILanguage} from './types'; - -export var language = { - displayName: 'XML', - name: 'xml', - defaultToken: '', - - ignoreCase: true, - - lineComment: '', // no line comment in xml - blockCommentStart: '', - - // Useful regular expressions - qualifiedName: /(?:[\w\.\-]+:)?[\w\.\-]+/, +import {ILanguage, IRichLanguageConfiguration} from './types'; +export var conf:IRichLanguageConfiguration = { + comments: { + blockComment: [''], + }, + brackets: [['{','}'],['[',']'],['(',')'],['<','>']], + autoClosingPairs: [ + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string', 'comment'] }, + ] // enhancedBrackets: [{ // tokenType: 'tag.tag-$1.xml', // openTrigger: '>', @@ -29,8 +24,16 @@ export var language = { // closeTrigger: '>', // close: /<\/(\w[\w\d]*)\s*>$/i // }], +}; - autoClosingPairs: [['\'', '\''], ['"', '"'] ], +export var language = { + defaultToken: '', + tokenPostfix: '.xml', + + ignoreCase: true, + + // Useful regular expressions + qualifiedName: /(?:[\w\.\-]+:)?[\w\.\-]+/, tokenizer: { root: [ diff --git a/src/vs/editor/test/common/commands/shiftCommand.test.ts b/src/vs/editor/test/common/commands/shiftCommand.test.ts index 1efc7d72172..df15da8e2ea 100644 --- a/src/vs/editor/test/common/commands/shiftCommand.test.ts +++ b/src/vs/editor/test/common/commands/shiftCommand.test.ts @@ -8,8 +8,8 @@ import * as assert from 'assert'; import {ShiftCommand} from 'vs/editor/common/commands/shiftCommand'; import {Selection} from 'vs/editor/common/core/selection'; import {IIdentifiedSingleEditOperation} from 'vs/editor/common/editorCommon'; -import {IRichEditSupport, IndentAction} from 'vs/editor/common/modes'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {IndentAction} from 'vs/editor/common/modes'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {createSingleEditOp, getEditOperation, testCommand} from 'vs/editor/test/common/commands/commandTestUtils'; import {withEditorModel} from 'vs/editor/test/common/editorTestUtils'; import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; @@ -32,11 +32,9 @@ function testUnshiftCommand(lines: string[], selection: Selection, expectedLines class DocBlockCommentMode extends MockMode { - public richEditSupport: IRichEditSupport; - constructor() { super(); - this.richEditSupport = new RichEditSupport(this.getId(), null, { + LanguageConfigurationRegistry.register(this.getId(), { brackets: [ ['(', ')'], ['{', '}'], diff --git a/src/vs/editor/test/common/controller/cursor.test.ts b/src/vs/editor/test/common/controller/cursor.test.ts index 4595547c5ec..67c1ba94118 100644 --- a/src/vs/editor/test/common/controller/cursor.test.ts +++ b/src/vs/editor/test/common/controller/cursor.test.ts @@ -16,10 +16,11 @@ import { ITokenizedModel, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon'; import {Model} from 'vs/editor/common/model/model'; -import {IMode, IRichEditSupport, IndentAction} from 'vs/editor/common/modes'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {IMode, IndentAction} from 'vs/editor/common/modes'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {MockConfiguration} from 'vs/editor/test/common/mocks/mockConfiguration'; import {BracketMode} from 'vs/editor/test/common/testModes'; +import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; let H = Handler; @@ -1062,41 +1063,26 @@ suite('Editor Controller - Cursor', () => { }); }); -class TestMode { - public getId():string { - return 'testing'; - } - - public toSimplifiedMode(): IMode { - return this; - } -} - -class SurroundingMode extends TestMode { - public richEditSupport: IRichEditSupport; - +class SurroundingMode extends MockMode { constructor() { super(); - this.richEditSupport = new RichEditSupport(this.getId(), null, { + LanguageConfigurationRegistry.register(this.getId(), { autoClosingPairs: [{ open: '(', close: ')' }] }); } } -class OnEnterMode extends TestMode { - public richEditSupport: IRichEditSupport; - +class OnEnterMode extends MockMode { constructor(indentAction: IndentAction) { super(); - this.richEditSupport = { - onEnter: { - onEnter: (model, position) => { - return { - indentAction: indentAction - }; + LanguageConfigurationRegistry.register(this.getId(), { + onEnterRules: [{ + beforeText: /.*/, + action: { + indentAction: indentAction } - } - }; + }] + }); } } diff --git a/src/vs/editor/test/common/mocks/mockMode.ts b/src/vs/editor/test/common/mocks/mockMode.ts index d2edd055a3f..0fdd4b18fc1 100644 --- a/src/vs/editor/test/common/mocks/mockMode.ts +++ b/src/vs/editor/test/common/mocks/mockMode.ts @@ -9,10 +9,13 @@ import {AbstractState} from 'vs/editor/common/modes/abstractState'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; export class MockMode implements IMode { - + private static instanceCount = 0; private _id:string; - constructor(id:string = 'mockMode') { + constructor(id?:string) { + if (typeof id === 'undefined') { + id = 'mockMode' + (++MockMode.instanceCount); + } this._id = id; } diff --git a/src/vs/editor/test/common/mocks/mockModeService.ts b/src/vs/editor/test/common/mocks/mockModeService.ts index d6b2de4549c..6941fc9d362 100644 --- a/src/vs/editor/test/common/mocks/mockModeService.ts +++ b/src/vs/editor/test/common/mocks/mockModeService.ts @@ -9,10 +9,6 @@ import {IDisposable} from 'vs/base/common/lifecycle'; import {TPromise} from 'vs/base/common/winjs.base'; import {ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; import * as modes from 'vs/editor/common/modes'; -import {ILanguage} from 'vs/editor/common/modes/monarch/monarchTypes'; -import {IRichLanguageConfiguration} from 'vs/editor/common/modes/supports/richEditSupport'; -import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; -import {IModelService} from 'vs/editor/common/services/modelService'; import {IModeService, IModeLookupResult} from 'vs/editor/common/services/modeService'; export class MockModeService implements IModeService { @@ -83,16 +79,10 @@ export class MockModeService implements IModeService { throw new Error('Not implemented'); } - registerRichEditSupport(modeId: string, support: IRichLanguageConfiguration): IDisposable { - 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'); } - registerMonarchDefinition(modelService: IModelService, editorWorkerService: IEditorWorkerService, modeId:string, language:ILanguage): IDisposable { - throw new Error('Not implemented'); - } } diff --git a/src/vs/editor/test/common/modes/supports/onEnter.test.ts b/src/vs/editor/test/common/modes/supports/onEnter.test.ts index b050594c95f..4ec3eb14888 100644 --- a/src/vs/editor/test/common/modes/supports/onEnter.test.ts +++ b/src/vs/editor/test/common/modes/supports/onEnter.test.ts @@ -11,7 +11,7 @@ import {OnEnterSupport} from 'vs/editor/common/modes/supports/onEnter'; suite('OnEnter', () => { test('uses indentationRules', () => { - var support = new OnEnterSupport(null, { + var support = new OnEnterSupport(null, null, { indentationRules: { decreaseIndentPattern: /^\s*((?!\S.*\/[*]).*[*]\/\s*)?[})\]]|^\s*(case\b.*|default):\s*(\/\/.*|\/[*].*[*]\/\s*)?$/, increaseIndentPattern: /(\{[^}"']*|\([^)"']*|\[[^\]"']*|^\s*(\{\}|\(\)|\[\]|(case\b.*|default):))\s*(\/\/.*|\/[*].*[*]\/\s*)?$/, @@ -42,7 +42,7 @@ suite('OnEnter', () => { ['(', ')'], ['begin', 'end'] ]; - var support = new OnEnterSupport(null, { + var support = new OnEnterSupport(null, null, { brackets: brackets }); var testIndentAction = (beforeText:string, afterText:string, expected:IndentAction) => { @@ -75,7 +75,7 @@ suite('OnEnter', () => { }); test('uses regExpRules', () => { - var support = new OnEnterSupport(null, { + var support = new OnEnterSupport(null, null, { regExpRules: [ { beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, diff --git a/src/vs/editor/test/common/modes/tokenization.test.ts b/src/vs/editor/test/common/modes/tokenization.test.ts index dbe1b45918c..c56db2344f2 100644 --- a/src/vs/editor/test/common/modes/tokenization.test.ts +++ b/src/vs/editor/test/common/modes/tokenization.test.ts @@ -104,7 +104,7 @@ export class SwitchingMode extends MockMode { this.tokenizationSupport = new TokenizationSupport(this, this, true, false); } - registerSupport(support:modes.MutableSupport, callback:(mode:modes.IMode)=>T): IDisposable { + setTokenizationSupport(callback:(mode:modes.IMode)=>T): IDisposable { return EmptyDisposable; } @@ -336,8 +336,8 @@ suite('Editor Modes - Tokenization', () => { { startIndex: 5, id: 'B' } ]); - handleEvent(createMockLineContext('abc (def', lineTokens), 0, (mode:modes.IMode, context:modes.ILineContext, offset:number) => { - assert.deepEqual(mode.getId(), 'A'); + handleEvent(createMockLineContext('abc (def', lineTokens), 0, (modeId:string, context:modes.ILineContext, offset:number) => { + assert.deepEqual(modeId, 'A'); assert.equal(context.getTokenCount(), 3); assert.equal(context.getTokenStartIndex(0), 0); assert.equal(context.getTokenType(0), 'A.abc'); @@ -349,8 +349,8 @@ suite('Editor Modes - Tokenization', () => { assert.equal(context.getLineContent(), 'abc ('); }); - handleEvent(createMockLineContext('abc (def', lineTokens), 6, (mode:modes.IMode, context:modes.ILineContext, offset:number) => { - assert.deepEqual(mode.getId(), 'B'); + handleEvent(createMockLineContext('abc (def', lineTokens), 6, (modeId:string, context:modes.ILineContext, offset:number) => { + assert.deepEqual(modeId, 'B'); assert.equal(context.getTokenCount(), 1); assert.equal(context.getTokenStartIndex(0), 0); assert.equal(context.getTokenType(0), 'B.def'); diff --git a/src/vs/editor/test/common/modesTestUtils.ts b/src/vs/editor/test/common/modesTestUtils.ts index 10edb1a5162..90ff862fba4 100644 --- a/src/vs/editor/test/common/modesTestUtils.ts +++ b/src/vs/editor/test/common/modesTestUtils.ts @@ -6,26 +6,8 @@ import {Arrays} from 'vs/editor/common/core/arrays'; import * as modes from 'vs/editor/common/modes'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; -import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; import {ModeTransition} from 'vs/editor/common/core/modeTransition'; -class ModeWithRichEditSupport extends MockMode { - - public richEditSupport: modes.IRichEditSupport; - - constructor(id:string, wordRegExp:RegExp) { - super(id); - this.richEditSupport = new RichEditSupport(id, null, { - wordPattern: wordRegExp - }); - } -} - -export function createMockMode(id:string, wordRegExp:RegExp = null):modes.IMode { - return new ModeWithRichEditSupport(id, wordRegExp); -} - export interface TokenText { text: string; type: string; diff --git a/src/vs/editor/test/common/modesUtil.ts b/src/vs/editor/test/common/modesUtil.ts index afa1cdd2eab..5f31e19bda5 100644 --- a/src/vs/editor/test/common/modesUtil.ts +++ b/src/vs/editor/test/common/modesUtil.ts @@ -12,6 +12,7 @@ import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchL import {ILanguage} from 'vs/editor/common/modes/monarch/monarchTypes'; import {createMockModeService} from 'vs/editor/test/common/servicesTestUtils'; import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; +import {RichEditSupport, IRichLanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; export interface ITestItem { line: string; @@ -47,13 +48,14 @@ export interface IOnEnterAsserter { indentsOutdents(oneLineAboveText:string, beforeText:string, afterText:string): void; } -export function createOnEnterAsserter(modeId:string, richEditSupport: modes.IRichEditSupport): IOnEnterAsserter { +export function createOnEnterAsserter(modeId:string, conf: IRichLanguageConfiguration): IOnEnterAsserter { var assertOne = (oneLineAboveText:string, beforeText:string, afterText:string, expected: modes.IndentAction) => { var model = new Model( [ oneLineAboveText, beforeText + afterText ].join('\n'), Model.DEFAULT_CREATION_OPTIONS, new MockMode(modeId) ); + var richEditSupport = new RichEditSupport(modeId, null, conf); var actual = richEditSupport.onEnter.onEnter(model, { lineNumber: 2, column: beforeText.length + 1 }); if (expected === modes.IndentAction.None) { assert.equal(actual, null, oneLineAboveText + '\\n' + beforeText + '|' + afterText); @@ -92,9 +94,8 @@ export function executeTests2(tokenizationSupport: modes.TokensProvider, tests:I } } - export function executeMonarchTokenizationTests(name:string, language:ILanguage, tests:ITestItem[][]): void { - var lexer = compile(language); + var lexer = compile(name, language); var modeService = createMockModeService(); diff --git a/src/vs/editor/test/common/testModes.ts b/src/vs/editor/test/common/testModes.ts index 49e782ed37c..3b5fcb607d3 100644 --- a/src/vs/editor/test/common/testModes.ts +++ b/src/vs/editor/test/common/testModes.ts @@ -6,7 +6,7 @@ import * as modes from 'vs/editor/common/modes'; import {AbstractState} from 'vs/editor/common/modes/abstractState'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {LanguageConfigurationRegistry, CommentRule} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; @@ -33,17 +33,16 @@ export class CommentState extends AbstractState { export class CommentMode extends MockMode { public tokenizationSupport: modes.ITokenizationSupport; - public richEditSupport: modes.IRichEditSupport; - constructor(commentsConfig:modes.ICommentsConfiguration) { + constructor(commentsConfig:CommentRule) { super(); this.tokenizationSupport = new TokenizationSupport(this, { getInitialState: () => new CommentState(this, 0) }, false, false); - this.richEditSupport = { - comments:commentsConfig - }; + LanguageConfigurationRegistry.register(this.getId(), { + comments: commentsConfig + }); } } @@ -141,11 +140,9 @@ export class ModelMode2 extends MockMode { export class BracketMode extends MockMode { - public richEditSupport: modes.IRichEditSupport; - constructor() { super(); - this.richEditSupport = new RichEditSupport(this.getId(), null, { + LanguageConfigurationRegistry.register(this.getId(), { brackets: [ ['{', '}'], ['[', ']'], diff --git a/src/vs/languages/css/common/css.ts b/src/vs/languages/css/common/css.ts index 83a5aed0df6..9eb39e601e3 100644 --- a/src/vs/languages/css/common/css.ts +++ b/src/vs/languages/css/common/css.ts @@ -17,7 +17,7 @@ import {AbstractState} from 'vs/editor/common/modes/abstractState'; import {IMarker} from 'vs/platform/markers/common/markers'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IThreadService, ThreadAffinity} from 'vs/platform/thread/common/thread'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {LanguageConfigurationRegistry, IRichLanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {wireCancellationToken} from 'vs/base/common/async'; @@ -278,8 +278,30 @@ export class State extends AbstractState { export class CSSMode extends AbstractMode { + public static LANG_CONFIG:IRichLanguageConfiguration = { + // TODO@Martin: This definition does not work with umlauts for example + wordPattern: /(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g, + + comments: { + blockComment: ['/*', '*/'] + }, + + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"', notIn: ['string'] }, + { open: '\'', close: '\'', notIn: ['string'] } + ] + }; + public tokenizationSupport: modes.ITokenizationSupport; - public richEditSupport: modes.IRichEditSupport; public inplaceReplaceSupport:modes.IInplaceReplaceSupport; public configSupport:modes.IConfigurationSupport; @@ -299,28 +321,7 @@ export class CSSMode extends AbstractMode { getInitialState: () => new State(this, States.Selector, false, null, false, 0) }, false, false); - this.richEditSupport = new RichEditSupport(this.getId(), null, { - // TODO@Martin: This definition does not work with umlauts for example - wordPattern: /(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g, - - comments: { - blockComment: ['/*', '*/'] - }, - - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ], - - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"', notIn: ['string'] }, - { open: '\'', close: '\'', notIn: ['string'] } - ] - }); + LanguageConfigurationRegistry.register(this.getId(), CSSMode.LANG_CONFIG); this.inplaceReplaceSupport = this; this.configSupport = this; diff --git a/src/vs/languages/css/test/common/css-worker.test.ts b/src/vs/languages/css/test/common/css-worker.test.ts index 43ec70606e6..ffefcef5a3d 100644 --- a/src/vs/languages/css/test/common/css-worker.test.ts +++ b/src/vs/languages/css/test/common/css-worker.test.ts @@ -14,12 +14,24 @@ import Modes = require('vs/editor/common/modes'); import WinJS = require('vs/base/common/winjs.base'); import cssErrors = require('vs/languages/css/common/parser/cssErrors'); import servicesUtil2 = require('vs/editor/test/common/servicesTestUtils'); -import modesUtil = require('vs/editor/test/common/modesTestUtils'); import {NULL_THREAD_SERVICE} from 'vs/platform/test/common/nullThreadService'; import {IMarker} from 'vs/platform/markers/common/markers'; +import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; + +export class CSSMockMode extends MockMode { + constructor() { + super('css-mock-mode-id'); + LanguageConfigurationRegistry.register(this.getId(), { + wordPattern: /(#?-?\d*\.\d\w*%?)|([@#.:!]?[\w-?]+%?)|[@#.!]/g + }); + } +} + +var cssMockMode = new CSSMockMode(); export function mockMirrorModel(content:string, url:URI = null) : mm.MirrorModel { - return mm.createTestMirrorModelFromString(content, modesUtil.createMockMode('mock.mode.id', /(#?-?\d*\.\d\w*%?)|([@#.:!]?[\w-?]+%?)|[@#.!]/g), url); + return mm.createTestMirrorModelFromString(content, cssMockMode, url); } suite('Validation - CSS', () => { @@ -39,7 +51,7 @@ suite('Validation - CSS', () => { resourceService: resourceService, markerService: markerService }); - var worker = new cssWorker.CSSWorker('mock.mode.id', services.resourceService, services.markerService); + var worker = new cssWorker.CSSWorker('css-mock-mode-id', services.resourceService, services.markerService); worker.doValidate([url]); var markers = markerService.read({ resource: url }); @@ -61,7 +73,7 @@ suite('Validation - CSS', () => { markerService: markerService }); - var worker = new cssWorker.CSSWorker('mock.mode.id', services.resourceService, services.markerService); + var worker = new cssWorker.CSSWorker('css-mock-mode-id', services.resourceService, services.markerService); worker.doValidate([url]); var markers = markerService.read({ resource: url }); diff --git a/src/vs/languages/css/test/common/css.test.ts b/src/vs/languages/css/test/common/css.test.ts index 8509272daf8..659dd2a5c6c 100644 --- a/src/vs/languages/css/test/common/css.test.ts +++ b/src/vs/languages/css/test/common/css.test.ts @@ -11,6 +11,7 @@ import {NULL_THREAD_SERVICE} from 'vs/platform/test/common/nullThreadService'; import {IThreadService} from 'vs/platform/thread/common/thread'; import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; suite('CSS Colorizing', () => { @@ -31,8 +32,8 @@ suite('CSS Colorizing', () => { ); tokenizationSupport = mode.tokenizationSupport; - assertOnEnter = modesUtil.createOnEnterAsserter(mode.getId(), mode.richEditSupport); - wordDefinition = mode.richEditSupport.wordDefinition; + assertOnEnter = modesUtil.createOnEnterAsserter(mode.getId(), CSSMode.LANG_CONFIG); + wordDefinition = LanguageConfigurationRegistry.getWordDefinition(mode.getId()); })(); test('Skip whitespace', () => { diff --git a/src/vs/languages/handlebars/common/handlebars.ts b/src/vs/languages/handlebars/common/handlebars.ts index 15164883363..965c1b68d61 100644 --- a/src/vs/languages/handlebars/common/handlebars.ts +++ b/src/vs/languages/handlebars/common/handlebars.ts @@ -10,7 +10,7 @@ import handlebarsTokenTypes = require('vs/languages/handlebars/common/handlebars 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 {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {LanguageConfigurationRegistry, IRichLanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {createWordRegExp} from 'vs/editor/common/modes/abstractMode'; import {ILeavingNestedModeData} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {IThreadService} from 'vs/platform/thread/common/thread'; @@ -107,6 +107,49 @@ export class HandlebarsState extends htmlMode.State { export class HandlebarsMode extends htmlMode.HTMLMode { + public static LANG_CONFIG:IRichLanguageConfiguration = { + 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, @@ -148,53 +191,8 @@ export class HandlebarsMode extends htmlMode.HTMLMode { return wireCancellationToken(token, this._provideLinks(model.uri)); } }, true); - } - protected _createRichEditSupport(): modes.IRichEditSupport { - return new RichEditSupport(this.getId(), null, { - - wordPattern: createWordRegExp('#-?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['{{', '}}'] - ], - - __electricCharacterSupport: { - caseInsensitive: true, - 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 } - } - ], - }); + LanguageConfigurationRegistry.register(this.getId(), HandlebarsMode.LANG_CONFIG); } public getInitialState() : modes.IState { diff --git a/src/vs/languages/html/common/html.ts b/src/vs/languages/html/common/html.ts index ad6191580ab..29ab8545fad 100644 --- a/src/vs/languages/html/common/html.ts +++ b/src/vs/languages/html/common/html.ts @@ -16,7 +16,7 @@ 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 {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {LanguageConfigurationRegistry, IRichLanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; import {TokenizationSupport, IEnteringNestedModeData, ILeavingNestedModeData, ITokenizationCustomization} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {IThreadService} from 'vs/platform/thread/common/thread'; import {wireCancellationToken} from 'vs/base/common/async'; @@ -285,8 +285,49 @@ export class State extends AbstractState { export class HTMLMode extends AbstractMode implements ITokenizationCustomization { + public static LANG_CONFIG:IRichLanguageConfiguration = { + 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 } + } + ], + }; + public tokenizationSupport: modes.ITokenizationSupport; - public richEditSupport: modes.IRichEditSupport; public configSupport: modes.IConfigurationSupport; private modeService:IModeService; @@ -308,8 +349,6 @@ export class HTMLMode extends AbstractMode impl this.tokenizationSupport = new TokenizationSupport(this, this, true, true); this.configSupport = this; - this.richEditSupport = this._createRichEditSupport(); - this._registerSupports(); } @@ -362,6 +401,8 @@ export class HTMLMode extends AbstractMode impl return wireCancellationToken(token, this._provideLinks(model.uri)); } }, true); + + LanguageConfigurationRegistry.register(this.getId(), HTMLMode.LANG_CONFIG); } protected _createModeWorkerManager(descriptor:modes.IModeDescriptor, instantiationService: IInstantiationService): ModeWorkerManager { @@ -372,52 +413,6 @@ export class HTMLMode extends AbstractMode impl return this._modeWorkerManager.worker(runner); } - protected _createRichEditSupport(): modes.IRichEditSupport { - return new RichEditSupport(this.getId(), null, { - - wordPattern: createWordRegExp('#-?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['<', '>'], - ], - - __electricCharacterSupport: { - caseInsensitive: true, - 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 } - } - ], - }); - } - // TokenizationSupport public getInitialState():modes.IState { diff --git a/src/vs/languages/html/test/common/html.test.ts b/src/vs/languages/html/test/common/html.test.ts index 1b4dba831f1..c123ed6cd8e 100644 --- a/src/vs/languages/html/test/common/html.test.ts +++ b/src/vs/languages/html/test/common/html.test.ts @@ -5,12 +5,10 @@ 'use strict'; import assert = require('assert'); -import EditorCommon = require('vs/editor/common/editorCommon'); import Modes = require('vs/editor/common/modes'); import modesUtil = require('vs/editor/test/common/modesUtil'); import {Model} from 'vs/editor/common/model/model'; import {getTag, DELIM_END, DELIM_START, DELIM_ASSIGN, ATTRIB_NAME, ATTRIB_VALUE, COMMENT, DELIM_COMMENT, DELIM_DOCTYPE, DOCTYPE} from 'vs/languages/html/common/htmlTokenTypes'; -import {getRawEnterActionAtPosition} from 'vs/editor/common/modes/supports/onEnter'; import {TextModelWithTokens} from 'vs/editor/common/model/textModelWithTokens'; import {TextModel} from 'vs/editor/common/model/textModel'; import {Range} from 'vs/editor/common/core/range'; @@ -23,16 +21,14 @@ import {InstantiationService} from 'vs/platform/instantiation/common/instantiati import {HTMLMode} from 'vs/languages/html/common/html'; import htmlWorker = require('vs/languages/html/common/htmlWorker'); import {MockTokenizingMode} from 'vs/editor/test/common/mocks/mockMode'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; class MockJSMode extends MockTokenizingMode { - public richEditSupport: Modes.IRichEditSupport; - constructor() { - super('js', 'mock-js'); + super('html-js-mock', 'mock-js'); - this.richEditSupport = new RichEditSupport(this.getId(), null, { + LanguageConfigurationRegistry.register(this.getId(), { brackets: [ ['(', ')'], ['{', '}'], @@ -97,6 +93,7 @@ suite('Colorizing - HTML', () => { let tokenizationSupport: Modes.ITokenizationSupport; let _mode: Modes.IMode; + let onEnterSupport: Modes.IRichEditOnEnter; (function() { let threadService = NULL_THREAD_SERVICE; @@ -115,6 +112,8 @@ suite('Colorizing - HTML', () => { ); tokenizationSupport = _mode.tokenizationSupport; + + onEnterSupport = LanguageConfigurationRegistry.getOnEnterSupport(_mode.getId()); })(); test('Open Start Tag #1', () => { @@ -708,7 +707,7 @@ suite('Colorizing - HTML', () => { test('onEnter 1', function() { var model = new Model('