提交 66d9c92b 编写于 作者: B Brad Gashler

Merge branches 'master' and 'master' of https://github.com/Microsoft/vscode

environment:
ELECTRON_RUN_AS_NODE: 1
ATOM_SHELL_INTERNAL_RUN_AS_NODE: 1
install:
- ps: Install-Product node 4.1.1 x64
......
......@@ -15,6 +15,8 @@ var File = require('vinyl');
var underscore = require('underscore');
var bundle = require('./lib/bundle');
var util = require('./lib/util');
var root = path.dirname(__dirname);
var commit = util.getVersion(root);
var tsOptions = {
target: 'ES5',
......@@ -243,6 +245,9 @@ exports.minifyTask = function (src, addSourceMapsComment) {
.pipe(minifyCSS())
.pipe(cssFilter.restore)
.pipe(sourcemaps.write('./', {
sourceMappingURL: function (file) {
return 'https://ticino.blob.core.windows.net/sourcemaps/' + commit + '/' + file.relative + '.map';
},
sourceRoot: null,
includeContent: true,
addComment: addSourceMapsComment
......
......@@ -95,7 +95,7 @@ gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compil
}));
gulp.task('clean-minified-vscode', util.rimraf('out-vscode-min'));
gulp.task('minify-vscode', ['clean-minified-vscode', 'optimize-vscode'], common.minifyTask('out-vscode', false));
gulp.task('minify-vscode', ['clean-minified-vscode', 'optimize-vscode'], common.minifyTask('out-vscode', true));
// Package
var product = require('../product.json');
......@@ -341,7 +341,7 @@ gulp.task('vscode-linux-packages', ['vscode-linux-ia32-build-deb', 'vscode-linux
// Sourcemaps
gulp.task('vscode-sourcemaps', ['minify-vscode'], function () {
gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], function () {
return gulp.src('out-vscode-min/**/*.map')
.pipe(azure.upload({
account: process.env.AZURE_STORAGE_ACCOUNT,
......
......@@ -30,7 +30,7 @@ export function activate(context: ExtensionContext) {
// The server is implemented in node
let serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
// The debug options for the server
let debugOptions = { execArgv: ["--nolazy", "--debug=6004"] };
let debugOptions = { execArgv: ['--nolazy', '--debug=6004'] };
// If the extension is launch in debug mode the debug server options are use
// Otherwise the run options are used
......
{
"account": "monacobuild",
"container": "debuggers",
"zip": "e740544/node-debug.zip",
"zip": "9105842/node-debug.zip",
"output": ""
}
......@@ -9,16 +9,14 @@
["(", ")"]
]
/*
enhancedBrackets: [
{ tokenType:'string', openTrigger: '"', open: /@"$/, closeComplete: '"@' },
{ tokenType:'string', openTrigger: '\'', open: /@'$/, closeComplete: '\'@' },
{ tokenType:'string', openTrigger: '"', open: /"$/, closeComplete: '"' },
{ tokenType: 'string', openTrigger: '\'', open: /'$/, closeComplete: '\'' }
],
// 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
*/
// autoClosingPairs: [['{', '}'], ['[', ']'], ['(', ')']], // Defined explicitly, to suppress the
// // default auto-closing of ' and " which is
// // override above by enhancedBrackets
}
\ No newline at end of file
......@@ -7,9 +7,10 @@
"languages": [{
"id": "shellscript",
"aliases": ["Shell Script (Bash)", "shellscript"],
"extensions": [".sh", ".bash", ".zsh", ".bashrc", ".bash_profile", ".bash_login", ".profile", ".bash_logout"],
"extensions": [".sh", ".bash", ".bashrc", ".bash_profile", ".bash_login", ".profile", ".bash_logout", ".zsh", ".zshrc"],
"firstLine": "^#!.*\\b(bash|zsh|sh|tcsh)|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-",
"configuration": "./shellscript.configuration.json"
"configuration": "./shellscript.configuration.json",
"mimetypes": ["text/x-shellscript"]
}],
"grammars": [{
"language": "shellscript",
......
......@@ -8,12 +8,11 @@
["[", "]"],
["(", ")"]
]
/*
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: '()',
*/
// 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: '()',
}
\ No newline at end of file
......@@ -56,17 +56,17 @@
],
"configuration": {
"type": "object",
"title": "TypeScript configuration",
"title": "%configuration.typescript%",
"properties": {
"typescript.useCodeSnippetsOnMethodSuggest": {
"type": "boolean",
"default": false,
"description": "Complete functions with their parameter signature."
"description": "%typescript.useCodeSnippetsOnMethodSuggest.dec%"
},
"typescript.tsdk": {
"type": ["string", "null"],
"default": null,
"description": "Specifies the folder path containing the tsserver and lib*.d.ts files to use."
"description": "%typescript.tsdk.desc%"
}
}
},
......@@ -78,7 +78,7 @@
"commands": [
{
"command": "typescript.reloadProjects",
"title": "Reload Projects",
"title": "%typescript.reloadProjects.title%",
"category": "TypeScript"
}
],
......
{
"typescript.reloadProjects.title": "Reload Project",
"configuration.typescript": "TypeScript configuration",
"typescript.useCodeSnippetsOnMethodSuggest.dec": "Complete functions with their parameter signature.",
"typescript.tsdk.desc": "Specifies the folder path containing the tsserver and lib*.d.ts files to use."
}
\ No newline at end of file
......@@ -47,7 +47,7 @@ function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string
newEnv['STDIN_PIPE_NAME'] = stdInPipeName;
newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName;
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1';
return newEnv;
}
......
......@@ -29,7 +29,7 @@ var stdOutPipeName = process.env['STDOUT_PIPE_NAME'];
log('STDIN_PIPE_NAME: ' + stdInPipeName);
log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']);
// stdout redirection to named pipe
(function() {
......@@ -134,7 +134,7 @@ log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
// Unset the custom environmental variables that should not get inherited
delete process.env['STDIN_PIPE_NAME'];
delete process.env['STDOUT_PIPE_NAME'];
delete process.env['ELECTRON_RUN_AS_NODE'];
delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'];
require(program);
......
......@@ -6,16 +6,16 @@
"brackets": [
["<", ">"]
]
/*
enhancedBrackets: [{
tokenType: 'tag.tag-$1.xml',
openTrigger: '>',
open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i,
closeComplete: '</$1>',
closeTrigger: '>',
close: /<\/(\w[\w\d]*)\s*>$/i
}],
autoClosingPairs: [['\'', '\''], ['"', '"'] ]
*/
// enhancedBrackets: [{
// tokenType: 'tag.tag-$1.xml',
// openTrigger: '>',
// open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i,
// closeComplete: '</$1>',
// closeTrigger: '>',
// close: /<\/(\w[\w\d]*)\s*>$/i
// }],
// autoClosingPairs: [['\'', '\''], ['"', '"'] ]
}
......@@ -6,16 +6,15 @@
"brackets": [
["<", ">"]
]
/*
enhancedBrackets: [{
tokenType: 'tag.tag-$1.xml',
openTrigger: '>',
open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i,
closeComplete: '</$1>',
closeTrigger: '>',
close: /<\/(\w[\w\d]*)\s*>$/i
}],
autoClosingPairs: [['\'', '\''], ['"', '"'] ]
*/
// enhancedBrackets: [{
// tokenType: 'tag.tag-$1.xml',
// openTrigger: '>',
// open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i,
// closeComplete: '</$1>',
// closeTrigger: '>',
// close: /<\/(\w[\w\d]*)\s*>$/i
// }],
// autoClosingPairs: [['\'', '\''], ['"', '"'] ]
}
......@@ -7,5 +7,5 @@ function realpath() { python -c "import os,sys; print os.path.realpath(sys.argv[
CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")"
ELECTRON="$CONTENTS/MacOS/Electron"
CLI="$CONTENTS/Resources/app/out/cli.js"
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $?
\ No newline at end of file
......@@ -7,5 +7,5 @@ NAME="@@NAME@@"
VSCODE_PATH="/usr/share/$NAME"
ELECTRON="$VSCODE_PATH/$NAME"
CLI="$VSCODE_PATH/resources/app/out/cli.js"
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $?
@echo off
setlocal
set VSCODE_DEV=
set ELECTRON_RUN_AS_NODE=1
set ATOM_SHELL_INTERNAL_RUN_AS_NODE=1
"%~dp0..\\Code.exe" "%~dp0code.js" %*
endlocal
\ No newline at end of file
delete process.env['ELECTRON_RUN_AS_NODE'];
delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'];
require('child_process').spawn(require('path').resolve(__dirname, '..', 'Code.exe'), process.argv.slice(2), { detached: true, stdio: 'ignore' });
process.exit(0);
\ No newline at end of file
@echo off
set ELECTRON_RUN_AS_NODE=1
set ATOM_SHELL_INTERNAL_RUN_AS_NODE=1
pushd %~dp0\..
.\.build\electron\electron.exe .\node_modules\mocha\bin\_mocha %*
......
......@@ -10,11 +10,11 @@ fi
# Unit Tests
if [[ "$OSTYPE" == "darwin"* ]]; then
cd $ROOT ; ulimit -n 4096 ; ELECTRON_RUN_AS_NODE=1 \
cd $ROOT ; ulimit -n 4096 ; ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \
./.build/electron/Electron.app/Contents/MacOS/Electron \
node_modules/mocha/bin/_mocha $*
else
cd $ROOT ; ELECTRON_RUN_AS_NODE=1 \
cd $ROOT ; ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \
./.build/electron/electron \
node_modules/mocha/bin/_mocha $*
fi
......
......@@ -24,18 +24,19 @@ function getNLSConfiguration() {
}
if (locale === 'pseudo') {
return { availableLanguages: {}, pseudo: true }
return { locale: locale, availableLanguages: {}, pseudo: true }
}
locale = locale || app.getLocale();
var initialLocale = locale;
if (process.env.VSCODE_DEV) {
return { availableLanguages: {} };
return { locale: locale, availableLanguages: {} };
}
// We have a built version so we have extracted nls file. Try to find
// the right file to use.
locale = locale || app.getLocale();
while (locale) {
var candidate = path.join(__dirname, 'main.nls.') + locale + '.js';
if (fs.existsSync(candidate)) {
return { availableLanguages: { '*': locale } };
return { locale: initialLocale, availableLanguages: { '*': locale } };
} else {
var index = locale.lastIndexOf('-');
if (index > 0) {
......@@ -46,7 +47,7 @@ function getNLSConfiguration() {
}
}
return { availableLanguages: {} };
return { locale: initialLocale, availableLanguages: {} };
}
// Change cwd if given via env variable
......
......@@ -496,6 +496,7 @@ declare module "os" {
export function freemem(): number;
export function cpus(): { model: string; speed: number; times: { user: number; nice: number; sys: number; idle: number; irq: number; }; }[];
export function networkInterfaces(): any;
export function homedir(): string;
export var EOL: string;
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
"use strict";
'use strict';
import * as Platform from 'vs/base/common/platform';
import * as Browser from 'vs/base/browser/browser';
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
"use strict";
'use strict';
import * as nls from 'vs/nls';
import * as defaultPlatform from 'vs/base/common/platform';
......@@ -561,10 +561,10 @@ export class Keybinding {
private static _cachedKeybindingRegex: string = null;
public static getUserSettingsKeybindingRegex(): string {
if (!this._cachedKeybindingRegex) {
let numpadKey = "numpad(0|1|2|3|4|5|6|7|8|9|_multiply|_add|_subtract|_decimal|_divide|_separator)";
let oemKey = "`|\\-|=|\\[|\\]|\\\\\\\\|;|'|,|\\.|\\/|oem_8|oem_102";
let specialKey = "left|up|right|down|pageup|pagedown|end|home|tab|enter|escape|space|backspace|delete|pausebreak|capslock|insert|contextmenu|numlock|scrolllock";
let casualKey = "[a-z]|[0-9]|f(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19)";
let numpadKey = 'numpad(0|1|2|3|4|5|6|7|8|9|_multiply|_add|_subtract|_decimal|_divide|_separator)';
let oemKey = '`|\\-|=|\\[|\\]|\\\\\\\\|;|\'|,|\\.|\\/|oem_8|oem_102';
let specialKey = 'left|up|right|down|pageup|pagedown|end|home|tab|enter|escape|space|backspace|delete|pausebreak|capslock|insert|contextmenu|numlock|scrolllock';
let casualKey = '[a-z]|[0-9]|f(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19)';
let key = '((' + [numpadKey, oemKey, specialKey, casualKey].join(')|(') + '))';
let mod = '((ctrl|shift|alt|cmd|win|meta)\\+)*';
let keybinding = '(' + mod + key + ')';
......
......@@ -15,23 +15,5 @@ export interface IProxyHelper {
}
export interface IRemoteCom extends IProxyHelper {
registerBigHandler(handler:IManyHandler): void;
}
export function createProxyFromCtor(remote:IProxyHelper, id:string, ctor:Function): any {
var result: any = {
$__IS_REMOTE_OBJ: true
};
for (var prop in ctor.prototype) {
if (typeof ctor.prototype[prop] === 'function') {
result[prop] = createMethodProxy(remote, id, prop);
}
}
return result;
}
function createMethodProxy(remote:IProxyHelper, proxyId: string, path: string): (...myArgs: any[]) => TPromise<any> {
return (...myArgs: any[]) => {
return remote.callOnRemote(proxyId, path, myArgs);
};
setManyHandler(handler:IManyHandler): void;
}
......@@ -179,7 +179,7 @@ export function endsWith(haystack: string, needle: string): boolean {
}
}
export function createRegExp(searchString: string, isRegex: boolean, matchCase: boolean, wholeWord: boolean): RegExp {
export function createRegExp(searchString: string, isRegex: boolean, matchCase: boolean, wholeWord: boolean, global:boolean): RegExp {
if (searchString === '') {
throw new Error('Cannot create regex from empty string');
}
......@@ -194,7 +194,10 @@ export function createRegExp(searchString: string, isRegex: boolean, matchCase:
searchString = searchString + '\\b';
}
}
let modifiers = 'g';
let modifiers = '';
if (global) {
modifiers += 'g';
}
if (!matchCase) {
modifiers += 'i';
}
......@@ -213,7 +216,7 @@ export function createSafeRegExp(searchString:string, isRegex:boolean, matchCase
// Try to create a RegExp out of the params
var regex:RegExp = null;
try {
regex = createRegExp(searchString, isRegex, matchCase, wholeWord);
regex = createRegExp(searchString, isRegex, matchCase, wholeWord, true);
} catch (err) {
return null;
}
......@@ -233,7 +236,7 @@ export function createSafeRegExp(searchString:string, isRegex:boolean, matchCase
export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean {
// Exit early if it's one of these special cases which are meant to match
// against an empty string
if (regexp.source === "^" || regexp.source === "^$" || regexp.source === "$") {
if (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$') {
return false;
}
......
......@@ -76,9 +76,15 @@ export declare class TPromise<V> {
constructor(init:(complete: TValueCallback<V>, error:(err:any)=>void, progress:ProgressCallback)=>void, oncancel?: any);
public then<U>(success?: (value:V)=>TPromise<U>, error?: (err:any)=>TPromise<U>, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>, error?: (err:any)=>TPromise<U>|U, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>, error?: (err:any)=>U, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>, error?: (err:any)=>void, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>|U, error?: (err:any)=>TPromise<U>, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>|U, error?: (err:any)=>TPromise<U>|U, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>|U, error?: (err:any)=>U, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>TPromise<U>|U, error?: (err:any)=>void, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>U, error?: (err:any)=>TPromise<U>, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>U, error?: (err:any)=>TPromise<U>|U, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>U, error?: (err:any)=>U, progress?:ProgressCallback): TPromise<U>;
public then<U>(success?: (value:V)=>U, error?: (err:any)=>void, progress?:ProgressCallback): TPromise<U>;
......
......@@ -93,7 +93,7 @@ export class RemoteCom implements remote.IRemoteCom {
});
}
public registerBigHandler(handler:remote.IManyHandler): void {
public setManyHandler(handler:remote.IManyHandler): void {
this._bigHandler = handler;
}
......
/*---------------------------------------------------------------------------------------------
* 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 types = require('vs/base/common/types');
import {safeStringify} from 'vs/base/common/objects';
import appInsights = require('applicationinsights');
export interface IAIAdapter {
log(eventName: string, data?: any): void;
logException(exception: any): void;
dispose(): void;
}
export class AIAdapter implements IAIAdapter {
private appInsights: typeof appInsights.client;
constructor(
private aiKey: string,
private eventPrefix: string,
/* for test only */
client?: any
) {
// for test
if (client) {
this.appInsights = client;
return;
}
if (aiKey) {
// if another client is already initialized
if (appInsights.client) {
this.appInsights = appInsights.getClient(aiKey);
// no other way to enable offline mode
this.appInsights.channel.setOfflineMode(true);
} else {
this.appInsights = appInsights.setup(aiKey)
.setAutoCollectRequests(false)
.setAutoCollectPerformance(false)
.setAutoCollectExceptions(false)
.setOfflineMode(true)
.start()
.client;
}
if(aiKey.indexOf('AIF-') === 0) {
this.appInsights.config.endpointUrl = 'https://vortex.data.microsoft.com/collect/v1';
}
this.setupAIClient(this.appInsights);
}
}
private setupAIClient(client: typeof appInsights.client): void {
//prevent App Insights from reporting machine name
if (client && client.context &&
client.context.keys && client.context.tags) {
var machineNameKey = client.context.keys.deviceMachineName;
client.context.tags[machineNameKey] = '';
}
}
private getData(data?: any): any {
var properties: {[key: string]: string;} = {};
var measurements: {[key: string]: number;} = {};
var event_data = this.flaten(data);
for(var prop in event_data) {
// enforce property names less than 150 char, take the last 150 char
var propName = prop && prop.length > 150 ? prop.substr( prop.length - 149) : prop;
var property = event_data[prop];
if (types.isNumber(property)) {
measurements[propName] = property;
} else if (types.isBoolean(property)) {
measurements[propName] = property ? 1:0;
} else if (types.isString(property)) {
//enforce proeprty value to be less than 1024 char, take the first 1024 char
var propValue = property && property.length > 1024 ? property.substring(0, 1023): property;
properties[propName] = propValue;
} else if (!types.isUndefined(property) && property !== null) {
properties[propName] = property;
}
}
return {
properties: properties,
measurements: measurements
};
}
private flaten(obj:any, order:number = 0, prefix? : string): any {
var result:{[key:string]: any} = {};
var properties = obj ? Object.getOwnPropertyNames(obj) : [];
for (var i =0; i < properties.length; i++) {
var item = properties[i];
var index = prefix ? prefix + item : item;
if (types.isArray(obj[item])) {
try {
result[index] = safeStringify(obj[item]);
} catch (e) {
// workaround for catching the edge case for #18383
// safe stringfy should never throw circular object exception
result[index] = '[Circular-Array]';
}
} else if (obj[item] instanceof Date) {
result[index] = (<Date> obj[item]).toISOString();
} else if (types.isObject(obj[item])) {
if (order < 2) {
var item_result = this.flaten(obj[item], order + 1, index + '.');
for (var prop in item_result) {
result[prop] = item_result[prop];
}
} else {
try {
result[index] = safeStringify(obj[item]);
} catch (e) {
// workaround for catching the edge case for #18383
// safe stringfy should never throw circular object exception
result[index] = '[Circular]';
}
}
} else {
result[index] = obj[item];
}
}
return result;
}
public log(eventName: string, data?: any): void {
var result = this.getData(data);
if (this.appInsights) {
this.appInsights.trackEvent(this.eventPrefix+'/'+eventName, result.properties, result.measurements);
}
}
public logException(exception: any): void {
if (this.appInsights) {
this.appInsights.trackException(exception);
}
}
public dispose(): void {
this.appInsights = null;
}
}
\ No newline at end of file
......@@ -80,6 +80,10 @@ export function stat(path: string): TPromise<fs.Stats> {
return nfcall(fs.stat, path);
}
export function lstat(path: string): TPromise<fs.Stats> {
return nfcall(fs.lstat, path);
}
export function mstat(paths: string[]): TPromise<{ path: string; stats: fs.Stats; }> {
return doStatMultiple(paths.slice(0));
}
......@@ -96,6 +100,14 @@ export function unlink(path: string): Promise {
return nfcall(fs.unlink, path);
}
export function symlink(target: string, path: string, type?: string): TPromise<void> {
return nfcall<void>(fs.symlink, target, path, type);
}
export function readlink(path: string): TPromise<string> {
return nfcall<string>(fs.readlink, path);
}
function doStatMultiple(paths: string[]): TPromise<{ path: string; stats: fs.Stats; }> {
let path = paths.shift();
return stat(path).then((value) => {
......
......@@ -48,7 +48,7 @@ function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string
newEnv['STDIN_PIPE_NAME'] = stdInPipeName;
newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName;
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1';
return newEnv;
}
......
......@@ -31,7 +31,7 @@ var stdOutPipeName = process.env['STDOUT_PIPE_NAME'];
log('STDIN_PIPE_NAME: ' + stdInPipeName);
log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']);
// stdout redirection to named pipe
(function() {
......@@ -136,7 +136,7 @@ log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
// Unset the custom environmental variables that should not get inherited
delete process.env['STDIN_PIPE_NAME'];
delete process.env['STDOUT_PIPE_NAME'];
delete process.env['ELECTRON_RUN_AS_NODE'];
delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'];
require(program);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { AIAdapter } from 'vs/base/node/aiAdapter';
interface IAppInsightsEvent {
eventName: string;
properties?: {string?: string;};
measurements?: {string?: number;}
}
class AppInsightsMock {
public events: IAppInsightsEvent[]=[];
public IsTrackingPageView: boolean = false;
public exceptions: any[] =[];
public trackEvent(eventName: string, properties?: {string?: string;}, measurements?: {string?: number;}): void {
this.events.push({
eventName: eventName,
properties: properties,
measurements: measurements
});
}
public trackPageView(): void {
this.IsTrackingPageView = true;
}
public trackException(exception: any): void {
this.exceptions.push(exception);
}
}
suite('AIAdapter', () => {
var appInsightsMock: AppInsightsMock;
var adapter: AIAdapter;
var prefix = 'prefix';
setup(() => {
appInsightsMock = new AppInsightsMock();
adapter = new AIAdapter(null, prefix, appInsightsMock);
});
teardown(() => {
adapter.dispose();
});
test('Simple event', () => {
adapter.log('testEvent');
assert.equal(appInsightsMock.events.length, 1);
assert.equal(appInsightsMock.events[0].eventName, `${prefix}/testEvent`);
});
test('Track UnhandledError as exception and events', () => {
var sampleError = new Error('test');
adapter.logException(sampleError);
assert.equal(appInsightsMock.exceptions.length, 1);
});
test('property limits', () => {
var reallyLongPropertyName = 'abcdefghijklmnopqrstuvwxyz';
for (var i =0; i <6; i++) {
reallyLongPropertyName +='abcdefghijklmnopqrstuvwxyz';
}
assert(reallyLongPropertyName.length > 150);
var reallyLongPropertyValue = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123';
for (var i =0; i <21; i++) {
reallyLongPropertyValue +='abcdefghijklmnopqrstuvwxyz012345678901234567890123';
}
assert(reallyLongPropertyValue.length > 1024);
var data = {};
data[reallyLongPropertyName] = '1234';
data['reallyLongPropertyValue'] = reallyLongPropertyValue;
adapter.log('testEvent', data);
assert.equal(appInsightsMock.events.length, 1);
for (var prop in appInsightsMock.events[0].properties){
assert(prop.length < 150);
assert(appInsightsMock.events[0].properties[prop].length <1024);
}
});
test('Different data types', () => {
var date = new Date();
adapter.log('testEvent', { favoriteDate: date, likeRed: false, likeBlue: true, favoriteNumber:1, favoriteColor: 'blue', favoriteCars: ['bmw', 'audi', 'ford']});
assert.equal(appInsightsMock.events.length, 1);
assert.equal(appInsightsMock.events[0].eventName, `${prefix}/testEvent`);
assert.equal(appInsightsMock.events[0].properties['favoriteColor'], 'blue');
assert.equal(appInsightsMock.events[0].measurements['likeRed'], 0);
assert.equal(appInsightsMock.events[0].measurements['likeBlue'], 1);
assert.equal(appInsightsMock.events[0].properties['favoriteDate'], date.toISOString());
assert.equal(appInsightsMock.events[0].properties['favoriteCars'], JSON.stringify(['bmw', 'audi', 'ford']));
assert.equal(appInsightsMock.events[0].measurements['favoriteNumber'], 1);
});
test('Nested data', () => {
adapter.log('testEvent', {
window : {
title: 'some title',
measurements: {
width: 100,
height: 200
}
},
nestedObj: {
nestedObj2: {
nestedObj3: {
testProperty: 'test',
}
},
testMeasurement:1
}
});
assert.equal(appInsightsMock.events.length, 1);
assert.equal(appInsightsMock.events[0].eventName, `${prefix}/testEvent`);
assert.equal(appInsightsMock.events[0].properties['window.title'], 'some title');
assert.equal(appInsightsMock.events[0].measurements['window.measurements.width'], 100);
assert.equal(appInsightsMock.events[0].measurements['window.measurements.height'], 200);
assert.equal(appInsightsMock.events[0].properties['nestedObj.nestedObj2.nestedObj3'], JSON.stringify({"testProperty":"test"}));
assert.equal(appInsightsMock.events[0].measurements['nestedObj.testMeasurement'],1);
});
});
\ No newline at end of file
......@@ -748,7 +748,7 @@ MonacoEditorSchemas['http://json.schemastore.org/tsconfig'] = {
},
'watch': {
'description': nls.localize('tsconfig.json.compilerOptions.watch', "Watch input files."),
"type": 'boolean'
'type': 'boolean'
},
'jsx': {
'description': nls.localize('tsconfig.json.compilerOptions.jsx', "Enable the JSX option (requires TypeScript 1.6): 'preserve', 'react'."),
......
......@@ -177,11 +177,11 @@ export class ViewCursors extends ViewPart {
if (this._editorHasFocus) {
if (this._primaryCursor.getIsInEditableRange() && !this._context.configuration.editor.readOnly) {
switch (this._context.configuration.editor.cursorBlinking) {
case ("blink"):
case 'blink':
return RenderType.Blink;
case ("visible"):
case 'visible':
return RenderType.Visible;
case ("hidden"):
case 'hidden':
return RenderType.Hidden;
default:
return RenderType.Blink;
......
......@@ -55,10 +55,12 @@
/*.monaco-editor .inputarea {
position: fixed !important;
width: 200px !important;
width: 800px !important;
height: 200px !important;
top: initial !important;
left: initial !important;
bottom: 0 !important;
right: 0 !important;
}*/
.monaco-editor.ff .inputarea,
......
......@@ -307,19 +307,21 @@ export class CursorCollection {
}
private getModeConfiguration(): IModeConfiguration {
var i: number;
let i: number;
var result: IModeConfiguration = {
let result: IModeConfiguration = {
electricChars: {},
autoClosingPairsOpen: {},
autoClosingPairsClose: {},
surroundingPairs: {}
};
var electricChars: string[];
if (this.model.getMode().electricCharacterSupport) {
let richEditSupport = this.model.getMode().richEditSupport;
let electricChars: string[];
if (richEditSupport && richEditSupport.electricCharacter) {
try {
electricChars = this.model.getMode().electricCharacterSupport.getElectricCharacters();
electricChars = richEditSupport.electricCharacter.getElectricCharacters();
} catch(e) {
Errors.onUnexpectedError(e);
electricChars = null;
......@@ -331,10 +333,10 @@ export class CursorCollection {
}
}
var autoClosingPairs: IAutoClosingPair[];
if (this.model.getMode().characterPairSupport) {
let autoClosingPairs: IAutoClosingPair[];
if (richEditSupport && richEditSupport.characterPair) {
try {
autoClosingPairs = this.model.getMode().characterPairSupport.getAutoClosingPairs();
autoClosingPairs = richEditSupport.characterPair.getAutoClosingPairs();
} catch(e) {
Errors.onUnexpectedError(e);
autoClosingPairs = null;
......@@ -347,10 +349,10 @@ export class CursorCollection {
}
}
var surroundingPairs: IAutoClosingPair[];
if (this.model.getMode().characterPairSupport) {
let surroundingPairs: IAutoClosingPair[];
if (richEditSupport && richEditSupport.characterPair) {
try {
surroundingPairs = this.model.getMode().characterPairSupport.getSurroundingPairs();
surroundingPairs = richEditSupport.characterPair.getSurroundingPairs();
} catch(e) {
Errors.onUnexpectedError(e);
surroundingPairs = null;
......
......@@ -1035,7 +1035,9 @@ export class OneCursorOp {
return false;
}
if(!cursor.model.getMode().characterPairSupport) {
let richEditSupport = cursor.model.getMode().richEditSupport;
if(!richEditSupport || !richEditSupport.characterPair) {
return false;
}
......@@ -1061,7 +1063,7 @@ export class OneCursorOp {
var shouldAutoClosePair = false;
try {
shouldAutoClosePair = cursor.model.getMode().characterPairSupport.shouldAutoClosePair(ch, lineContext, position.column - 1);
shouldAutoClosePair = richEditSupport.characterPair.shouldAutoClosePair(ch, lineContext, position.column - 1);
} catch(e) {
Errors.onUnexpectedError(e);
}
......@@ -1144,22 +1146,23 @@ export class OneCursorOp {
var lineContext = cursor.model.getLineContext(position.lineNumber);
var electricAction:IElectricAction;
if(cursor.model.getMode().electricCharacterSupport) {
let richEditSupport = cursor.model.getMode().richEditSupport;
if(richEditSupport && richEditSupport.electricCharacter) {
try {
electricAction = cursor.model.getMode().electricCharacterSupport.onElectricCharacter(lineContext, position.column - 2);
electricAction = richEditSupport.electricCharacter.onElectricCharacter(lineContext, position.column - 2);
} catch(e) {
Errors.onUnexpectedError(e);
}
}
if (electricAction) {
var matchBracketType = electricAction.matchBracketType;
let matchOpenBracket = electricAction.matchOpenBracket;
var appendText = electricAction.appendText;
if (matchBracketType) {
var match:EditorCommon.IEditorRange = null;
if (matchBracketType) {
match = cursor.model.findMatchingBracketUp(matchBracketType, position);
}
if (matchOpenBracket) {
var match = cursor.model.findMatchingBracketUp(matchOpenBracket, {
lineNumber: position.lineNumber,
column: position.column - matchOpenBracket.length
});
if (match) {
var matchLineNumber = match.startLineNumber;
var matchLine = cursor.model.getLineContent(matchLineNumber);
......
......@@ -757,13 +757,9 @@ export interface IModeSupportChangedEvent {
emitOutputSupport:boolean;
linkSupport:boolean;
configSupport:boolean;
electricCharacterSupport:boolean;
commentsSupport:boolean;
characterPairSupport:boolean;
tokenTypeClassificationSupport:boolean;
quickFixSupport: boolean;
codeLensSupport: boolean;
onEnterSupport: boolean;
richEditSupport: boolean;
}
/**
......@@ -1178,16 +1174,13 @@ export interface ITokensInflatorMap {
export interface ILineTokensBinaryEncoding {
START_INDEX_MASK: number;
TYPE_MASK: number;
BRACKET_MASK: number;
START_INDEX_OFFSET: number;
TYPE_OFFSET: number;
BRACKET_OFFSET: number;
deflateArr(map:ITokensInflatorMap, tokens:Modes.IToken[]): number[];
inflate(map:ITokensInflatorMap, binaryEncodedToken:number): Modes.IToken;
getStartIndex(binaryEncodedToken:number): number;
getType(map:ITokensInflatorMap, binaryEncodedToken:number): string;
getBracket(binaryEncodedToken:number): Modes.Bracket;
inflateArr(map:ITokensInflatorMap, binaryEncodedTokens:number[]): Modes.IToken[];
findIndexOfOffset(binaryEncodedTokens:number[], offset:number): number;
sliceAndInflate(map:ITokensInflatorMap, binaryEncodedTokens:number[], startOffset:number, endOffset:number, deltaStartIndex:number): Modes.IToken[];
......@@ -1211,7 +1204,6 @@ export interface ILineTokens {
getTokenCount(): number;
getTokenStartIndex(tokenIndex:number): number;
getTokenType(tokenIndex:number): string;
getTokenBracket(tokenIndex:number): Modes.Bracket;
getTokenEndIndex(tokenIndex:number, textLength:number): number;
/**
......@@ -1391,6 +1383,21 @@ export interface ITextModel {
isDisposed(): boolean;
}
export interface IRichEditBracket {
modeId: string;
open: string;
close: string;
forwardRegex: RegExp;
reversedRegex: RegExp;
}
export interface IFoundBracket {
range: IEditorRange;
open: string;
close: string;
isOpen: boolean;
}
/**
* A model that is tokenized.
*/
......@@ -1483,12 +1490,26 @@ export interface ITokenizedModel extends ITextModel {
tokenIterator(position: IPosition, callback: (it: ITokenIterator) =>any): any;
/**
* Find the matching bracket of `tokenType` up, counting brackets.
* @param tokenType The token type of the bracket we're searching for
* Find the matching bracket of `request` up, counting brackets.
* @param request The bracket we're searching for
* @param position The position at which to start the search.
* @return The range of the matching bracket, or null if the bracket match was not found.
*/
findMatchingBracketUp(tokenType:string, position:IPosition): IEditorRange;
findMatchingBracketUp(bracket:string, position:IPosition): IEditorRange;
/**
* Find the first bracket in the model before `position`.
* @param position The position at which to start the search.
* @return The info for the first bracket before `position`, or null if there are no more brackets before `positions`.
*/
findPrevBracket(position:IPosition): IFoundBracket;
/**
* Find the first bracket in the model after `position`.
* @param position The position at which to start the search.
* @return The info for the first bracket after `position`, or null if there are no more brackets after `positions`.
*/
findNextBracket(position:IPosition): IFoundBracket;
/**
* Given a `position`, if the position is on top or near a bracket,
......
......@@ -171,9 +171,8 @@ export class ModelLine {
if (currentTokenStartIndex > 0 && delta !== 0) {
// adjust token's `startIndex` by `delta`
let deflatedType = (tokens[tokensIndex] / BIN.TYPE_OFFSET) & BIN.TYPE_MASK;
let deflatedBracket = (tokens[tokensIndex] / BIN.BRACKET_OFFSET) & BIN.BRACKET_MASK;
let newStartIndex = Math.max(minimumAllowedIndex, currentTokenStartIndex + delta);
let newToken = deflatedBracket * BIN.BRACKET_OFFSET + deflatedType * BIN.TYPE_OFFSET + newStartIndex * BIN.START_INDEX_OFFSET;
let newToken = deflatedType * BIN.TYPE_OFFSET + newStartIndex * BIN.START_INDEX_OFFSET;
if (delta < 0) {
// pop all previous tokens that have become `collapsed`
......@@ -439,9 +438,8 @@ export class ModelLine {
let deflatedStartIndex = (token / BIN.START_INDEX_OFFSET) & BIN.START_INDEX_MASK;
let deflatedType = (token / BIN.TYPE_OFFSET) & BIN.TYPE_MASK;
let deflatedBracket = (token / BIN.BRACKET_OFFSET) & BIN.BRACKET_MASK;
let newStartIndex = deflatedStartIndex + thisTextLength;
let newToken = deflatedBracket * BIN.BRACKET_OFFSET + deflatedType * BIN.TYPE_OFFSET + newStartIndex * BIN.START_INDEX_OFFSET;
let newToken = deflatedType * BIN.TYPE_OFFSET + newStartIndex * BIN.START_INDEX_OFFSET;
otherTokens[i] = newToken;
}
......@@ -618,7 +616,7 @@ function toLineTokens(map:EditorCommon.ITokensInflatorMap, tokens:Modes.IToken[]
return null;
}
} else {
if (tokens[0].startIndex === 0 && tokens[0].type === '' && !tokens[0].bracket) {
if (tokens[0].startIndex === 0 && tokens[0].type === '') {
return null;
}
}
......@@ -628,7 +626,6 @@ function toLineTokens(map:EditorCommon.ITokensInflatorMap, tokens:Modes.IToken[]
var getStartIndex = EditorCommon.LineTokensBinaryEncoding.getStartIndex;
var getType = EditorCommon.LineTokensBinaryEncoding.getType;
var getBracket = EditorCommon.LineTokensBinaryEncoding.getBracket;
var findIndexOfOffset = EditorCommon.LineTokensBinaryEncoding.findIndexOfOffset;
export class LineTokens implements EditorCommon.ILineTokens {
......@@ -669,10 +666,6 @@ export class LineTokens implements EditorCommon.ILineTokens {
return getType(this.map, this._tokens[tokenIndex]);
}
public getTokenBracket(tokenIndex:number): Modes.Bracket {
return getBracket(this._tokens[tokenIndex]);
}
public getTokenEndIndex(tokenIndex:number, textLength:number): number {
if (tokenIndex + 1 < this._tokens.length) {
return getStartIndex(this._tokens[tokenIndex + 1]);
......@@ -714,10 +707,6 @@ class EmptyLineTokens implements EditorCommon.ILineTokens {
return Strings.empty;
}
public getTokenBracket(tokenIndex:number): Modes.Bracket {
return 0;
}
public getTokenEndIndex(tokenIndex:number, textLength:number): number {
return 0;
}
......@@ -756,10 +745,6 @@ export class DefaultLineTokens implements EditorCommon.ILineTokens {
return Strings.empty;
}
public getTokenBracket(tokenIndex:number): Modes.Bracket {
return 0;
}
public getTokenEndIndex(tokenIndex:number, textLength:number): number {
return textLength;
}
......
......@@ -8,7 +8,7 @@ import nls = require('vs/nls');
import Timer = require('vs/base/common/timer');
import {NullMode, NullState, nullTokenize} from 'vs/editor/common/modes/nullMode';
import {WordHelper, BracketsHelper} from 'vs/editor/common/model/textModelWithTokensHelpers';
import {WordHelper} from 'vs/editor/common/model/textModelWithTokensHelpers';
import {TokenIterator} from 'vs/editor/common/model/tokenIterator';
import {ModelLine} from 'vs/editor/common/model/modelLine';
import {TextModel} from 'vs/editor/common/model/textModel';
......@@ -21,6 +21,9 @@ import Errors = require('vs/base/common/errors');
import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
import {StopWatch} from 'vs/base/common/stopwatch';
import {TPromise} from 'vs/base/common/winjs.base';
import {Range} from 'vs/editor/common/core/range';
import {ignoreBracketsInToken} from 'vs/editor/common/modes/supports';
import {BracketsUtils} from 'vs/editor/common/modes/supports/electricCharacter';
export class TokensInflatorMap implements EditorCommon.ITokensInflatorMap {
......@@ -166,10 +169,6 @@ class LineContext implements Modes.ILineContext {
return this._lineTokens.getTokenType(tokenIndex);
}
public getTokenBracket(tokenIndex:number): Modes.Bracket {
return this._lineTokens.getTokenBracket(tokenIndex);
}
public getTokenText(tokenIndex:number): string {
var startIndex = this._lineTokens.getTokenStartIndex(tokenIndex);
var endIndex = this._lineTokens.getTokenEndIndex(tokenIndex, this._text.length);
......@@ -848,12 +847,28 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
return result;
}
public findMatchingBracketUp(tokenType:string, position:EditorCommon.IPosition): EditorCommon.IEditorRange {
public findMatchingBracketUp(bracket:string, _position:EditorCommon.IPosition): EditorCommon.IEditorRange {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.findMatchingBracketUp: Model is disposed');
}
return BracketsHelper.findMatchingBracketUp(this, tokenType, this.validatePosition(position));
let position = this.validatePosition(_position);
let modeTransitions = this._lines[position.lineNumber - 1].getModeTransitions().toArray(this._mode);
let currentModeIndex = Arrays.findIndexInSegmentsArray(modeTransitions, position.column - 1);
let currentMode = modeTransitions[currentModeIndex];
let currentModeBrackets = currentMode.mode.richEditSupport ? currentMode.mode.richEditSupport.brackets : null;
if (!currentModeBrackets) {
return null;
}
let data = currentModeBrackets.textIsBracket[bracket];
if (!data) {
return null;
}
return this._findMatchingBracketUp(data, position);
}
public matchBracket(position:EditorCommon.IPosition, inaccurateResultAcceptable:boolean = false): EditorCommon.IMatchBracketResult {
......@@ -861,6 +876,362 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
throw new Error('TextModelWithTokens.matchBracket: Model is disposed');
}
return BracketsHelper.matchBracket(this, this.validatePosition(position), inaccurateResultAcceptable);
return this._matchBracket(this.validatePosition(position));
}
private _matchBracket(position:EditorCommon.IEditorPosition): EditorCommon.IMatchBracketResult {
let tokensMap = this._tokensInflatorMap;
let lineNumber = position.lineNumber;
let lineText = this._lines[lineNumber - 1].text;
let lineTokens = this._lines[lineNumber - 1].getTokens();
let tokens = lineTokens.getBinaryEncodedTokens();
let currentTokenIndex = lineTokens.findIndexOfOffset(position.column - 1);
let currentTokenStart = getStartIndex(tokens[currentTokenIndex]);
let modeTransitions = this._lines[lineNumber - 1].getModeTransitions().toArray(this._mode);
let currentModeIndex = Arrays.findIndexInSegmentsArray(modeTransitions, position.column - 1);
let currentMode = modeTransitions[currentModeIndex];
let currentModeBrackets = currentMode.mode.richEditSupport ? currentMode.mode.richEditSupport.brackets : null;
// If position is in between two tokens, try first looking in the previous token
if (currentTokenIndex > 0 && currentTokenStart === position.column - 1) {
let prevTokenIndex = currentTokenIndex - 1;
let prevTokenType = getType(tokensMap, tokens[prevTokenIndex]);
// check that previous token is not to be ignored
if (!ignoreBracketsInToken(prevTokenType)) {
let prevTokenStart = getStartIndex(tokens[prevTokenIndex]);
let prevMode = currentMode;
let prevModeBrackets = currentModeBrackets;
// 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;
}
if (prevModeBrackets) {
// limit search in case previous token is very large, there's no need to go beyond `maxBracketLength`
prevTokenStart = Math.max(prevTokenStart, position.column - 1 - prevModeBrackets.maxBracketLength);
let foundBracket = BracketsUtils.findPrevBracketInToken(prevModeBrackets.reversedRegex, lineNumber, lineText, prevTokenStart, currentTokenStart);
// check that we didn't hit a bracket too far away from position
if (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
let foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1);
let r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText]);
// check that we can actually match this bracket
if (r) {
return r;
}
}
}
}
}
// check that the token is not to be ignored
if (!ignoreBracketsInToken(getType(tokensMap, tokens[currentTokenIndex]))) {
if (currentModeBrackets) {
// limit search to not go before `maxBracketLength`
currentTokenStart = Math.max(currentTokenStart, position.column - 1 - currentModeBrackets.maxBracketLength);
// limit search to not go after `maxBracketLength`
let currentTokenEnd = (currentTokenIndex + 1 < tokens.length ? getStartIndex(tokens[currentTokenIndex + 1]) : lineText.length);
currentTokenEnd = Math.min(currentTokenEnd, position.column - 1 + currentModeBrackets.maxBracketLength);
// it might still be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets
while(true) {
let foundBracket = BracketsUtils.findNextBracketInText(currentModeBrackets.forwardRegex, lineNumber, lineText.substring(currentTokenStart, currentTokenEnd), currentTokenStart);
if (!foundBracket) {
// there are no brackets in this text
break;
}
// check that we didn't hit a bracket too far away from position
if (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
let foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1);
let r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText]);
// check that we can actually match this bracket
if (r) {
return r;
}
}
currentTokenStart = foundBracket.endColumn - 1;
}
}
}
return {
brackets: null,
isAccurate: true
};
}
private _matchFoundBracket(foundBracket:Range, data:EditorCommon.IRichEditBracket, isOpen:boolean): EditorCommon.IMatchBracketResult {
if (isOpen) {
let matched = this._findMatchingBracketDown(data, foundBracket.getEndPosition());
if (matched) {
return {
brackets: [foundBracket, matched],
isAccurate: true
};
}
} else {
let matched = this._findMatchingBracketUp(data, foundBracket.getStartPosition());
if (matched) {
return {
brackets: [foundBracket, matched],
isAccurate: true
};
}
}
return null;
}
private _findMatchingBracketUp(bracket:EditorCommon.IRichEditBracket, position:EditorCommon.IEditorPosition): Range {
// console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
let modeId = bracket.modeId;
let tokensMap = this._tokensInflatorMap;
let reversedBracketRegex = bracket.reversedRegex;
let count = -1;
for (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {
let lineTokens = this._lines[lineNumber - 1].getTokens();
let lineText = this._lines[lineNumber - 1].text;
let tokens = lineTokens.getBinaryEncodedTokens();
let modeTransitions = this._lines[lineNumber - 1].getModeTransitions().toArray(this._mode);
let currentModeIndex = modeTransitions.length - 1;
let currentModeStart = modeTransitions[currentModeIndex].startIndex;
let currentModeId = modeTransitions[currentModeIndex].mode.getId();
let tokensLength = tokens.length - 1;
let currentTokenEnd = lineText.length;
if (lineNumber === position.lineNumber) {
tokensLength = lineTokens.findIndexOfOffset(position.column - 1);
currentTokenEnd = position.column - 1;
currentModeIndex = Arrays.findIndexInSegmentsArray(modeTransitions, position.column - 1);
currentModeStart = modeTransitions[currentModeIndex].startIndex;
currentModeId = modeTransitions[currentModeIndex].mode.getId();
}
for (let tokenIndex = tokensLength; tokenIndex >= 0; tokenIndex--) {
let currentToken = tokens[tokenIndex];
let currentTokenType = getType(tokensMap, currentToken);
let currentTokenStart = getStartIndex(currentToken);
if (currentTokenStart < currentModeStart) {
currentModeIndex--;
currentModeStart = modeTransitions[currentModeIndex].startIndex;
currentModeId = modeTransitions[currentModeIndex].mode.getId();
}
if (currentModeId === modeId && !ignoreBracketsInToken(currentTokenType)) {
while (true) {
let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (!r) {
break;
}
let hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1);
if (hitText === bracket.open) {
count++;
} else if (hitText === bracket.close) {
count--;
}
if (count === 0) {
return r;
}
currentTokenEnd = r.startColumn - 1;
}
}
currentTokenEnd = currentTokenStart;
}
}
return null;
}
private _findMatchingBracketDown(bracket:EditorCommon.IRichEditBracket, position:EditorCommon.IEditorPosition): Range {
// console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
let modeId = bracket.modeId;
let tokensMap = this._tokensInflatorMap;
let bracketRegex = bracket.forwardRegex;
let count = 1;
for (let lineNumber = position.lineNumber, lineCount = this.getLineCount(); lineNumber <= lineCount; lineNumber++) {
let lineTokens = this._lines[lineNumber - 1].getTokens();
let lineText = this._lines[lineNumber - 1].text;
let tokens = lineTokens.getBinaryEncodedTokens();
let modeTransitions = this._lines[lineNumber - 1].getModeTransitions().toArray(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 startTokenIndex = 0;
let currentTokenStart = getStartIndex(startTokenIndex);
if (lineNumber === position.lineNumber) {
startTokenIndex = lineTokens.findIndexOfOffset(position.column - 1);
currentTokenStart = Math.max(currentTokenStart, position.column - 1);
currentModeIndex = Arrays.findIndexInSegmentsArray(modeTransitions, position.column - 1);
nextModeStart = (currentModeIndex + 1 < modeTransitions.length ? modeTransitions[currentModeIndex + 1].startIndex : lineText.length + 1);
currentModeId = modeTransitions[currentModeIndex].mode.getId();
}
for (let tokenIndex = startTokenIndex, tokensLength = tokens.length; tokenIndex < tokensLength; tokenIndex++) {
let currentToken = tokens[tokenIndex];
let currentTokenType = getType(tokensMap, currentToken);
let currentTokenEnd = tokenIndex + 1 < tokensLength ? getStartIndex(tokens[tokenIndex + 1]) : lineText.length;
if (currentTokenStart >= nextModeStart) {
currentModeIndex++;
nextModeStart = (currentModeIndex + 1 < modeTransitions.length ? modeTransitions[currentModeIndex + 1].startIndex : lineText.length + 1);
currentModeId = modeTransitions[currentModeIndex].mode.getId();
}
if (currentModeId === modeId && !ignoreBracketsInToken(currentTokenType)) {
while (true) {
let r = BracketsUtils.findNextBracketInToken(bracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (!r) {
break;
}
let hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1);
if (hitText === bracket.open) {
count++;
} else if (hitText === bracket.close) {
count--;
}
if (count === 0) {
return r;
}
currentTokenStart = r.endColumn - 1;
}
}
currentTokenStart = currentTokenEnd;
}
}
return null;
}
public findPrevBracket(_position:EditorCommon.IPosition): EditorCommon.IFoundBracket {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.findPrevBracket: Model is disposed');
}
let position = this.validatePosition(_position);
let tokensMap = this._tokensInflatorMap;
let reversedBracketRegex = /[\(\)\[\]\{\}]/; // TODO@Alex: use mode's brackets
for (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {
let lineTokens = this._lines[lineNumber - 1].getTokens();
let lineText = this._lines[lineNumber - 1].text;
let tokens = lineTokens.getBinaryEncodedTokens();
let tokensLength = tokens.length - 1;
let currentTokenEnd = lineText.length;
if (lineNumber === position.lineNumber) {
tokensLength = lineTokens.findIndexOfOffset(position.column - 1);
currentTokenEnd = position.column - 1;
}
for (let tokenIndex = tokensLength; tokenIndex >= 0; tokenIndex--) {
let currentToken = tokens[tokenIndex];
let currentTokenType = getType(tokensMap, currentToken);
let currentTokenStart = getStartIndex(currentToken);
if (!ignoreBracketsInToken(currentTokenType)) {
let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (r) {
return this._toFoundBracket(r);
}
}
currentTokenEnd = currentTokenStart;
}
}
return null;
}
public findNextBracket(_position:EditorCommon.IPosition): EditorCommon.IFoundBracket {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.findNextBracket: Model is disposed');
}
let position = this.validatePosition(_position);
let tokensMap = this._tokensInflatorMap;
let bracketRegex = /[\(\)\[\]\{\}]/; // TODO@Alex: use mode's brackets
for (let lineNumber = position.lineNumber, lineCount = this.getLineCount(); lineNumber <= lineCount; lineNumber++) {
let lineTokens = this._lines[lineNumber - 1].getTokens();
let lineText = this._lines[lineNumber - 1].text;
let tokens = lineTokens.getBinaryEncodedTokens();
let startTokenIndex = 0;
let currentTokenStart = getStartIndex(startTokenIndex);
if (lineNumber === position.lineNumber) {
startTokenIndex = lineTokens.findIndexOfOffset(position.column - 1);
currentTokenStart = Math.max(currentTokenStart, position.column - 1);
}
for (let tokenIndex = startTokenIndex, tokensLength = tokens.length; tokenIndex < tokensLength; tokenIndex++) {
let currentToken = tokens[tokenIndex];
let currentTokenType = getType(tokensMap, currentToken);
let currentTokenEnd = tokenIndex + 1 < tokensLength ? getStartIndex(tokens[tokenIndex + 1]) : lineText.length;
if (!ignoreBracketsInToken(currentTokenType)) {
let r = BracketsUtils.findNextBracketInToken(bracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (r) {
return this._toFoundBracket(r);
}
}
currentTokenStart = currentTokenEnd;
}
}
return null;
}
private _toFoundBracket(r:Range): EditorCommon.IFoundBracket {
if (!r) {
return null;
}
let text = this.getValueInRange(r);
// TODO@Alex: use mode's brackets
switch (text) {
case '(': return { range: r, open: '(', close: ')', isOpen: true };
case ')': return { range: r, open: '(', close: ')', isOpen: false };
case '[': return { range: r, open: '[', close: ']', isOpen: true };
case ']': return { range: r, open: '[', close: ']', isOpen: false };
case '{': return { range: r, open: '{', close: '}', isOpen: true };
case '}': return { range: r, open: '{', close: '}', isOpen: false };
}
return null;
}
}
var getType = EditorCommon.LineTokensBinaryEncoding.getType;
var getStartIndex = EditorCommon.LineTokensBinaryEncoding.getStartIndex;
......@@ -5,11 +5,9 @@
'use strict';
import {NullMode} from 'vs/editor/common/modes/nullMode';
import {Range} from 'vs/editor/common/core/range';
import Modes = require('vs/editor/common/modes');
import EditorCommon = require('vs/editor/common/editorCommon');
import {Arrays} from 'vs/editor/common/core/arrays';
import Errors = require('vs/base/common/errors');
export interface ITextSource {
......@@ -28,10 +26,6 @@ export interface ITextSource {
getLineTokens(lineNumber:number, inaccurateTokensAcceptable:boolean): EditorCommon.ILineTokens;
}
var getType = EditorCommon.LineTokensBinaryEncoding.getType;
var getBracket = EditorCommon.LineTokensBinaryEncoding.getBracket;
var getStartIndex = EditorCommon.LineTokensBinaryEncoding.getStartIndex;
export interface INonWordTokenMap {
[key:string]:boolean;
}
......@@ -39,17 +33,7 @@ export interface INonWordTokenMap {
export class WordHelper {
private static _safeGetWordDefinition(mode:Modes.IMode): RegExp {
var result: RegExp = null;
if (mode.tokenTypeClassificationSupport) {
try {
result = mode.tokenTypeClassificationSupport.getWordDefinition();
} catch(e) {
Errors.onUnexpectedError(e);
}
}
return result;
return (mode.richEditSupport ? mode.richEditSupport.wordDefinition : null);
}
public static ensureValidWordDefinition(wordDefinition?:RegExp): RegExp {
......@@ -232,159 +216,3 @@ export class WordHelper {
return null;
}
}
export class BracketsHelper {
private static _sign(n:number): number {
return n < 0 ? -1 : n > 0 ? 1 : 0;
}
private static _findMatchingBracketUp(textSource:ITextSource, type:string, lineNumber:number, tokenIndex:number, initialCount:number): Range {
var i:number,
end:number,
j:number,
count = initialCount;
for (i = lineNumber; i >= 1; i--) {
var lineTokens = textSource.getLineTokens(i, false),
tokens = lineTokens.getBinaryEncodedTokens(),
tokensMap = lineTokens.getBinaryEncodedTokensMap(),
lineText = textSource.getLineContent(i);
for (j = (i === lineNumber ? tokenIndex : tokens.length) - 1; j >= 0; j--) {
if (getType(tokensMap, tokens[j]) === type) {
count += BracketsHelper._sign(getBracket(tokens[j]));
if (count === 0) {
end = (j === tokens.length - 1 ? lineText.length : getStartIndex(tokens[j + 1]));
return new Range(i, getStartIndex(tokens[j]) + 1, i, end + 1);
}
}
}
}
return null;
}
private static _findMatchingBracketDown(textSource:ITextSource, type:string, lineNumber:number, tokenIndex:number, inaccurateResultAcceptable:boolean): { range:Range; isAccurate:boolean; } {
var i:number,
len:number,
end:number,
j:number,
lenJ:number,
count = 1;
for (i = lineNumber, len = textSource.getLineCount(); i <= len; i++) {
if (inaccurateResultAcceptable && !textSource._lineIsTokenized(i)) {
return {
range: null,
isAccurate: false
};
}
var lineTokens = textSource.getLineTokens(i, false),
tokens = lineTokens.getBinaryEncodedTokens(),
tokensMap = lineTokens.getBinaryEncodedTokensMap(),
lineText = textSource.getLineContent(i);
for (j = (i === lineNumber ? tokenIndex + 1 : 0), lenJ = tokens.length; j < lenJ; j++) {
if (getType(tokensMap, tokens[j]) === type) {
count += BracketsHelper._sign(getBracket(tokens[j]));
if (count === 0) {
end = (j === tokens.length - 1 ? lineText.length : getStartIndex(tokens[j + 1]));
return {
range: new Range(i, getStartIndex(tokens[j]) + 1, i, end + 1),
isAccurate: true
};
}
}
}
}
return {
range: null,
isAccurate: true
};
}
public static findMatchingBracketUp(textSource:ITextSource, tokenType:string, position:EditorCommon.IPosition): EditorCommon.IEditorRange {
var i:number,
len:number,
end:number,
columnIndex = position.column - 1,
tokenIndex = -1,
lineTokens = textSource.getLineTokens(position.lineNumber, false),
tokens = lineTokens.getBinaryEncodedTokens(),
lineText = textSource.getLineContent(position.lineNumber);
for (i = 0, len = tokens.length; tokenIndex === -1 && i < len; i++) {
end = i === len - 1 ? lineText.length : getStartIndex(tokens[i + 1]);
if (getStartIndex(tokens[i]) <= columnIndex && columnIndex <= end) {
tokenIndex = i;
}
}
// Start looking one token after the bracket
return BracketsHelper._findMatchingBracketUp(textSource, tokenType, position.lineNumber, tokenIndex + 1, 0);
}
public static matchBracket(textSource:ITextSource, position:EditorCommon.IPosition, inaccurateResultAcceptable:boolean): EditorCommon.IMatchBracketResult {
if (inaccurateResultAcceptable && !textSource._lineIsTokenized(position.lineNumber)) {
return {
brackets: null,
isAccurate: false
};
}
var lineText = textSource.getLineContent(position.lineNumber),
i:number,
len:number;
var result:EditorCommon.IMatchBracketResult = {
brackets: null,
isAccurate: true
};
if (lineText.length > 0) {
var columnIndex = position.column - 1;
var token:number;
var end:number;
var lineTokens = textSource.getLineTokens(position.lineNumber, false),
tokens = lineTokens.getBinaryEncodedTokens(),
tokensMap = lineTokens.getBinaryEncodedTokensMap(),
tokenStartIndex:number,
tokenBracket:number,
tokenType:string;
for (i = 0, len = tokens.length; result.brackets === null && i < len; i++) {
token = tokens[i];
tokenStartIndex = getStartIndex(token);
tokenType = getType(tokensMap, token);
tokenBracket = getBracket(token);
end = i === len - 1 ? lineText.length : getStartIndex(tokens[i + 1]);
if (tokenStartIndex <= columnIndex && columnIndex <= end) {
if (tokenBracket < 0) {
var upMatch = BracketsHelper._findMatchingBracketUp(textSource, tokenType, position.lineNumber, i, -1);
if (upMatch) {
result.brackets = [new Range(position.lineNumber, tokenStartIndex + 1, position.lineNumber, end + 1), upMatch];
}
}
if (result.brackets === null && tokenBracket > 0) {
var downMatch = BracketsHelper._findMatchingBracketDown(textSource, tokenType, position.lineNumber, i, inaccurateResultAcceptable);
result.isAccurate = downMatch.isAccurate;
if (downMatch.range) {
result.brackets = [new Range(position.lineNumber, tokenStartIndex + 1, position.lineNumber, end + 1), downMatch.range];
}
}
}
}
}
return result;
}
}
\ No newline at end of file
......@@ -12,30 +12,25 @@ import Errors = require('vs/base/common/errors');
class InflatedToken implements Modes.IToken {
startIndex:number;
type:string;
bracket:Modes.Bracket;
constructor(startIndex:number, type:string, bracket:Modes.Bracket) {
constructor(startIndex:number, type:string) {
this.startIndex = startIndex;
this.type = type;
this.bracket = bracket;
}
public toString(): string {
return '{ ' + this.startIndex + ', \'' + this.type + '\', ' + this.bracket + '}';
return '{ ' + this.startIndex + ', \'' + this.type + '\'}';
}
}
export var START_INDEX_MASK = 0xffffffff;
export var TYPE_MASK = 0xffff;
export var BRACKET_MASK = 0xff;
export var START_INDEX_OFFSET = 1;
export var TYPE_OFFSET = Math.pow(2, 32);
export var BRACKET_OFFSET = Math.pow(2, 48);
var DEFAULT_TOKEN = {
startIndex: 0,
type: '',
bracket: 0
type: ''
};
var INFLATED_TOKENS_EMPTY_TEXT = <Modes.IToken[]>[];
var DEFLATED_TOKENS_EMPTY_TEXT = <number[]>[];
......@@ -46,14 +41,13 @@ export function deflateArr(map:EditorCommon.ITokensInflatorMap, tokens:Modes.ITo
if (tokens.length === 0) {
return DEFLATED_TOKENS_EMPTY_TEXT;
}
if (tokens.length === 1 && tokens[0].startIndex === 0 && !tokens[0].type && !tokens[0].bracket) {
if (tokens.length === 1 && tokens[0].startIndex === 0 && !tokens[0].type) {
return DEFLATED_TOKENS_NON_EMPTY_TEXT;
}
var i:number,
len:number,
deflatedToken:number,
deflatedBracket:number,
deflated:number,
token:Modes.IToken,
inflateMap = map._inflate,
......@@ -80,11 +74,6 @@ export function deflateArr(map:EditorCommon.ITokensInflatorMap, tokens:Modes.ITo
inflateMap.push(token.type);
}
deflatedBracket = token.bracket;
if (deflatedBracket < 0) {
deflatedBracket = 2;
}
// http://stackoverflow.com/a/2803010
// All numbers in JavaScript are actually IEEE-754 compliant floating-point doubles.
// These have a 53-bit mantissa which should mean that any integer value with a magnitude
......@@ -96,10 +85,9 @@ export function deflateArr(map:EditorCommon.ITokensInflatorMap, tokens:Modes.ITo
// 32 bits for startIndex => up to 2^32 = 4,294,967,296
// 16 bits for token => up to 2^16 = 65,536
// 2 bits for bracket => up to 2^2 = 4
// [bracket][token][startIndex]
deflated = deflatedBracket * BRACKET_OFFSET + deflatedToken * TYPE_OFFSET + token.startIndex * START_INDEX_OFFSET;
// [token][startIndex]
deflated = deflatedToken * TYPE_OFFSET + token.startIndex * START_INDEX_OFFSET;
result[i] = deflated;
......@@ -116,13 +104,8 @@ export function inflate(map:EditorCommon.ITokensInflatorMap, binaryEncodedToken:
var startIndex = (binaryEncodedToken / START_INDEX_OFFSET) & START_INDEX_MASK;
var deflatedType = (binaryEncodedToken / TYPE_OFFSET) & TYPE_MASK;
var deflatedBracket = (binaryEncodedToken / BRACKET_OFFSET) & BRACKET_MASK;
if (deflatedBracket === 2) {
deflatedBracket = -1;
}
return new InflatedToken(startIndex, map._inflate[deflatedType], deflatedBracket);
return new InflatedToken(startIndex, map._inflate[deflatedType]);
}
export function getStartIndex(binaryEncodedToken:number): number {
......@@ -137,16 +120,6 @@ export function getType(map:EditorCommon.ITokensInflatorMap, binaryEncodedToken:
return map._inflate[deflatedType];
}
export function getBracket(binaryEncodedToken:number): Modes.Bracket {
var deflatedBracket = (binaryEncodedToken / BRACKET_OFFSET) & BRACKET_MASK;
if (deflatedBracket === 2) {
deflatedBracket = -1;
}
return deflatedBracket;
}
export function inflateArr(map:EditorCommon.ITokensInflatorMap, binaryEncodedTokens:number[]): Modes.IToken[] {
if (binaryEncodedTokens.length === 0) {
return INFLATED_TOKENS_EMPTY_TEXT;
......@@ -160,7 +133,6 @@ export function inflateArr(map:EditorCommon.ITokensInflatorMap, binaryEncodedTok
len:number,
deflated:number,
startIndex:number,
deflatedBracket:number,
deflatedType:number,
inflateMap = map._inflate;
......@@ -169,13 +141,8 @@ export function inflateArr(map:EditorCommon.ITokensInflatorMap, binaryEncodedTok
startIndex = (deflated / START_INDEX_OFFSET) & START_INDEX_MASK;
deflatedType = (deflated / TYPE_OFFSET) & TYPE_MASK;
deflatedBracket = (deflated / BRACKET_OFFSET) & BRACKET_MASK;
if (deflatedBracket === 2) {
deflatedBracket = -1;
}
result[i] = new InflatedToken(startIndex, inflateMap[deflatedType], deflatedBracket);
result[i] = new InflatedToken(startIndex, inflateMap[deflatedType]);
}
return result;
......@@ -200,15 +167,13 @@ export function sliceAndInflate(map:EditorCommon.ITokensInflatorMap, binaryEncod
originalStartIndex:number,
newStartIndex:number,
deflatedType:number,
deflatedBracket:number,
result: Modes.IToken[] = [],
inflateMap = map._inflate;
originalToken = binaryEncodedTokens[startIndex];
deflatedType = (originalToken / TYPE_OFFSET) & TYPE_MASK;
deflatedBracket = (originalToken / BRACKET_OFFSET) & BRACKET_MASK;
newStartIndex = 0;
result.push(new InflatedToken(newStartIndex, inflateMap[deflatedType], deflatedBracket));
result.push(new InflatedToken(newStartIndex, inflateMap[deflatedType]));
for (i = startIndex + 1, len = binaryEncodedTokens.length; i < len; i++) {
originalToken = binaryEncodedTokens[i];
......@@ -219,9 +184,8 @@ export function sliceAndInflate(map:EditorCommon.ITokensInflatorMap, binaryEncod
}
deflatedType = (originalToken / TYPE_OFFSET) & TYPE_MASK;
deflatedBracket = (originalToken / BRACKET_OFFSET) & BRACKET_MASK;
newStartIndex = originalStartIndex - startOffset + deltaStartIndex;
result.push(new InflatedToken(newStartIndex, inflateMap[deflatedType], deflatedBracket));
result.push(new InflatedToken(newStartIndex, inflateMap[deflatedType]));
}
return result;
......
......@@ -176,7 +176,6 @@ export interface ILineContext {
getTokenCount(): number;
getTokenStartIndex(tokenIndex:number): number;
getTokenType(tokenIndex:number): string;
getTokenBracket(tokenIndex:number): Bracket;
getTokenText(tokenIndex:number): string;
getTokenEndIndex(tokenIndex:number): number;
findIndexOfOffset(offset:number): number;
......@@ -283,26 +282,6 @@ export interface IMode {
*/
configSupport?:IConfigurationSupport;
/**
* Optional adapter to support electric characters.
*/
electricCharacterSupport?:IElectricCharacterSupport;
/**
* Optional adapter to support comment insertion.
*/
commentsSupport?:ICommentsSupport;
/**
* Optional adapter to support insertion of character pair.
*/
characterPairSupport?:ICharacterPairSupport;
/**
* Optional adapter to support classification of tokens.
*/
tokenTypeClassificationSupport?:ITokenTypeClassificationSupport;
/**
* Optional adapter to support quick fix of typing errors.
*/
......@@ -323,7 +302,10 @@ export interface IMode {
*/
taskSupport?: ITaskSupport;
onEnterSupport?: IOnEnterSupport;
/**
* Optional adapter to support rich editing.
*/
richEditSupport?: IRichEditSupport;
}
/**
......@@ -332,7 +314,7 @@ export interface IMode {
export interface IToken {
startIndex:number;
type:string;
bracket:Bracket;
bracket?:Bracket;
}
export interface IModeTransition {
......@@ -456,12 +438,6 @@ export interface IParameterHints {
signatures:ISignature[];
}
export interface IParameterHintsContribution {
triggerCharacters: string[];
excludeTokens: string[];
getParameterHints: (resource: URI, position: EditorCommon.IPosition) => TPromise<IParameterHints>;
}
/**
* Interface used to get parameter hints.
*/
......@@ -645,87 +621,6 @@ export interface IConfigurationSupport {
configure(options:any):TPromise<boolean>;
}
/**
* Interface used to support electric characters
*/
export interface IElectricAction {
// Only one of the following properties should be defined:
// The line will be indented at the same level of the line
// which contains the matching given bracket type.
matchBracketType?:string;
// The text will be appended after the electric character.
appendText?:string;
// The number of characters to advance the cursor, useful with appendText
advanceCount?:number;
}
export enum IndentAction {
None,
Indent,
IndentOutdent,
Outdent
}
/**
* An action the editor executes when 'enter' is being pressed
*/
export interface IEnterAction {
indentAction:IndentAction;
appendText?:string;
removeText?:number;
}
export interface IElectricCharacterSupport {
getElectricCharacters():string[];
// Should return opening bracket type to match indentation with
onElectricCharacter(context:ILineContext, offset:number):IElectricAction;
onEnter(context:ILineContext, offset:number):IEnterAction;
}
export interface IOnEnterSupport {
onEnter(model:EditorCommon.ITokenizedModel, position: EditorCommon.IPosition): IEnterAction;
}
/**
* Interface used to support insertion of mode specific comments.
*/
export interface ICommentsConfiguration {
lineCommentTokens?:string[];
blockCommentStartToken?:string;
blockCommentEndToken?:string;
}
export interface ICommentsSupport {
getCommentsConfiguration():ICommentsConfiguration;
}
/**
* Interface used to support insertion of matching characters like brackets and qoutes.
*/
export interface IAutoClosingPair {
open:string;
close:string;
}
export interface ICharacterPairSupport {
getAutoClosingPairs():IAutoClosingPairConditional[];
shouldAutoClosePair(character:string, context:ILineContext, offset:number):boolean;
getSurroundingPairs():IAutoClosingPair[];
}
/**
* Interface used to support the classification of tokens.
*/
export interface ITokenTypeClassificationSupport {
getWordDefinition():RegExp;
}
export interface IResourceEdit {
resource: URI;
range?: EditorCommon.IRange;
......@@ -790,41 +685,112 @@ export interface IBracketPair {
isElectric:boolean;
}
export interface IAutoClosingPairConditional extends IAutoClosingPair {
notIn?: string[];
}
/**
* Regular expression based brackets. These are always electric.
* Interface used to support electric characters
*/
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. '</$1>'
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')
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 IElectricAction {
// Only one of the following properties should be defined:
// The line will be indented at the same level of the line
// which contains the matching given bracket type.
matchOpenBracket?:string;
// The text will be appended after the electric character.
appendText?:string;
// The number of characters to advance the cursor, useful with appendText
advanceCount?:number;
}
export enum IndentAction {
None,
Indent,
IndentOutdent,
Outdent
}
/**
* Definition of documentation comments (e.g. Javadoc/JSdoc)
* An action the editor executes when 'enter' is being pressed
*/
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 IEnterAction {
indentAction:IndentAction;
appendText?:string;
removeText?:number;
}
export interface IAutoClosingPairConditional extends IAutoClosingPair {
notIn?: string[];
export interface IRichEditElectricCharacter {
getElectricCharacters():string[];
// Should return opening bracket type to match indentation with
onElectricCharacter(context:ILineContext, offset:number):IElectricAction;
}
export interface IRichEditOnEnter {
onEnter(model:EditorCommon.ITokenizedModel, position: EditorCommon.IPosition): IEnterAction;
}
export interface ICharacterPairContribution {
autoClosingPairs: IAutoClosingPairConditional[];
surroundingPairs?: IAutoClosingPair[];
}
\ No newline at end of file
/**
* Interface used to support insertion of mode specific comments.
*/
export interface ICommentsConfiguration {
lineCommentToken?:string;
blockCommentStartToken?:string;
blockCommentEndToken?:string;
}
/**
* Interface used to support insertion of matching characters like brackets and qoutes.
*/
export interface IAutoClosingPair {
open:string;
close:string;
}
export interface IRichEditCharacterPair {
getAutoClosingPairs():IAutoClosingPairConditional[];
shouldAutoClosePair(character:string, context:ILineContext, offset:number):boolean;
getSurroundingPairs():IAutoClosingPair[];
}
export interface IRichEditBrackets {
maxBracketLength: number;
forwardRegex: RegExp;
reversedRegex: RegExp;
brackets: EditorCommon.IRichEditBracket[];
textIsBracket: {[text:string]:EditorCommon.IRichEditBracket;};
textIsOpenBracket: {[text:string]:boolean;};
}
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;
}
......@@ -41,8 +41,6 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
public dirtyDiffSupport:Modes.IDirtyDiffSupport;
public linkSupport:Modes.ILinkSupport;
public configSupport:Modes.IConfigurationSupport;
public commentsSupport:Modes.ICommentsSupport;
public tokenTypeClassificationSupport:Modes.ITokenTypeClassificationSupport;
public codeLensSupport:Modes.ICodeLensSupport;
// adapters end
......@@ -68,8 +66,6 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
this.dirtyDiffSupport = this;
this.linkSupport = this;
this.configSupport = this;
this.commentsSupport = this;
this.tokenTypeClassificationSupport = this;
this._workerPiecePromise = null;
this._simplifiedMode = null;
......@@ -228,24 +224,12 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
}
// END
public getWordDefinition():RegExp {
return NullMode.DEFAULT_WORD_REGEXP;
}
public getCommentsConfiguration():Modes.ICommentsConfiguration {
return null;
}
}
class SimplifiedMode implements Modes.IMode {
tokenizationSupport: Modes.ITokenizationSupport;
electricCharacterSupport: Modes.IElectricCharacterSupport;
commentsSupport: Modes.ICommentsSupport;
characterPairSupport: Modes.ICharacterPairSupport;
tokenTypeClassificationSupport: Modes.ITokenTypeClassificationSupport;
onEnterSupport: Modes.IOnEnterSupport;
richEditSupport: Modes.IRichEditSupport;
private _sourceMode: Modes.IMode;
private _eventEmitter: EventEmitter;
......@@ -259,7 +243,7 @@ class SimplifiedMode implements Modes.IMode {
if (this._sourceMode.addSupportChangedListener) {
this._sourceMode.addSupportChangedListener((e) => {
if (e.tokenizationSupport || e.electricCharacterSupport || e.commentsSupport || e.characterPairSupport || e.tokenTypeClassificationSupport || e.onEnterSupport) {
if (e.tokenizationSupport || e.richEditSupport) {
this._assignSupports();
let newEvent = SimplifiedMode._createModeSupportChangedEvent(e);
this._eventEmitter.emit('modeSupportChanged', newEvent);
......@@ -278,11 +262,7 @@ class SimplifiedMode implements Modes.IMode {
private _assignSupports(): void {
this.tokenizationSupport = this._sourceMode.tokenizationSupport;
this.electricCharacterSupport = this._sourceMode.electricCharacterSupport;
this.commentsSupport = this._sourceMode.commentsSupport;
this.characterPairSupport = this._sourceMode.characterPairSupport;
this.tokenTypeClassificationSupport = this._sourceMode.tokenTypeClassificationSupport;
this.onEnterSupport = this._sourceMode.onEnterSupport;
this.richEditSupport = this._sourceMode.richEditSupport;
}
private static _createModeSupportChangedEvent(originalModeEvent:EditorCommon.IModeSupportChangedEvent): EditorCommon.IModeSupportChangedEvent {
......@@ -306,12 +286,8 @@ class SimplifiedMode implements Modes.IMode {
emitOutputSupport:false,
linkSupport:false,
configSupport:false,
electricCharacterSupport: originalModeEvent.electricCharacterSupport,
commentsSupport: originalModeEvent.commentsSupport,
characterPairSupport: originalModeEvent.characterPairSupport,
tokenTypeClassificationSupport: originalModeEvent.tokenTypeClassificationSupport,
quickFixSupport:false,
onEnterSupport: originalModeEvent.onEnterSupport
richEditSupport: originalModeEvent.richEditSupport,
};
return event;
}
......@@ -392,7 +368,7 @@ export class FrankensteinMode extends AbstractMode<AbstractModeWorker> {
}
function _createModeSupportChangedEvent(...changedSupports: string[]): EditorCommon.IModeSupportChangedEvent {
var event = {
var event:EditorCommon.IModeSupportChangedEvent = {
codeLensSupport: false,
tokenizationSupport:false,
occurrencesSupport:false,
......@@ -412,12 +388,8 @@ function _createModeSupportChangedEvent(...changedSupports: string[]): EditorCom
emitOutputSupport:false,
linkSupport:false,
configSupport:false,
electricCharacterSupport:false,
commentsSupport:false,
characterPairSupport:false,
tokenTypeClassificationSupport:false,
quickFixSupport:false,
onEnterSupport: false
richEditSupport: false
};
changedSupports.forEach(support => event[support] = true);
return event;
......
......@@ -11,11 +11,11 @@ import {computeLinks} from 'vs/editor/common/modes/linkComputer';
import {DiffComputer} from 'vs/editor/common/diff/diffComputer';
import {DefaultFilter} from 'vs/editor/common/modes/modesFilters';
import {TextModel} from 'vs/editor/common/model/textModel';
import {WorkerInplaceReplaceSupport} from 'vs/editor/common/modes/supports';
import {ValidationHelper} from 'vs/editor/common/worker/validationHelper';
import EditorCommon = require('vs/editor/common/editorCommon');
import Modes = require('vs/editor/common/modes');
import {TPromise} from 'vs/base/common/winjs.base';
import {WorkerInplaceReplaceSupport} from 'vs/editor/common/modes/supports/inplaceReplaceSupport';
export class AbstractModeWorker {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Strings = require('vs/base/common/strings');
import Modes = require('vs/editor/common/modes');
enum Lettercase { Unknown, Lowercase, Uppercase, Camelcase}
export class Brackets {
private brackets: Modes.IBracketPair[];
private regexBrackets: Modes.IRegexBracketPair[];
private docComment: Modes.IDocComment;
private caseInsensitive: boolean;
/**
* In case of case insensitive brackets, these assumptions must be met:
* - all standard brackets are passed as lowercase
* - the passed regular expressions already contain the /i flag
*
* Brackets defined in 'regexBrackets' are not used in the following methods:
* - stringIsBracket
*
*/
constructor(brackets: Modes.IBracketPair[], regexBrackets: Modes.IRegexBracketPair[] = [], docComment: Modes.IDocComment = null,
caseInsensitive: boolean = false) {
this.brackets = brackets;
this.regexBrackets = regexBrackets ? regexBrackets : [];
this.docComment = docComment ? docComment : null;
this.caseInsensitive = caseInsensitive ? caseInsensitive : false;
}
public getElectricCharacters():string[] {
var result: string[] = [];
// Plain brackets
var bracketPair: Modes.IBracketPair;
var length = this.brackets.length;
for (var i = 0; i < length; i++) {
bracketPair = this.brackets[i];
if (bracketPair.isElectric) {
var lastChar = bracketPair.close.charAt(bracketPair.close.length - 1);
result.push(this.caseInsensitive ? lastChar.toLowerCase() : lastChar);
}
}
// Regexp brackets (always electric)
var regexBracketPair: Modes.IRegexBracketPair;
length = this.regexBrackets.length;
for (var i = 0; i < length; i++) {
regexBracketPair = this.regexBrackets[i];
if (regexBracketPair.openTrigger) {
result.push( this.caseInsensitive ? regexBracketPair.openTrigger.toLowerCase() : regexBracketPair.openTrigger);
}
if (regexBracketPair.closeTrigger) {
result.push( this.caseInsensitive ? regexBracketPair.closeTrigger.toLowerCase() : regexBracketPair.closeTrigger);
}
}
// Doc comments
if (this.docComment){
result.push(this.docComment.open.charAt(this.docComment.open.length - 1));
}
// Add uppercase if needed
if (this.caseInsensitive)
{
var oldLength = result.length;
for (var i = 0; i < oldLength; ++i) {
result.push(result[i].toUpperCase());
}
}
// Filter duplicate entries
result = result.filter((item, pos, array) => {
return array.indexOf(item) === pos;
});
return result;
}
public onEnter(context: Modes.ILineContext, offset: number): Modes.IEnterAction {
if (context.getTokenCount() === 0) {
return null;
}
return this._onEnterRegexBrackets(context, offset);
}
public onElectricCharacter(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
if (context.getTokenCount() === 0) {
return null;
}
return (this._onElectricCharacterDocComment(context, offset) ||
this._onElectricCharacterRegexBrackets(context, offset) ||
this._onElectricCharacterStandardBrackets(context, offset));
}
public stringIsBracket(text: string): boolean {
var caseCorrectString = text;
if (this.caseInsensitive) {
caseCorrectString = text.toLowerCase();
}
var bracketPair: Modes.IBracketPair;
for (var i = 0; i < this.brackets.length; i++) {
bracketPair = this.brackets[i];
if (caseCorrectString === bracketPair.open || caseCorrectString === bracketPair.close) {
return true;
}
}
return false;
}
private containsTokenTypes(fullTokenSpec: string, tokensToLookFor: string): boolean {
var array = tokensToLookFor.split('.');
for (var i = 0; i < array.length; ++i) {
if (fullTokenSpec.indexOf(array[i]) < 0) {
return false;
}
}
return true;
}
private _onEnterRegexBrackets(context: Modes.ILineContext, offset: number): Modes.IEnterAction {
// Handle regular expression brackets
for (var i = 0; i < this.regexBrackets.length; ++i) {
var regexBracket = this.regexBrackets[i];
var line = context.getLineContent();
if (this.caseInsensitive) {
line = line.toLowerCase(); // Even with the /../i regexes we need this for the indexof below
}
// Check if an open bracket matches the line up to offset.
var matchLine = line.substr(0, offset);
var matches = matchLine.match(regexBracket.open);
if (matches) {
// The opening bracket matches. Check the closing one.
if (regexBracket.closeComplete) {
matchLine = line.substring(offset);
var matchAfter = matches[0].replace(regexBracket.open, regexBracket.closeComplete);
if (matchLine.indexOf(matchAfter) === 0) {
return { indentAction: Modes.IndentAction.IndentOutdent };
}
}
return { indentAction: Modes.IndentAction.Indent };
}
}
return null;
}
private _onElectricCharacterStandardBrackets(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
var tokenIndex = context.findIndexOfOffset(offset);
var tokenText = context.getTokenText(tokenIndex);
var tokenType = context.getTokenType(tokenIndex);
if (!this.stringIsBracket(tokenText)) {
// This is not a brace type that we are aware of.
// Keep in mind that tokenType above might be different than what this.tokenTypeFromString(tokenText)
// returns, which could happen when using TextMate bundles.
return null;
}
if (tokenIndex >= 0 && context.getTokenEndIndex(tokenIndex)-1 > offset) {
// We're in the middle of a token, do not do anything
return null;
}
var firstNonWhitespaceIndex = Strings.firstNonWhitespaceIndex(context.getLineContent());
if (firstNonWhitespaceIndex !== -1 && firstNonWhitespaceIndex <= offset-tokenText.length) {
return null;
}
return { matchBracketType: tokenType };
}
private _onElectricCharacterRegexBrackets(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
// Handle regular expression brackets
var line = context.getLineContent();
for (var i = 0; i < this.regexBrackets.length; ++i) {
var regexBracket = this.regexBrackets[i];
// Check if an open bracket matches the line up to offset.
if (regexBracket.openTrigger && regexBracket.closeComplete &&
(line.charAt(offset) === regexBracket.openTrigger ||
(this.caseInsensitive && line.charAt(offset).toLowerCase() === regexBracket.openTrigger.toLowerCase()))) {
var matchLine = line.substr(0, offset+1);
var matches = matchLine.match(regexBracket.open);
if (matches) {
// Auto-complete with closing bracket.
var finalText = matches[0].replace(regexBracket.open, regexBracket.closeComplete);
if (regexBracket.matchCase) {
finalText = this._changeLettercase(finalText, this._detectLetercase(matches[0]));
}
return { appendText: finalText };
}
}
// Check if a close bracket matches the line up to offset.
if (regexBracket.closeTrigger &&
(line.charAt(offset) === regexBracket.closeTrigger ||
(this.caseInsensitive && line.charAt(offset).toLowerCase() === regexBracket.closeTrigger.toLowerCase()))) {
var matches = matchLine.match(regexBracket.close);
if (matches) {
// Auto-indent to the level of the opening bracket.
var properCaseMatch = matches[0];
if (this.caseInsensitive) {
properCaseMatch = properCaseMatch.toLowerCase();
}
return { matchBracketType: properCaseMatch.replace(regexBracket.close, regexBracket.tokenType)};
}
}
}
return null;
}
private _onElectricCharacterDocComment(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
// We only auto-close, so do nothing if there is no closing part.
if (!this.docComment || !this.docComment.close) {
return null;
}
var line = context.getLineContent();
var char: string = line[offset];
// See if the right electric character was pressed
if (char !== this.docComment.open.charAt(this.docComment.open.length - 1)) {
return null;
}
// If this line already contains the closing tag, do nothing.
if (line.indexOf(this.docComment.close, offset) >= 0) {
return null;
}
// If we're not in a documentation comment, do nothing.
var lastTokenIndex = context.findIndexOfOffset(offset);
if (! this.containsTokenTypes(context.getTokenType(lastTokenIndex), this.docComment.scope)) {
return null;
}
if (line.substring(context.getTokenStartIndex(lastTokenIndex), offset+1/* include electric char*/) !== this.docComment.open) {
return null;
}
return { appendText: this.docComment.close};
}
private _detectLetercase(s: string): Lettercase {
if (s.toLowerCase() === s) {
return Lettercase.Lowercase;
}
if (s.toUpperCase() === s) {
return Lettercase.Uppercase;
}
if (s.length > 1) {
if (s.charAt(0).toUpperCase() === s.charAt(0) && s.charAt(1).toLowerCase() === s.charAt(1)) {
return Lettercase.Camelcase;
}
}
return Lettercase.Unknown;
}
private _changeLettercase(s: string, newCase: Lettercase): string {
switch (newCase) {
case Lettercase.Lowercase:
return s.toLowerCase();
case Lettercase.Uppercase:
return s.toUpperCase();
case Lettercase.Camelcase:
var words = s.toLowerCase().split(' ');
for (var i = 0; i < words.length; ++i) {
words[i] = words[i].charAt(0).toUpperCase() + words[i].substr(1);
}
return words.join(' ');
default:
return s;
}
}
}
\ No newline at end of file
......@@ -164,7 +164,6 @@ export interface ILanguageExtensionPointHandler {
isRegisteredMode(mimetypeOrModeId: string): boolean;
getRegisteredModes(): string[];
getRegisteredMimetypes(): string[];
getRegisteredLanguageNames(): string[];
getLanguageName(modeId: string): string;
getExtensions(languageName: string): string[];
......@@ -398,10 +397,6 @@ class LanguageExtensionPointHandler implements IThreadSynchronizableObject<ILang
return Object.keys(this.knownModeIds);
}
public getRegisteredMimetypes(): string[] {
return Object.keys(this.mime2LanguageId);
}
public getRegisteredLanguageNames(): string[]{
return Object.keys(this.name2LanguageId);
}
......
......@@ -26,17 +26,6 @@ export interface IEditorModesRegistry {
// --- modes registration
registerMode(def:ILegacyLanguageDefinition): void;
// --- reading
isRegisteredMode(modeName: string): boolean;
getRegisteredModes(): string[];
getRegisteredMimetypes(): string[];
getRegisteredLanguageNames(): string[];
getExtensions(alias: string): string[];
getMimeForMode(modeId: string): string;
getLanguageName(modeId:string): string;
getModeIdForLanguageName(alias:string): string;
getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string;
}
class EditorModesRegistry implements IEditorModesRegistry {
......@@ -69,53 +58,9 @@ class EditorModesRegistry implements IEditorModesRegistry {
return this.workerParticipants.filter(p => p.modeId === modeId);
}
// --- modes registration
public isRegisteredMode(mimetypeOrModeId: string): boolean {
return LanguageExtensions.isRegisteredMode(mimetypeOrModeId);
}
public getRegisteredModes(): string[] {
return LanguageExtensions.getRegisteredModes();
}
public getRegisteredMimetypes(): string[] {
return LanguageExtensions.getRegisteredMimetypes();
}
public getRegisteredLanguageNames(): string[] {
return LanguageExtensions.getRegisteredLanguageNames();
}
public getExtensions(alias: string): string[] {
return LanguageExtensions.getExtensions(alias);
}
public getMimeForMode(modeId: string): string {
return LanguageExtensions.getMimeForMode(modeId);
}
public getLanguageName(modeId: string): string {
return LanguageExtensions.getLanguageName(modeId);
}
public getModeIdForLanguageName(alias:string): string {
return LanguageExtensions.getModeIdForLanguageNameLowercase(alias);
}
public registerMode(def:ILegacyLanguageDefinition): void {
LanguageExtensions.registerCompatMode(def);
}
public getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string {
var modeIds = LanguageExtensions.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds);
if (modeIds.length > 0) {
return modeIds[0];
}
return null;
}
}
var mR = new EditorModesRegistry();
......
......@@ -11,25 +11,24 @@
import {AbstractMode} from 'vs/editor/common/modes/abstractMode';
import {AbstractModeWorker} from 'vs/editor/common/modes/abstractModeWorker';
import Supports = require('vs/editor/common/modes/supports');
import {ILexer} from 'vs/editor/common/modes/monarch/monarchCommon';
import Modes = require('vs/editor/common/modes');
import MonarchDefinition = require('vs/editor/common/modes/monarch/monarchDefinition');
import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchLexer';
import {OnEnterSupport} from 'vs/editor/common/modes/supports/onEnter';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IThreadService} from 'vs/platform/thread/common/thread';
import {IModeService} from 'vs/editor/common/services/modeService';
import {IModelService} from 'vs/editor/common/services/modelService';
import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport';
import {ComposableSuggestSupport} from 'vs/editor/common/modes/supports/suggestSupport';
/**
* The MonarchMode creates a Monaco language mode given a certain language description
*/
export class MonarchMode<W extends AbstractModeWorker> extends AbstractMode<W> {
public tokenizationSupport: Modes.ITokenizationSupport;
public electricCharacterSupport: Modes.IElectricCharacterSupport;
public characterPairSupport: Modes.ICharacterPairSupport;
public onEnterSupport: Modes.IOnEnterSupport;
public richEditSupport: Modes.IRichEditSupport;
constructor(
descriptor:Modes.IModeDescriptor,
......@@ -42,11 +41,9 @@ export class MonarchMode<W extends AbstractModeWorker> extends AbstractMode<W> {
super(descriptor, instantiationService, threadService);
this.tokenizationSupport = createTokenizationSupport(modeService, this, lexer);
this.electricCharacterSupport = new Supports.BracketElectricCharacterSupport(this, MonarchDefinition.createBracketElectricCharacterContribution(lexer));
this.commentsSupport = new Supports.CommentsSupport(MonarchDefinition.createCommentsSupport(lexer));
this.tokenTypeClassificationSupport = new Supports.TokenTypeClassificationSupport(MonarchDefinition.createTokenTypeClassificationSupportContribution(lexer));
this.characterPairSupport = new Supports.CharacterPairSupport(this, MonarchDefinition.createCharacterPairContribution(lexer));
this.suggestSupport = new Supports.ComposableSuggestSupport(this, MonarchDefinition.createSuggestSupport(modelService, this, lexer));
this.onEnterSupport = new OnEnterSupport(this.getId(), MonarchDefinition.createOnEnterSupportOptions(lexer));
this.richEditSupport = new RichEditSupport(this.getId(), MonarchDefinition.createRichEditSupport(lexer));
this.suggestSupport = new ComposableSuggestSupport(this.getId(), MonarchDefinition.createSuggestSupport(modelService, this, lexer));
}
}
......@@ -48,7 +48,7 @@ export interface ILexer extends ILexerMin {
autoClosingPairs: Modes.IAutoClosingPairConditional[];
standardBrackets: Modes.IBracketPair[];
enhancedBrackets: Modes.IRegexBracketPair[];
// enhancedBrackets: Modes.IRegexBracketPair[];
outdentTriggers: string;
}
......
......@@ -646,46 +646,46 @@ export function compile(json: MonarchTypes.ILanguage): MonarchCommonTypes.ILexer
}
// Set enhanced brackets
var enhancedBrackets : Modes.IRegexBracketPair[] = [];
if (json.enhancedBrackets) {
if (!(Array.isArray(<any>json.enhancedBrackets))) {
MonarchCommonTypes.throwError(lexer, 'the \'enhancedBrackets\' attribute must be defined as an array');
}
for (var bracketIdx in json.enhancedBrackets) {
if (json.enhancedBrackets.hasOwnProperty(bracketIdx)) {
var desc = <any> json.enhancedBrackets[bracketIdx];
if (desc.hasOwnProperty('openTrigger') && typeof (desc.openTrigger) !== 'string') {
MonarchCommonTypes.throwError(lexer, 'openTrigger in the \'enhancedBrackets\' array must be a string');
}
if (desc.hasOwnProperty('open') && !(desc.open instanceof RegExp)) {
MonarchCommonTypes.throwError(lexer, 'open in the \'enhancedBrackets\' array must be a regex');
}
if (desc.hasOwnProperty('closeComplete') && typeof (desc.closeComplete) !== 'string') {
MonarchCommonTypes.throwError(lexer, 'closeComplete in the \'enhancedBrackets\' array must be a string');
}
if (desc.hasOwnProperty('matchCase') && typeof (desc.matchCase) !== 'boolean') {
MonarchCommonTypes.throwError(lexer, 'matchCase in the \'enhancedBrackets\' array must be a boolean');
}
if (desc.hasOwnProperty('closeTrigger') && typeof (desc.closeTrigger) !== 'string') {
MonarchCommonTypes.throwError(lexer, 'closeTrigger in the \'enhancedBrackets\' array must be a string');
}
if (desc.hasOwnProperty('close') && !(desc.close instanceof RegExp)) {
MonarchCommonTypes.throwError(lexer, 'close in the \'enhancedBrackets\' array must be a regex');
}
if (desc.hasOwnProperty('tokenType')) {
if (typeof (desc.tokenType) !== 'string') {
MonarchCommonTypes.throwError(lexer, 'tokenType in the \'enhancedBrackets\' array must be a string');
}
else {
desc.tokenType += lexer.tokenPostfix;
}
}
enhancedBrackets.push(desc);
}
}
}
lexer.enhancedBrackets = enhancedBrackets;
// var enhancedBrackets : Modes.IRegexBracketPair[] = [];
// if (json.enhancedBrackets) {
// if (!(Array.isArray(<any>json.enhancedBrackets))) {
// MonarchCommonTypes.throwError(lexer, 'the \'enhancedBrackets\' attribute must be defined as an array');
// }
// for (var bracketIdx in json.enhancedBrackets) {
// if (json.enhancedBrackets.hasOwnProperty(bracketIdx)) {
// var desc = <any> json.enhancedBrackets[bracketIdx];
// if (desc.hasOwnProperty('openTrigger') && typeof (desc.openTrigger) !== 'string') {
// MonarchCommonTypes.throwError(lexer, 'openTrigger in the \'enhancedBrackets\' array must be a string');
// }
// if (desc.hasOwnProperty('open') && !(desc.open instanceof RegExp)) {
// MonarchCommonTypes.throwError(lexer, 'open in the \'enhancedBrackets\' array must be a regex');
// }
// if (desc.hasOwnProperty('closeComplete') && typeof (desc.closeComplete) !== 'string') {
// MonarchCommonTypes.throwError(lexer, 'closeComplete in the \'enhancedBrackets\' array must be a string');
// }
// if (desc.hasOwnProperty('matchCase') && typeof (desc.matchCase) !== 'boolean') {
// MonarchCommonTypes.throwError(lexer, 'matchCase in the \'enhancedBrackets\' array must be a boolean');
// }
// if (desc.hasOwnProperty('closeTrigger') && typeof (desc.closeTrigger) !== 'string') {
// MonarchCommonTypes.throwError(lexer, 'closeTrigger in the \'enhancedBrackets\' array must be a string');
// }
// if (desc.hasOwnProperty('close') && !(desc.close instanceof RegExp)) {
// MonarchCommonTypes.throwError(lexer, 'close in the \'enhancedBrackets\' array must be a regex');
// }
// if (desc.hasOwnProperty('tokenType')) {
// if (typeof (desc.tokenType) !== 'string') {
// MonarchCommonTypes.throwError(lexer, 'tokenType in the \'enhancedBrackets\' array must be a string');
// }
// else {
// desc.tokenType += lexer.tokenPostfix;
// }
// }
// enhancedBrackets.push(desc);
// }
// }
// }
// lexer.enhancedBrackets = enhancedBrackets;
var standardBrackets: Modes.IBracketPair[] = [];
for (var i = 0; i < brackets.length; ++i) {
......
......@@ -11,41 +11,44 @@
import {TPromise} from 'vs/base/common/winjs.base';
import {AbstractMode} from 'vs/editor/common/modes/abstractMode';
import Supports = require('vs/editor/common/modes/supports');
import MonarchCommonTypes = require('vs/editor/common/modes/monarch/monarchCommon');
import EditorCommon = require('vs/editor/common/editorCommon');
import {IModelService} from 'vs/editor/common/services/modelService';
import Modes = require('vs/editor/common/modes');
import {IOnEnterSupportOptions} from 'vs/editor/common/modes/supports/onEnter';
import {CharacterPair, IRichEditConfiguration} from 'vs/editor/common/modes/supports/richEditSupport';
import {IComposableSuggestContribution} from 'vs/editor/common/modes/supports/suggestSupport';
export function createCommentsSupport(lexer: MonarchCommonTypes.ILexer): Supports.ICommentsSupportContribution {
return {
commentsConfiguration: {
lineCommentTokens: [lexer.lineComment],
blockCommentStartToken: lexer.blockCommentStart,
blockCommentEndToken: lexer.blockCommentEnd
}
};
}
export function createRichEditSupport(lexer: MonarchCommonTypes.ILexer): IRichEditConfiguration {
export function createBracketElectricCharacterContribution(lexer: MonarchCommonTypes.ILexer): Supports.IBracketElectricCharacterContribution {
return {
brackets: lexer.standardBrackets,
regexBrackets: lexer.enhancedBrackets,
caseInsensitive: lexer.ignoreCase,
embeddedElectricCharacters: lexer.outdentTriggers.split('')
};
}
function toBracket(input:Modes.IBracketPair): CharacterPair {
return [input.open, input.close];
}
export function createTokenTypeClassificationSupportContribution(lexer: MonarchCommonTypes.ILexer): Supports.ITokenTypeClassificationSupportContribution {
return {
wordDefinition: lexer.wordDefinition
};
}
function toBrackets(input:Modes.IBracketPair[]): CharacterPair[] {
return input.map(toBracket);
}
export function createCharacterPairContribution(lexer: MonarchCommonTypes.ILexer): Modes.ICharacterPairContribution {
return {
autoClosingPairs: lexer.autoClosingPairs
wordPattern: lexer.wordDefinition,
comments: {
lineComment: lexer.lineComment,
blockComment: [lexer.blockCommentStart, lexer.blockCommentEnd]
},
brackets: toBrackets(lexer.standardBrackets),
__electricCharacterSupport: {
brackets: lexer.standardBrackets,
// regexBrackets: lexer.enhancedBrackets,
caseInsensitive: lexer.ignoreCase,
embeddedElectricCharacters: lexer.outdentTriggers.split('')
},
__characterPairSupport: {
autoClosingPairs: lexer.autoClosingPairs
}
};
}
......@@ -67,13 +70,7 @@ function _addSuggestionsAtPosition(model: EditorCommon.IModel, position:EditorCo
return superSuggestions;
}
export function createOnEnterSupportOptions(lexer:MonarchCommonTypes.ILexer): IOnEnterSupportOptions {
return {
brackets: lexer.standardBrackets
};
}
export function createSuggestSupport(modelService: IModelService, mode:Modes.IMode, lexer:MonarchCommonTypes.ILexer): Supports.IComposableSuggestContribution {
export function createSuggestSupport(modelService: IModelService, mode:Modes.IMode, lexer:MonarchCommonTypes.ILexer): IComposableSuggestContribution {
if (lexer.suggestSupport.textualCompletions && mode instanceof AbstractMode) {
return {
triggerCharacters:lexer.suggestSupport.triggerCharacters,
......
......@@ -11,14 +11,10 @@
import {AbstractState} from 'vs/editor/common/modes/abstractState';
import {LineStream} from 'vs/editor/common/modes/lineStream';
import ModesRegistry = require('vs/editor/common/modes/modesRegistry');
import Supports = require('vs/editor/common/modes/supports');
import MonarchCommonTypes = require('vs/editor/common/modes/monarch/monarchCommon');
import Modes = require('vs/editor/common/modes');
import {Registry} from 'vs/platform/platform';
import {IModeService} from 'vs/editor/common/services/modeService';
var modesRegistry = <ModesRegistry.IEditorModesRegistry>Registry.as(ModesRegistry.Extensions.EditorModes);
import {TokenizationSupport, IEnteringNestedModeData} from 'vs/editor/common/modes/supports/tokenizationSupport';
/**
* The MonarchLexer class implements a monaco lexer that highlights source code.
......@@ -29,6 +25,8 @@ export class MonarchLexer extends AbstractState {
static ID = 0;
private modeService:IModeService;
private id: number;
private lexer: MonarchCommonTypes.ILexer;
private stack: string[];
......@@ -41,9 +39,10 @@ export class MonarchLexer extends AbstractState {
private groupMatched: string[];
private groupRule: MonarchCommonTypes.IRule;
constructor(mode: Modes.IMode, lexer: MonarchCommonTypes.ILexer, stack?: string[], embeddedMode?: string) {
constructor(mode: Modes.IMode, modeService:IModeService, lexer: MonarchCommonTypes.ILexer, stack?: string[], embeddedMode?: string) {
super(mode);
this.id = MonarchLexer.ID++; // for debugging, assigns unique id to each instance
this.modeService = modeService;
this.lexer = lexer; // (compiled) lexer description
this.stack = (stack ? stack : [lexer.start]); // stack of states
......@@ -62,7 +61,7 @@ export class MonarchLexer extends AbstractState {
}
public makeClone(): MonarchLexer {
return new MonarchLexer(this.getMode(), this.lexer, this.stack.slice(0), this.embeddedMode);
return new MonarchLexer(this.getMode(), this.modeService, this.lexer, this.stack.slice(0), this.embeddedMode);
}
public equals(other: Modes.IState): boolean {
......@@ -219,7 +218,7 @@ export class MonarchLexer extends AbstractState {
this.embeddedMode = MonarchCommonTypes.substituteMatches(this.lexer, action.nextEmbedded, matched, matches, state);
// substitute language alias to known modes to support syntax highlighting
var embeddedMode = modesRegistry.getModeIdForLanguageName(this.embeddedMode);
var embeddedMode = this.modeService.getModeIdForLanguageName(this.embeddedMode);
if (this.embeddedMode && embeddedMode) {
this.embeddedMode = embeddedMode;
}
......@@ -388,9 +387,9 @@ function findBracket(lexer: MonarchCommonTypes.ILexer, matched: string) {
}
export function createTokenizationSupport(modeService:IModeService, mode:Modes.IMode, lexer: MonarchCommonTypes.ILexer): Modes.ITokenizationSupport {
return new Supports.TokenizationSupport(mode, {
return new TokenizationSupport(mode, {
getInitialState: (): Modes.IState => {
return new MonarchLexer(mode, lexer);
return new MonarchLexer(mode, modeService, lexer);
},
enterNestedMode: (state: Modes.IState): boolean => {
......@@ -400,10 +399,10 @@ export function createTokenizationSupport(modeService:IModeService, mode:Modes.I
return false;
},
getNestedMode: (rawState: Modes.IState): Supports.IEnteringNestedModeData => {
getNestedMode: (rawState: Modes.IState): IEnteringNestedModeData => {
var mime = (<MonarchLexer>rawState).embeddedMode;
if (!modesRegistry.isRegisteredMode(mime)) {
if (!modeService.isRegisteredMode(mime)) {
// unknown mode
return {
mode: modeService.getMode('text/plain'),
......
......@@ -75,10 +75,10 @@ export interface ILanguage {
* characters that could potentially cause outdentation
*/
outdentTriggers?: string;
/**
* Advanced auto completion, auto indenting, and bracket matching
*/
enhancedBrackets?: Modes.IRegexBracketPair[];
// /**
// * Advanced auto completion, auto indenting, and bracket matching
// */
// enhancedBrackets?: Modes.IRegexBracketPair[];
suggestSupport?: {
textualCompletions?: boolean;
......
......@@ -80,10 +80,12 @@ export class NullMode implements Modes.IMode {
public static ID = 'vs.editor.modes.nullMode';
public tokenTypeClassificationSupport: Modes.ITokenTypeClassificationSupport;
public richEditSupport: Modes.IRichEditSupport;
constructor() {
this.tokenTypeClassificationSupport = this;
this.richEditSupport = {
wordDefinition: NullMode.DEFAULT_WORD_REGEXP
};
}
public getId():string {
......@@ -93,18 +95,13 @@ export class NullMode implements Modes.IMode {
public toSimplifiedMode(): Modes.IMode {
return this;
}
public getWordDefinition():RegExp {
return NullMode.DEFAULT_WORD_REGEXP;
}
}
export function nullTokenize(mode: Modes.IMode, buffer:string, state: Modes.IState, deltaOffset:number = 0, stopAtOffset?:number): Modes.ILineTokens {
var tokens:Modes.IToken[] = [
{
startIndex: deltaOffset,
type: '',
bracket: Modes.Bracket.None
type: ''
}
];
......
/*---------------------------------------------------------------------------------------------
* 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 {handleEvent} from 'vs/editor/common/modes/supports';
import * as Modes from 'vs/editor/common/modes';
export interface ICharacterPairContribution {
autoClosingPairs: Modes.IAutoClosingPairConditional[];
surroundingPairs?: Modes.IAutoClosingPair[];
}
export class CharacterPairSupport implements Modes.IRichEditCharacterPair {
private _modeId: string;
private _autoClosingPairs: Modes.IAutoClosingPairConditional[];
private _surroundingPairs: Modes.IAutoClosingPair[];
constructor(modeId: string, contribution: ICharacterPairContribution) {
this._modeId = modeId;
this._autoClosingPairs = contribution.autoClosingPairs;
this._surroundingPairs = Array.isArray(contribution.surroundingPairs) ? contribution.surroundingPairs : contribution.autoClosingPairs;
}
public getAutoClosingPairs(): Modes.IAutoClosingPair[] {
return this._autoClosingPairs;
}
public shouldAutoClosePair(character:string, context:Modes.ILineContext, offset:number): boolean {
return handleEvent(context, offset, (nestedMode:Modes.IMode, context:Modes.ILineContext, offset:number) => {
if (this._modeId === nestedMode.getId()) {
// Always complete on empty line
if (context.getTokenCount() === 0) {
return true;
}
var tokenIndex = context.findIndexOfOffset(offset - 1);
var tokenType = context.getTokenType(tokenIndex);
for (var i = 0; i < this._autoClosingPairs.length; ++i) {
if (this._autoClosingPairs[i].open === character) {
if (this._autoClosingPairs[i].notIn) {
for (var notInIndex = 0; notInIndex < this._autoClosingPairs[i].notIn.length; ++notInIndex) {
if (tokenType.indexOf(this._autoClosingPairs[i].notIn[notInIndex]) > -1) {
return false;
}
}
}
break;
}
}
return true;
} else if (nestedMode.richEditSupport && nestedMode.richEditSupport.characterPair) {
return nestedMode.richEditSupport.characterPair.shouldAutoClosePair(character, context, offset);
} else {
return null;
}
});
}
public getSurroundingPairs(): Modes.IAutoClosingPair[]{
return this._surroundingPairs;
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IReference, IDeclarationSupport, ILineContext, IMode} from 'vs/editor/common/modes';
import {IPosition} from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import {handleEvent, isLineToken} from 'vs/editor/common/modes/supports';
export interface IDeclarationContribution {
tokens?: string[];
findDeclaration: (resource: URI, position: IPosition) => TPromise<IReference>;
}
export class DeclarationSupport implements IDeclarationSupport {
private _modeId: string;
private contribution: IDeclarationContribution;
/**
* Provide the token type postfixes for the tokens where a declaration can be found in the 'tokens' argument.
*/
constructor(modeId: string, contribution: IDeclarationContribution) {
this._modeId = modeId;
this.contribution = contribution;
}
public canFindDeclaration(context: ILineContext, offset:number):boolean {
return handleEvent(context, offset, (nestedMode:IMode, context:ILineContext, offset:number) => {
if (this._modeId === nestedMode.getId()) {
return (!Array.isArray(this.contribution.tokens) ||
this.contribution.tokens.length < 1 ||
isLineToken(context, offset, this.contribution.tokens));
} else if (nestedMode.declarationSupport) {
return nestedMode.declarationSupport.canFindDeclaration(context, offset);
} else {
return false;
}
});
}
public findDeclaration(resource: URI, position: IPosition): TPromise<IReference>{
return this.contribution.findDeclaration(resource, position);
}
}
/*---------------------------------------------------------------------------------------------
* 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 Modes from 'vs/editor/common/modes';
import {handleEvent, ignoreBracketsInToken} from 'vs/editor/common/modes/supports';
import Strings = require('vs/base/common/strings');
import {Range} from 'vs/editor/common/core/range';
import {IRichEditBracket} from 'vs/editor/common/editorCommon';
/**
* Definition of documentation comments (e.g. Javadoc/JSdoc)
*/
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 {
brackets: Modes.IBracketPair[];
docComment?: IDocComment;
caseInsensitive?: boolean;
embeddedElectricCharacters?: string[];
}
export class BracketElectricCharacterSupport implements Modes.IRichEditElectricCharacter {
private _modeId: string;
private contribution: IBracketElectricCharacterContribution;
private brackets: Brackets;
constructor(modeId: string, contribution: IBracketElectricCharacterContribution) {
this._modeId = modeId;
this.contribution = contribution;
this.brackets = new Brackets(modeId, contribution.brackets, contribution.docComment, contribution.caseInsensitive);
}
public getElectricCharacters(): string[]{
if (Array.isArray(this.contribution.embeddedElectricCharacters)) {
return this.contribution.embeddedElectricCharacters.concat(this.brackets.getElectricCharacters());
}
return this.brackets.getElectricCharacters();
}
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 this.brackets.onElectricCharacter(context, offset);
} else if (nestedMode.richEditSupport && nestedMode.richEditSupport.electricCharacter) {
return nestedMode.richEditSupport.electricCharacter.onElectricCharacter(context, offset);
} else {
return null;
}
});
}
public getRichEditBrackets(): Modes.IRichEditBrackets {
return this.brackets.getRichEditBrackets();
}
}
interface ISimpleInternalBracket {
open: string;
close: string;
}
export class Brackets {
private _modeId: string;
private _brackets: IRichEditBracket[];
private _bracketsForwardRegex: RegExp;
private _bracketsReversedRegex: RegExp;
private _maxBracketLength: number;
private _textIsBracket: {[text:string]:IRichEditBracket;};
private _textIsOpenBracket: {[text:string]:boolean;};
private _docComment: IDocComment;
constructor(modeId: string, brackets: Modes.IBracketPair[], docComment: IDocComment = null, caseInsensitive: boolean = false) {
this._modeId = modeId;
this._brackets = brackets.map((b) => {
return {
modeId: modeId,
open: b.open,
close: b.close,
forwardRegex: getRegexForBracketPair({ open: b.open, close: b.close }),
reversedRegex: getReversedRegexForBracketPair({ open: b.open, close: b.close })
};
});
this._bracketsForwardRegex = getRegexForBrackets(this._brackets);
this._bracketsReversedRegex = getReversedRegexForBrackets(this._brackets);
this._textIsBracket = {};
this._textIsOpenBracket = {};
this._maxBracketLength = 0;
this._brackets.forEach((b) => {
this._textIsBracket[b.open] = b;
this._textIsBracket[b.close] = b;
this._textIsOpenBracket[b.open] = true;
this._textIsOpenBracket[b.close] = false;
this._maxBracketLength = Math.max(this._maxBracketLength, b.open.length);
this._maxBracketLength = Math.max(this._maxBracketLength, b.close.length);
});
this._docComment = docComment ? docComment : null;
}
public getRichEditBrackets(): Modes.IRichEditBrackets {
if (this._brackets.length === 0) {
return null;
}
return {
maxBracketLength: this._maxBracketLength,
forwardRegex: this._bracketsForwardRegex,
reversedRegex: this._bracketsReversedRegex,
brackets: this._brackets,
textIsBracket: this._textIsBracket,
textIsOpenBracket: this._textIsOpenBracket
};
}
public getElectricCharacters():string[] {
var result: string[] = [];
for (let i = 0, len = this._brackets.length; i < len; i++) {
let bracketPair = this._brackets[i];
let lastChar = bracketPair.close.charAt(bracketPair.close.length - 1);
result.push(lastChar);
}
// Doc comments
if (this._docComment){
result.push(this._docComment.open.charAt(this._docComment.open.length - 1));
}
// Filter duplicate entries
result = result.filter((item, pos, array) => {
return array.indexOf(item) === pos;
});
return result;
}
public onElectricCharacter(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
if (context.getTokenCount() === 0) {
return null;
}
return (this._onElectricCharacterDocComment(context, offset) ||
this._onElectricCharacterStandardBrackets(context, offset));
}
private containsTokenTypes(fullTokenSpec: string, tokensToLookFor: string): boolean {
var array = tokensToLookFor.split('.');
for (var i = 0; i < array.length; ++i) {
if (fullTokenSpec.indexOf(array[i]) < 0) {
return false;
}
}
return true;
}
private _onElectricCharacterStandardBrackets(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
if (this._brackets.length === 0) {
return null;
}
let reversedBracketRegex = this._bracketsReversedRegex;
let lineText = context.getLineContent();
let tokenIndex = context.findIndexOfOffset(offset);
let tokenStart = context.getTokenStartIndex(tokenIndex);
let tokenEnd = offset + 1;
var firstNonWhitespaceIndex = Strings.firstNonWhitespaceIndex(context.getLineContent());
if (firstNonWhitespaceIndex !== -1 && firstNonWhitespaceIndex < tokenStart) {
return null;
}
if (!ignoreBracketsInToken(context.getTokenType(tokenIndex))) {
let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, lineText, tokenStart, tokenEnd);
if (r) {
let text = lineText.substring(r.startColumn - 1, r.endColumn - 1);
let isOpen = this._textIsOpenBracket[text];
if (!isOpen) {
return {
matchOpenBracket: text
};
}
}
}
return null;
}
private _onElectricCharacterDocComment(context: Modes.ILineContext, offset: number): Modes.IElectricAction {
// We only auto-close, so do nothing if there is no closing part.
if (!this._docComment || !this._docComment.close) {
return null;
}
var line = context.getLineContent();
var char: string = line[offset];
// See if the right electric character was pressed
if (char !== this._docComment.open.charAt(this._docComment.open.length - 1)) {
return null;
}
// If this line already contains the closing tag, do nothing.
if (line.indexOf(this._docComment.close, offset) >= 0) {
return null;
}
// If we're not in a documentation comment, do nothing.
var lastTokenIndex = context.findIndexOfOffset(offset);
if (! this.containsTokenTypes(context.getTokenType(lastTokenIndex), this._docComment.scope)) {
return null;
}
if (line.substring(context.getTokenStartIndex(lastTokenIndex), offset+1/* include electric char*/) !== this._docComment.open) {
return null;
}
return { appendText: this._docComment.close};
}
}
function once<T, R>(keyFn:(input:T)=>string, computeFn:(input:T)=>R):(input:T)=>R {
let cache: {[key:string]:R;} = {};
return (input:T):R => {
let key = keyFn(input);
if (!cache.hasOwnProperty(key)) {
cache[key] = computeFn(input);
}
return cache[key];
};
}
var getRegexForBracketPair = once<ISimpleInternalBracket,RegExp>(
(input) => `${input.open};${input.close}`,
(input) => {
return createOrRegex([input.open, input.close]);
}
);
var getReversedRegexForBracketPair = once<ISimpleInternalBracket,RegExp>(
(input) => `${input.open};${input.close}`,
(input) => {
return createOrRegex([toReversedString(input.open), toReversedString(input.close)]);
}
);
var getRegexForBrackets = once<ISimpleInternalBracket[],RegExp>(
(input) => input.map(b => `${b.open};${b.close}`).join(';'),
(input) => {
let pieces: string[] = [];
input.forEach((b) => {
pieces.push(b.open);
pieces.push(b.close);
});
return createOrRegex(pieces);
}
);
var getReversedRegexForBrackets = once<ISimpleInternalBracket[],RegExp>(
(input) => input.map(b => `${b.open};${b.close}`).join(';'),
(input) => {
let pieces: string[] = [];
input.forEach((b) => {
pieces.push(toReversedString(b.open));
pieces.push(toReversedString(b.close));
});
return createOrRegex(pieces);
}
);
function createOrRegex(pieces:string[]): RegExp {
let regexStr = `(${pieces.map(Strings.escapeRegExpCharacters).join(')|(')})`;
return Strings.createRegExp(regexStr, true, false, false, false);
}
function toReversedString(str:string): string {
let reversedStr = '';
for (let i = str.length - 1; i >= 0; i--) {
reversedStr += str.charAt(i);
}
return reversedStr;
}
export class BracketsUtils {
private static _findPrevBracketInText(reversedBracketRegex:RegExp, lineNumber:number, reversedText:string, offset:number): Range {
let m = reversedText.match(reversedBracketRegex);
if (!m) {
return null;
}
let matchOffset = reversedText.length - 1 - m.index;
let matchLength = m[0].length;
let absoluteMatchOffset = offset + matchOffset;
return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
}
public static findPrevBracketInToken(reversedBracketRegex:RegExp, lineNumber:number, lineText:string, currentTokenStart:number, currentTokenEnd:number): Range {
// Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;)
let currentTokenReversedText = '';
for (let index = currentTokenEnd - 1; index >= currentTokenStart; index--) {
currentTokenReversedText += lineText.charAt(index);
}
return this._findPrevBracketInText(reversedBracketRegex, lineNumber, currentTokenReversedText, currentTokenStart);
}
public static findNextBracketInText(bracketRegex:RegExp, lineNumber:number, text:string, offset:number): Range {
let m = text.match(bracketRegex);
if (!m) {
return null;
}
let matchOffset = m.index;
let matchLength = m[0].length;
let absoluteMatchOffset = offset + matchOffset;
return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
}
public static findNextBracketInToken(bracketRegex:RegExp, lineNumber:number, lineText:string, currentTokenStart:number, currentTokenEnd:number): Range {
let currentTokenText = lineText.substring(currentTokenStart, currentTokenEnd);
return this.findNextBracketInText(bracketRegex, lineNumber, currentTokenText, currentTokenStart);
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IInplaceReplaceSupport, IInplaceReplaceSupportResult} from 'vs/editor/common/modes';
import {ITokenizedModel, IRange} from 'vs/editor/common/editorCommon';
import {IResourceService} from 'vs/editor/common/services/resourceService';
import URI from 'vs/base/common/uri';
export interface IReplaceSupportHelper {
valueSetReplace(valueSet: string[], value: string, up: boolean): string;
valueSetsReplace(valueSets: string[][], value: string, up: boolean): string;
}
class ReplaceSupportHelperImpl implements IReplaceSupportHelper {
public valueSetsReplace(valueSets:string[][], value:string, up:boolean):string {
var result:string = null;
for (let i = 0, len = valueSets.length; result === null && i < len; i++) {
result = this.valueSetReplace(valueSets[i], value, up);
}
return result;
}
public valueSetReplace(valueSet:string[], value:string, up:boolean):string {
var idx = valueSet.indexOf(value);
if(idx >= 0) {
idx += up ? +1 : -1;
if(idx < 0) {
idx = valueSet.length - 1;
} else {
idx %= valueSet.length;
}
return valueSet[idx];
}
return null;
}
}
export var ReplaceSupport: IReplaceSupportHelper = new ReplaceSupportHelperImpl();
function isFunction(something) {
return typeof something === 'function';
}
export interface IInplaceReplaceSupportCustomization {
textReplace?: (value: string, up: boolean) => string;
navigateValueSetFallback?: (resource: URI, range: IRange, up: boolean) => TPromise<IInplaceReplaceSupportResult>;
}
export class AbstractInplaceReplaceSupport implements IInplaceReplaceSupport {
private defaults: {
textReplace: boolean;
navigateValueSetFallback: boolean;
};
private customization:IInplaceReplaceSupportCustomization;
constructor(customization: IInplaceReplaceSupportCustomization = null) {
this.defaults = {
textReplace: !customization || !isFunction(customization.textReplace),
navigateValueSetFallback: !customization || !isFunction(customization.navigateValueSetFallback)
};
this.customization = customization;
}
public navigateValueSet(resource:URI, range:IRange, up:boolean):TPromise<IInplaceReplaceSupportResult> {
var result = this.doNavigateValueSet(resource, range, up, true);
if (result && result.value && result.range) {
return TPromise.as(result);
}
if (this.defaults.navigateValueSetFallback) {
return TPromise.as(null);
}
return this.customization.navigateValueSetFallback(resource, range, up);
}
private doNavigateValueSet(resource:URI, range:IRange, up:boolean, selection:boolean):IInplaceReplaceSupportResult {
var model = this.getModel(resource),
result:IInplaceReplaceSupportResult = { range:null, value: null },
text:string;
if(selection) {
// Replace selection
if(range.startColumn === range.endColumn) {
range.endColumn += 1;
}
text = model.getValueInRange(range);
result.range = range;
} else {
// Replace word
var position = { lineNumber: range.startLineNumber, column: range.startColumn };
var wordPos = model.getWordAtPosition(position);
if(!wordPos || wordPos.startColumn === -1) {
return null;
}
text = wordPos.word;
result.range = { startLineNumber : range.startLineNumber, endLineNumber: range.endLineNumber, startColumn: wordPos.startColumn, endColumn: wordPos.endColumn };
}
// Try to replace numbers or text
var numberResult = this.numberReplace(text, up);
if(numberResult !== null) {
result.value = numberResult;
} else {
var textResult = this.textReplace(text, up);
if(textResult !== null) {
result.value = textResult;
} else if(selection) {
return this.doNavigateValueSet(resource, range, up, false);
}
}
return result;
}
private numberReplace(value:string, up:boolean):string {
var precision = Math.pow(10, value.length - (value.lastIndexOf('.') + 1)),
n1 = Number(value),
n2 = parseFloat(value);
if(!isNaN(n1) && !isNaN(n2) && n1 === n2) {
if(n1 === 0 && !up) {
return null; // don't do negative
// } else if(n1 === 9 && up) {
// return null; // don't insert 10 into a number
} else {
n1 = Math.floor(n1 * precision);
n1 += up ? precision : -precision;
return String(n1 / precision);
}
}
return null;
}
private _defaultValueSet: string[][] = [
['true', 'false'],
['True', 'False'],
['Private', 'Public', 'Friend', 'ReadOnly', 'Partial', 'Protected', 'WriteOnly'],
['public', 'protected', 'private'],
];
private textReplace(value:string, up:boolean):string {
if (this.defaults.textReplace) {
return ReplaceSupport.valueSetsReplace(this._defaultValueSet, value, up);
}
return this.customization.textReplace(value, up)
|| ReplaceSupport.valueSetsReplace(this._defaultValueSet, value, up);
}
protected getModel(resource:URI): ITokenizedModel {
throw new Error('Not implemented');
}
}
export class WorkerInplaceReplaceSupport extends AbstractInplaceReplaceSupport {
private resourceService: IResourceService;
constructor(resourceService: IResourceService, customization: IInplaceReplaceSupportCustomization = null) {
super(customization);
this.resourceService = resourceService;
}
protected getModel(resource:URI): ITokenizedModel {
return this.resourceService.get(resource);
}
}
......@@ -5,9 +5,9 @@
'use strict';
import {handleEvent} from 'vs/editor/common/modes/supports';
import {IEnterAction, IndentAction, IOnEnterSupport, ILineContext, IMode} from 'vs/editor/common/modes';
import EditorCommon = require('vs/editor/common/editorCommon');
import Errors = require('vs/base/common/errors');
import {IEnterAction, IndentAction, IRichEditOnEnter, ILineContext, IMode} from 'vs/editor/common/modes';
import {ITokenizedModel, ITextModel, IPosition} from 'vs/editor/common/editorCommon';
import {onUnexpectedError} from 'vs/base/common/errors';
import Strings = require('vs/base/common/strings');
import {Position} from 'vs/editor/common/core/position';
......@@ -40,7 +40,7 @@ interface IProcessedBracketPair extends IBracketPair {
closeRegExp: RegExp;
}
export class OnEnterSupport implements IOnEnterSupport {
export class OnEnterSupport implements IRichEditOnEnter {
private static _INDENT: IEnterAction = { indentAction: IndentAction.Indent };
private static _INDENT_OUTDENT: IEnterAction = { indentAction: IndentAction.IndentOutdent };
......@@ -72,21 +72,21 @@ export class OnEnterSupport implements IOnEnterSupport {
this._indentationRules = opts.indentationRules;
}
public onEnter(model:EditorCommon.ITokenizedModel, position: EditorCommon.IPosition): IEnterAction {
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 this._onEnter(model, position);
} else if (nestedMode.onEnterSupport) {
return nestedMode.onEnterSupport.onEnter(model, position);
} else if (nestedMode.richEditSupport && nestedMode.richEditSupport.onEnter) {
return nestedMode.richEditSupport.onEnter.onEnter(model, position);
} else {
return null;
}
});
}
private _onEnter(model:EditorCommon.ITextModel, position: EditorCommon.IPosition): IEnterAction {
private _onEnter(model:ITextModel, position: IPosition): IEnterAction {
let lineText = model.getLineContent(position.lineNumber);
let beforeEnterText = lineText.substr(0, position.column - 1);
let afterEnterText = lineText.substr(position.column - 1);
......@@ -175,40 +175,28 @@ export class OnEnterSupport implements IOnEnterSupport {
try {
return new RegExp(def);
} catch(err) {
Errors.onUnexpectedError(err);
onUnexpectedError(err);
return null;
}
}
}
export function getRawEnterActionAtPosition(model:EditorCommon.ITokenizedModel, lineNumber:number, column:number): IEnterAction {
let enterAction:IEnterAction;
export function getRawEnterActionAtPosition(model:ITokenizedModel, lineNumber:number, column:number): IEnterAction {
let result:IEnterAction;
let richEditSupport = model.getMode().richEditSupport;
if (model.getMode().onEnterSupport) {
if (richEditSupport && richEditSupport.onEnter) {
try {
enterAction = model.getMode().onEnterSupport.onEnter(model, new Position(lineNumber, column));
result = richEditSupport.onEnter.onEnter(model, new Position(lineNumber, column));
} catch (e) {
Errors.onUnexpectedError(e);
onUnexpectedError(e);
}
}
if (!enterAction) {
if (model.getMode().electricCharacterSupport) {
let lineContext = model.getLineContext(lineNumber);
try {
enterAction = model.getMode().electricCharacterSupport.onEnter(lineContext, column - 1);
} catch(e) {
Errors.onUnexpectedError(e);
}
}
} else {
// console.log('USING NEW INDENTATION LOGIC!');
}
return enterAction;
return result;
}
export function getEnterActionAtPosition(model:EditorCommon.ITokenizedModel, lineNumber:number, column:number): { enterAction: IEnterAction; indentation: string; } {
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) {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IParameterHints, IParameterHintsSupport, ILineContext, IMode} from 'vs/editor/common/modes';
import {IPosition} from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import {handleEvent, isLineToken} from 'vs/editor/common/modes/supports';
export interface IParameterHintsContribution {
triggerCharacters: string[];
excludeTokens: string[];
getParameterHints: (resource: URI, position: IPosition) => TPromise<IParameterHints>;
}
export class ParameterHintsSupport implements IParameterHintsSupport {
private _modeId: string;
private contribution: IParameterHintsContribution;
constructor(modeId: string, contribution: IParameterHintsContribution) {
this._modeId = modeId;
this.contribution = contribution;
}
public getParameterHintsTriggerCharacters(): string[]
{
return this.contribution.triggerCharacters;
}
public shouldTriggerParameterHints(context: ILineContext, offset: number): boolean
{
return handleEvent(context, offset, (nestedMode:IMode, context:ILineContext, offset:number) => {
if (this._modeId === nestedMode.getId()) {
if (!Array.isArray(this.contribution.excludeTokens)) {
return true;
}
if (this.contribution.excludeTokens.length === 1 && this.contribution.excludeTokens[0] === '*') {
return false;
}
return !isLineToken(context, offset-1, this.contribution.excludeTokens);
} else if (nestedMode.parameterHintsSupport) {
return nestedMode.parameterHintsSupport.shouldTriggerParameterHints(context, offset);
} else {
return false;
}
});
}
public getParameterHints(resource: URI, position: IPosition): TPromise<IParameterHints> {
return this.contribution.getParameterHints(resource, position);
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {IReference, IReferenceSupport, ILineContext, IMode} from 'vs/editor/common/modes';
import {IPosition} from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import {handleEvent, isLineToken} from 'vs/editor/common/modes/supports';
export interface IReferenceContribution {
tokens: string[];
findReferences: (resource: URI, position: IPosition, includeDeclaration: boolean) => TPromise<IReference[]>;
}
export class ReferenceSupport implements IReferenceSupport {
private _modeId: string;
private contribution: IReferenceContribution;
/**
* Provide the token type postfixes for the tokens where a reference can be found in the 'tokens' argument.
*/
constructor(modeId: string, contribution: IReferenceContribution) {
this._modeId = modeId;
this.contribution = contribution;
}
public canFindReferences(context: ILineContext, offset:number):boolean {
return handleEvent(context, offset, (nestedMode:IMode, context:ILineContext, offset:number) => {
if (this._modeId === nestedMode.getId()) {
return (!Array.isArray(this.contribution.tokens) ||
this.contribution.tokens.length < 1 ||
isLineToken(context, offset, this.contribution.tokens));
} else if (nestedMode.referenceSupport) {
return nestedMode.referenceSupport.canFindReferences(context, offset);
} else {
return false;
}
});
}
public findReferences(resource: URI, position: IPosition, includeDeclaration: boolean): TPromise<IReference[]> {
return this.contribution.findReferences(resource, position, includeDeclaration);
}
}
/*---------------------------------------------------------------------------------------------
* 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 Modes from 'vs/editor/common/modes';
import {OnEnterSupport, IOnEnterSupportOptions, IIndentationRules, IOnEnterRegExpRules} from 'vs/editor/common/modes/supports/onEnter';
import {CharacterPairSupport} from 'vs/editor/common/modes/supports/characterPair';
import {BracketElectricCharacterSupport, IBracketElectricCharacterContribution} from 'vs/editor/common/modes/supports/electricCharacter';
import {ICharacterPairContribution} from 'vs/editor/common/modes/supports/characterPair';
import {NullMode} from 'vs/editor/common/modes/nullMode';
export type CharacterPair = [string, string];
export interface CommentRule {
lineComment?: string;
blockComment?: CharacterPair;
}
export interface IRichEditConfiguration {
comments?: CommentRule;
brackets?: CharacterPair[];
wordPattern?: RegExp;
indentationRules?: IIndentationRules;
onEnterRules?: IOnEnterRegExpRules[];
__electricCharacterSupport?: IBracketElectricCharacterContribution;
__characterPairSupport?: ICharacterPairContribution;
}
export class RichEditSupport implements Modes.IRichEditSupport {
public electricCharacter: BracketElectricCharacterSupport;
public comments: Modes.ICommentsConfiguration;
public characterPair: Modes.IRichEditCharacterPair;
public wordDefinition: RegExp;
public onEnter: Modes.IRichEditOnEnter;
public brackets: Modes.IRichEditBrackets;
constructor(modeId:string, conf:IRichEditConfiguration) {
this._handleOnEnter(modeId, conf);
this._handleComments(modeId, conf);
if (conf.__characterPairSupport) {
this.characterPair = new CharacterPairSupport(modeId, conf.__characterPairSupport);
}
if (conf.__electricCharacterSupport) {
this.electricCharacter = new BracketElectricCharacterSupport(modeId, conf.__electricCharacterSupport);
this.brackets = this.electricCharacter.getRichEditBrackets();
}
this.wordDefinition = conf.wordPattern || NullMode.DEFAULT_WORD_REGEXP;
}
private _handleOnEnter(modeId:string, conf:IRichEditConfiguration): void {
// on enter
let onEnter: IOnEnterSupportOptions = {};
let empty = true;
let {brackets, indentationRules, onEnterRules} = conf;
if (brackets) {
empty = false;
onEnter.brackets = brackets.map(pair => {
let [open, close] = pair;
return { open, close };
});
}
if (indentationRules) {
empty = false;
onEnter.indentationRules = indentationRules;
}
if (onEnterRules) {
empty = false;
onEnter.regExpRules = <any>onEnterRules;
}
if (!empty) {
this.onEnter = new OnEnterSupport(modeId, onEnter);
}
}
private _handleComments(modeId:string, conf:IRichEditConfiguration): 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;
}
}
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {DefaultFilter} from 'vs/editor/common/modes/modesFilters';
import {ISuggestResult, ISuggestSupport, ISuggestion, ILineContext, IMode, ISuggestionFilter} from 'vs/editor/common/modes';
import {IPosition} from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import {handleEvent, isLineToken} from 'vs/editor/common/modes/supports';
export interface ISuggestContribution {
triggerCharacters: string[];
disableAutoTrigger?: boolean;
excludeTokens: string[];
suggest: (resource: URI, position: IPosition) => TPromise<ISuggestResult[]>;
getSuggestionDetails? : (resource:URI, position:IPosition, suggestion:ISuggestion) => TPromise<ISuggestion>;
}
export class SuggestSupport implements ISuggestSupport {
private _modeId: string;
private contribution: ISuggestContribution;
public suggest : (resource:URI, position:IPosition) => TPromise<ISuggestResult[]>;
public getSuggestionDetails : (resource:URI, position:IPosition, suggestion:ISuggestion) => TPromise<ISuggestion>;
constructor(modeId: string, contribution : ISuggestContribution){
this._modeId = modeId;
this.contribution = contribution;
this.suggest = (resource, position) => contribution.suggest(resource, position);
if (typeof contribution.getSuggestionDetails === 'function') {
this.getSuggestionDetails = (resource, position, suggestion) => contribution.getSuggestionDetails(resource, position, suggestion);
}
}
shouldAutotriggerSuggest(context: ILineContext, offset: number, triggeredByCharacter: string): boolean {
return handleEvent(context, offset, (nestedMode:IMode, context:ILineContext, offset:number) => {
if (this._modeId === nestedMode.getId()) {
if (this.contribution.disableAutoTrigger) {
return false;
}
if (!Array.isArray(this.contribution.excludeTokens)) {
return true;
}
if (this.contribution.excludeTokens.length === 1 && this.contribution.excludeTokens[0] === '*') {
return false;
}
return !isLineToken(context, offset-1, this.contribution.excludeTokens, true);
} else if (nestedMode.suggestSupport) {
return nestedMode.suggestSupport.shouldAutotriggerSuggest(context, offset, triggeredByCharacter);
} else {
return false;
}
});
}
public getFilter(): ISuggestionFilter {
return DefaultFilter;
}
public getTriggerCharacters(): string[] {
return this.contribution.triggerCharacters;
}
public shouldShowEmptySuggestionList(): boolean {
return true;
}
}
export interface IComposableSuggestContribution extends ISuggestContribution {
composeSuggest(resource:URI, position:IPosition, superSuggestions:ISuggestResult[]): TPromise<ISuggestResult[]>;
}
export class ComposableSuggestSupport extends SuggestSupport {
constructor(modeId: string, contribution: IComposableSuggestContribution) {
super(modeId, contribution);
this.suggest = (resource, position) => {
return (
contribution.suggest(resource, position)
.then(superSuggestions => contribution.composeSuggest(resource, position, superSuggestions))
);
};
}
}
......@@ -7,10 +7,13 @@
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
import {TPromise} from 'vs/base/common/winjs.base';
import Modes = require('vs/editor/common/modes');
import Supports = require ('vs/editor/common/modes/supports');
import MonarchTypes = require('vs/editor/common/modes/monarch/monarchTypes');
import {IOnEnterSupportOptions} from 'vs/editor/common/modes/supports/onEnter';
import {IDisposable} from 'vs/base/common/lifecycle';
import {IRichEditConfiguration} from 'vs/editor/common/modes/supports/richEditSupport';
import {IDeclarationContribution} from 'vs/editor/common/modes/supports/declarationSupport';
import {IReferenceContribution} from 'vs/editor/common/modes/supports/referenceSupport';
import {IParameterHintsContribution} from 'vs/editor/common/modes/supports/parameterHintsSupport';
import {ISuggestContribution} from 'vs/editor/common/modes/supports/suggestSupport';
export var IModeService = createDecorator<IModeService>('modeService');
......@@ -27,6 +30,16 @@ export interface IModeService {
configureAllModes(config:any): void;
getConfigurationForMode(modeId:string): any;
// --- reading
isRegisteredMode(mimetypeOrModeId: string): boolean;
getRegisteredModes(): string[];
getRegisteredLanguageNames(): string[];
getExtensions(alias: string): string[];
getMimeForMode(modeId: string): string;
getLanguageName(modeId:string): string;
getModeIdForLanguageName(alias:string): string;
getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string;
// --- instantiation
lookup(commaSeparatedMimetypesOrCommaSeparatedIds: string): IModeLookupResult[];
getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): Modes.IMode;
......@@ -34,24 +47,20 @@ export interface IModeService {
getOrCreateModeByLanguageName(languageName: string): TPromise<Modes.IMode>;
getOrCreateModeByFilenameOrFirstLine(filename: string, firstLine?:string): TPromise<Modes.IMode>;
registerDeclarativeCharacterPairSupport(modeId: string, support: Modes.ICharacterPairContribution): IDisposable;
registerCodeLensSupport(modeId: string, support: Modes.ICodeLensSupport): IDisposable;
registerDeclarativeCommentsSupport(modeId: string, support: Supports.ICommentsSupportContribution): IDisposable;
registerDeclarativeDeclarationSupport(modeId: string, contribution: Supports.IDeclarationContribution): IDisposable;
registerDeclarativeElectricCharacterSupport(modeId: string, support: Supports.IBracketElectricCharacterContribution): IDisposable;
registerDeclarativeDeclarationSupport(modeId: string, contribution: IDeclarationContribution): IDisposable;
registerExtraInfoSupport(modeId: string, support: Modes.IExtraInfoSupport): IDisposable;
registerFormattingSupport(modeId: string, support: Modes.IFormattingSupport): IDisposable;
registerInplaceReplaceSupport(modeId: string, support: Modes.IInplaceReplaceSupport): IDisposable;
registerOccurrencesSupport(modeId: string, support: Modes.IOccurrencesSupport): IDisposable;
registerOutlineSupport(modeId: string, support: Modes.IOutlineSupport): IDisposable;
registerDeclarativeParameterHintsSupport(modeId: string, support: Modes.IParameterHintsContribution): IDisposable;
registerDeclarativeParameterHintsSupport(modeId: string, support: IParameterHintsContribution): IDisposable;
registerQuickFixSupport(modeId: string, support: Modes.IQuickFixSupport): IDisposable;
registerDeclarativeReferenceSupport(modeId: string, contribution: Supports.IReferenceContribution): IDisposable;
registerDeclarativeReferenceSupport(modeId: string, contribution: IReferenceContribution): IDisposable;
registerRenameSupport(modeId: string, support: Modes.IRenameSupport): IDisposable;
registerDeclarativeSuggestSupport(modeId: string, declaration: Supports.ISuggestContribution): IDisposable;
registerDeclarativeSuggestSupport(modeId: string, declaration: ISuggestContribution): IDisposable;
registerTokenizationSupport(modeId: string, callback: (mode: Modes.IMode) => Modes.ITokenizationSupport): IDisposable;
registerDeclarativeTokenTypeClassificationSupport(modeId: string, support: Supports.ITokenTypeClassificationSupportContribution): IDisposable;
registerDeclarativeOnEnterSupport(modeId: string, support: IOnEnterSupportOptions): IDisposable;
registerRichEditSupport(modeId: string, support: IRichEditConfiguration): IDisposable;
registerMonarchDefinition(modeId:string, language:MonarchTypes.ILanguage): IDisposable;
}
......@@ -121,13 +121,8 @@ export class BlockCommentCommand implements EditorCommon.ICommand {
var endLineNumber = this._selection.endLineNumber;
var endColumn = this._selection.endColumn;
var commentsSupport = model.getModeAtPosition(startLineNumber, startColumn).commentsSupport;
if (!commentsSupport) {
// Mode does not support comments
return;
}
var config = commentsSupport.getCommentsConfiguration();
let richEditSupport = model.getModeAtPosition(startLineNumber, startColumn).richEditSupport;
let config = richEditSupport ? richEditSupport.comments : null;
if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {
// Mode does not support block comments
return;
......
......@@ -11,7 +11,7 @@ import {BlockCommentCommand} from 'vs/editor/contrib/comment/common/blockComment
import {Selection} from 'vs/editor/common/core/selection';
function testBlockCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
var mode = new CommentMode({ lineCommentTokens: ['!@#'], blockCommentStartToken: '<0', blockCommentEndToken: '0>' });
var mode = new CommentMode({ lineCommentToken: '!@#', blockCommentStartToken: '<0', blockCommentEndToken: '0>' });
testCommand(lines, mode, selection, (sel) => new BlockCommentCommand(sel), expectedLines, expectedSelection);
}
......
......@@ -324,7 +324,7 @@ export class StartFindReplaceAction extends EditorAction {
let controller = CommonFindController.getFindController(this.editor);
controller.start({
forceRevealReplace: true,
seedSearchStringFromSelection: (controller.getState().searchString.length === 0),
seedSearchStringFromSelection: true,
seedSearchScopeFromSelection: true,
shouldFocus: FindStartFocusAction.FocusReplaceInput,
shouldAnimate: true
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册