Merge branch 'master' into ben/stacks

This commit is contained in:
Benjamin Pasero 2016-05-21 08:06:12 +02:00
commit 6b0f18a91f
409 changed files with 18412 additions and 9764 deletions

15
.vscode/launch.json vendored
View file

@ -92,6 +92,21 @@
"request": "launch",
"program": "${workspaceRoot}/src/vs/languages/css/common/buildscripts/generate_browserjs.js",
"stopOnEntry": false
},
{
"name": "Debug monaco",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/build/lib/monaco.js",
"stopOnEntry": false,
"args": [
],
"cwd": "${workspaceRoot}/build/lib"
// ,
// "port": 5870,
// "sourceMaps": true,
// "outDir": "${workspaceRoot}/out"
}
]
}

View file

@ -40,10 +40,10 @@ exports.loaderConfig = function (emptyPaths) {
paths: {
'vs/extensions': 'extensions'
}
}
},
nodeModules: emptyPaths||[]
};
(emptyPaths || []).forEach(function(m) { result.paths[m] = 'empty:'; });
return result;
};

View file

@ -31,13 +31,12 @@ var languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita'];
var tasks = compilations.map(function(tsconfigFile) {
var absolutePath = path.join(extensionsPath, tsconfigFile);
var absoluteDirname = path.dirname(absolutePath);
var relativeDirname = path.dirname(tsconfigFile);
var tsOptions = require(absolutePath).compilerOptions;
tsOptions.verbose = !quiet;
tsOptions.sourceMap = true;
tsOptions.sourceRoot = util.toFileUri(path.join(absoluteDirname, 'src'));
tsOptions.sourceRoot = '../src';
var name = relativeDirname.replace(/\//g, '-');

View file

@ -32,7 +32,7 @@ var baseModules = [
'applicationinsights', 'assert', 'child_process', 'chokidar', 'crypto', 'emmet',
'events', 'fs', 'getmac', 'glob', 'graceful-fs', 'http', 'http-proxy-agent',
'https', 'https-proxy-agent', 'iconv-lite', 'electron', 'net',
'os', 'path', 'readline', 'sax', 'semver', 'stream', 'string_decoder', 'url',
'os', 'path', 'pty.js', 'readline', 'sax', 'semver', 'stream', 'string_decoder', 'url', 'term.js',
'vscode-textmate', 'winreg', 'yauzl', 'native-keymap', 'zlib', 'minimist'
];
@ -52,6 +52,7 @@ var vscodeResources = [
'out-build/cli.js',
'out-build/bootstrap.js',
'out-build/bootstrap-amd.js',
'out-build/paths.js',
'out-build/vs/**/*.{svg,png,cur}',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh}',
'out-build/vs/base/worker/workerMainCompatibility.html',
@ -67,6 +68,7 @@ var vscodeResources = [
'out-build/vs/workbench/parts/html/browser/webview.html',
'out-build/vs/workbench/parts/markdown/**/*.md',
'out-build/vs/workbench/parts/tasks/**/*.json',
'out-build/vs/workbench/parts/terminal/electron-browser/terminalProcess.js',
'out-build/vs/workbench/services/files/**/*.exe',
'out-build/vs/workbench/services/files/**/*.md',
'!**/test/**'
@ -295,6 +297,10 @@ function prepareDebPackage(arch) {
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(rename('DEBIAN/prerm'))
var postrm = gulp.src('resources/linux/debian/postrm.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(rename('DEBIAN/postrm'))
var postinst = gulp.src('resources/linux/debian/postinst.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@ARCHITECTURE@@', debArch))
@ -302,7 +308,7 @@ function prepareDebPackage(arch) {
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
.pipe(rename('DEBIAN/postinst'))
var all = es.merge(control, postinst, prerm, desktop, icon, code);
var all = es.merge(control, postinst, postrm, prerm, desktop, icon, code);
return all.pipe(symdest(destination));
};

4252
build/lib/monaco-editor.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,57 @@
declare module monaco {
interface Thenable<R> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
}
export interface Event<T> {
(listener: (e: T) => any): IDisposable;
}
export class Emitter<T> {
constructor();
event: Event<T>;
fire(event?: T): void;
dispose(): void;
}
export interface IDisposable {
dispose(): void;
}
#include(vs/base/common/uri): URI
#include(vs/base/common/winjs.base.d.ts): TValueCallback, ProgressCallback, TPromise
}
declare module monaco.editor {
export function create(domElement: HTMLElement, options: IEditorConstructionOptions, services?: any): ICodeEditor;
export function createDiffEditor(domElement: HTMLElement, options: IDiffEditorConstructionOptions, services?: any): IDiffEditor;
export function createModel(value:string, mode:string|IMonarchLanguage|IMode, associatedResource?:any|string): IModel;
export function getOrCreateMode(modeId: string): TPromise<IMode>;
export function createCustomMode(description:IMonarchLanguage): TPromise<IMode>;
export function colorize(text: string, modeId: string, options: IColorizerOptions): TPromise<string>;
export function colorizeElement(domNode: HTMLElement, options: IColorizerElementOptions): TPromise<void>;
export function colorizeLine(line: string, tokens: Editor.ILineToken[], tabSize?: number): string;
export function colorizeModelLine(model: Editor.IModel, lineNumber: number, tabSize?: number): string;
export function registerWorkerParticipant(modeId:string, moduleName:string, ctorName:string): void;
export function configureMode(modeId: string, options: any): void;
#include(vs/base/browser/ui/scrollbar/scrollableElementOptions): ScrollbarVisibility
#include(vs/base/common/htmlContent): IHTMLContentElementCode, IHTMLContentElement
#include(vs/editor/common/modes): ILineContext, IMode, IModeTransition, IToken
#includeAll(vs/editor/common/editorCommon):
#includeAll(vs/editor/browser/editorBrowser):
}

117
build/lib/monaco.js Normal file
View file

@ -0,0 +1,117 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
"use strict";
// PREREQUISITE:
// SET VSCODE_BUILD_DECLARATION_FILES=1
// run gulp watch once
var fs = require('fs');
var ts = require('typescript');
var path = require('path');
var SRC = path.join(__dirname, '../../src');
var OUT = path.join(__dirname, '../../out');
function moduleIdToPath(moduleId) {
if (/\.d\.ts/.test(moduleId)) {
return path.join(SRC, moduleId);
}
return path.join(OUT, moduleId) + '.d.ts';
}
var SOURCE_FILE_MAP = {};
function getSourceFile(moduleId) {
if (!SOURCE_FILE_MAP[moduleId]) {
var filePath = moduleIdToPath(moduleId);
var fileContents = fs.readFileSync(filePath).toString();
var sourceFile = ts.createSourceFile(filePath, fileContents, ts.ScriptTarget.ES5);
SOURCE_FILE_MAP[moduleId] = sourceFile;
}
return SOURCE_FILE_MAP[moduleId];
}
function visitTopLevelDeclarations(sourceFile, visitor) {
var stop = false;
var visit = function (node) {
if (stop) {
return;
}
switch (node.kind) {
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.ClassDeclaration:
stop = visitor(node);
break;
}
if (stop) {
return;
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
function getAllTopLevelDeclarations(sourceFile) {
var all = [];
visitTopLevelDeclarations(sourceFile, function (node) {
all.push(node);
return false /*continue*/;
});
return all;
}
function getTopLevelDeclaration(sourceFile, typeName) {
var result = null;
visitTopLevelDeclarations(sourceFile, function (node) {
if (node.name.text === typeName) {
result = node;
return true /*stop*/;
}
return false /*continue*/;
});
return result;
}
function getNodeText(sourceFile, node) {
return sourceFile.getFullText().substring(node.pos, node.end);
}
function getMassagedTopLevelDeclarationText(sourceFile, declaration) {
var result = getNodeText(sourceFile, declaration);
result = result.replace(/export default/g, 'export');
result = result.replace(/export declare/g, 'export');
return result;
}
var recipe = fs.readFileSync(path.join(__dirname, './monaco-editor.d.ts.recipe')).toString();
var lines = recipe.split(/\r\n|\n|\r/);
var result = [];
lines.forEach(function (line) {
var m1 = line.match(/^\s*#include\(([^\)]*)\)\:(.*)$/);
if (m1) {
var moduleId = m1[1];
var sourceFile_1 = getSourceFile(moduleId);
var typeNames = m1[2].split(/,/);
typeNames.forEach(function (typeName) {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
var declaration = getTopLevelDeclaration(sourceFile_1, typeName);
result.push(getMassagedTopLevelDeclarationText(sourceFile_1, declaration));
});
return;
}
var m2 = line.match(/^\s*#includeAll\(([^\)]*)\)\:(.*)$/);
if (m2) {
var moduleId = m2[1];
var sourceFile_2 = getSourceFile(moduleId);
var typeNames = m2[2].split(/,/);
var typesToExclude_1 = {};
typeNames.forEach(function (typeName) {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
typesToExclude_1[typeName] = true;
});
getAllTopLevelDeclarations(sourceFile_2).forEach(function (declaration) {
result.push(getMassagedTopLevelDeclarationText(sourceFile_2, declaration));
});
return;
}
result.push(line);
});
fs.writeFileSync(path.join(__dirname, './monaco-editor.d.ts'), result.join('\n'));

153
build/lib/monaco.ts Normal file
View file

@ -0,0 +1,153 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// PREREQUISITE:
// SET VSCODE_BUILD_DECLARATION_FILES=1
// run gulp watch once
import fs = require('fs');
import ts = require('typescript');
import path = require('path');
const SRC = path.join(__dirname, '../../src');
const OUT = path.join(__dirname, '../../out');
function moduleIdToPath(moduleId:string): string {
if (/\.d\.ts/.test(moduleId)) {
return path.join(SRC, moduleId);
}
return path.join(OUT, moduleId) + '.d.ts';
}
var SOURCE_FILE_MAP: {[moduleId:string]:ts.SourceFile;} = {};
function getSourceFile(moduleId:string): ts.SourceFile {
if (!SOURCE_FILE_MAP[moduleId]) {
let filePath = moduleIdToPath(moduleId);
let fileContents = fs.readFileSync(filePath).toString();
let sourceFile = ts.createSourceFile(filePath, fileContents, ts.ScriptTarget.ES5);
SOURCE_FILE_MAP[moduleId] = sourceFile;
}
return SOURCE_FILE_MAP[moduleId];
}
type TypeScriptTypeDeclaration = ts.InterfaceDeclaration | ts.EnumDeclaration | ts.ClassDeclaration;
function visitTopLevelDeclarations(sourceFile:ts.SourceFile, visitor:(node:TypeScriptTypeDeclaration)=>boolean): void {
let stop = false;
let visit = (node: ts.Node): void => {
if (stop) {
return;
}
switch (node.kind) {
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.ClassDeclaration:
stop = visitor(<TypeScriptTypeDeclaration>node);
break;
}
if (stop) {
return;
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
function getAllTopLevelDeclarations(sourceFile:ts.SourceFile): TypeScriptTypeDeclaration[] {
let all:TypeScriptTypeDeclaration[] = [];
visitTopLevelDeclarations(sourceFile, (node) => {
all.push(node);
return false /*continue*/;
});
return all;
}
function getTopLevelDeclaration(sourceFile:ts.SourceFile, typeName:string): TypeScriptTypeDeclaration {
let result:TypeScriptTypeDeclaration = null;
visitTopLevelDeclarations(sourceFile, (node) => {
if (node.name.text === typeName) {
result = node;
return true /*stop*/;
}
return false /*continue*/;
});
return result;
}
function getNodeText(sourceFile:ts.SourceFile, node:ts.Node): string {
return sourceFile.getFullText().substring(node.pos, node.end);
}
function getMassagedTopLevelDeclarationText(sourceFile:ts.SourceFile, declaration: TypeScriptTypeDeclaration): string {
let result = getNodeText(sourceFile, declaration);
result = result.replace(/export default/g, 'export');
result = result.replace(/export declare/g, 'export');
return result;
}
var recipe = fs.readFileSync(path.join(__dirname, './monaco-editor.d.ts.recipe')).toString();
var lines = recipe.split(/\r\n|\n|\r/);
var result = [];
lines.forEach(line => {
let m1 = line.match(/^\s*#include\(([^\)]*)\)\:(.*)$/);
if (m1) {
let moduleId = m1[1];
let sourceFile = getSourceFile(moduleId);
let typeNames = m1[2].split(/,/);
typeNames.forEach((typeName) => {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
let declaration = getTopLevelDeclaration(sourceFile, typeName);
result.push(getMassagedTopLevelDeclarationText(sourceFile, declaration));
});
return;
}
let m2 = line.match(/^\s*#includeAll\(([^\)]*)\)\:(.*)$/);
if (m2) {
let moduleId = m2[1];
let sourceFile = getSourceFile(moduleId);
let typeNames = m2[2].split(/,/);
let typesToExclude: {[typeName:string]:boolean;} = {};
typeNames.forEach((typeName) => {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
typesToExclude[typeName] = true;
});
getAllTopLevelDeclarations(sourceFile).forEach((declaration) => {
result.push(getMassagedTopLevelDeclarationText(sourceFile, declaration));
});
return;
}
result.push(line);
});
fs.writeFileSync(path.join(__dirname, './monaco-editor.d.ts'), result.join('\n'));

View file

@ -12,7 +12,7 @@
},
{
"id": "cpp",
"extensions": [ ".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx", ".h", ".mm", ".ino" ],
"extensions": [ ".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx", ".h", ".mm", ".ino", ".inl" ],
"aliases": [ "C++", "Cpp", "cpp"],
"configuration": "./cpp.configuration.json"
}],

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Location, getLocation, createScanner, SyntaxKind} from 'jsonc-parser';
import {Location, getLocation, createScanner, SyntaxKind, ScanError} from 'jsonc-parser';
import {basename} from 'path';
import {BowerJSONContribution} from './bowerJSONContribution';
import {PackageJSONContribution} from './packageJSONContribution';
@ -122,10 +122,7 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
if (location.isAtPropertyKey) {
let addValue = !location.previousNode || !location.previousNode.columnOffset;
let scanner = createScanner(document.getText(), true);
scanner.setPosition(offset);
scanner.scan();
let isLast = scanner.getToken() === SyntaxKind.CloseBraceToken || scanner.getToken() === SyntaxKind.EOF;
let isLast = this.isLast(document, position);
collectPromise = this.jsonContribution.collectPropertySuggestions(fileName, location, currentWord, addValue, isLast, collector);
} else {
if (location.path.length === 0) {
@ -153,4 +150,14 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
}
return text.substring(i+1, position.character);
}
private isLast(document: TextDocument, position: Position):boolean {
let scanner = createScanner(document.getText(), true);
scanner.setPosition(document.offsetAt(position));
let nextToken = scanner.scan();
if (nextToken === SyntaxKind.StringLiteral && scanner.getTokenError() === ScanError.UnexpectedEndOfString) {
nextToken= scanner.scan();
}
return nextToken === SyntaxKind.CloseBraceToken || nextToken === SyntaxKind.EOF;
}
}

View file

@ -210,6 +210,12 @@ function updateConfiguration() {
function validateTextDocument(textDocument: ITextDocument): void {
if (textDocument.getText().length === 0) {
// ignore empty documents
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
return;
}
let jsonDocument = getJSONDocument(textDocument);
jsonSchemaService.getSchemaForResource(textDocument.uri, jsonDocument).then(schema => {
if (schema) {

View file

@ -1,6 +1,6 @@
{
"account": "monacobuild",
"container": "debuggers",
"zip": "c2c41f3/node-debug.zip",
"zip": "3c7ed19/node-debug.zip",
"output": ""
}

View file

@ -11,11 +11,16 @@
"contributes": {
"languages": [{
"id": "php",
"extensions": [ ".php", ".phtml", ".ctp" ],
"extensions": [ ".php", ".php4", ".php5", ".phtml", ".ctp" ],
"aliases": [ "PHP", "php" ],
"mimetypes": ["application/x-php"],
"configuration": "./php.configuration.json"
}],
"grammars": [{
"language": "php",
"scopeName": "text.html.php",
"path": "./syntaxes/php.json"
}],
"snippets": [{
"language": "php",
"path": "./snippets/php.json"

View file

@ -8,4 +8,5 @@
["[", "]"],
["(", ")"]
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -12,8 +12,7 @@
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
["\"", "\""]
],
"surroundingPairs": [
["{", "}"],
@ -22,4 +21,4 @@
["\"", "\""],
["'", "'"]
]
}
}

View file

@ -4,7 +4,7 @@
"name": "Microsoft Corp."
},
"homepage": "http://typescriptlang.org/",
"version": "1.8.9",
"version": "1.8.10",
"license": "Apache-2.0",
"description": "TypeScript is a language for application scale JavaScript development",
"keywords": [
@ -19,7 +19,7 @@
},
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/TypeScript.git"
"url": "git+https://github.com/Microsoft/TypeScript.git"
},
"main": "./lib/typescript.js",
"typings": "./lib/typescript.d.ts",
@ -58,11 +58,12 @@
"os": false,
"path": false
},
"gitHead": "9ef75534e0fd5f92bef86b520dff768c11a2df4d",
"_id": "typescript@1.8.9",
"_shasum": "b3b3a74059fd31cbd3ecad95d62465939e7ed5fa",
"gitHead": "794c57478ec2a44ee15fb3e245a4c5d2d1612375",
"_id": "typescript@1.8.10",
"_shasum": "b475d6e0dff0bf50f296e5ca6ef9fbb5c7320f1e",
"_from": "typescript@latest",
"_npmVersion": "2.0.0",
"_npmVersion": "2.14.2",
"_nodeVersion": "5.9.0",
"_npmUser": {
"name": "typescript",
"email": "typescript@microsoft.com"
@ -74,13 +75,14 @@
}
],
"dist": {
"shasum": "b3b3a74059fd31cbd3ecad95d62465939e7ed5fa",
"tarball": "http://registry.npmjs.org/typescript/-/typescript-1.8.9.tgz"
"shasum": "b475d6e0dff0bf50f296e5ca6ef9fbb5c7320f1e",
"tarball": "https://registry.npmjs.org/typescript/-/typescript-1.8.10.tgz"
},
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/typescript-1.8.9.tgz_1458169371557_0.7292261146940291"
"tmp": "tmp/typescript-1.8.10.tgz_1460493736776_0.9304528103675693"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/typescript/-/typescript-1.8.9.tgz"
"_resolved": "https://registry.npmjs.org/typescript/-/typescript-1.8.10.tgz",
"readme": "ERROR: No README data found!"
}

View file

@ -383,7 +383,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
}
}
if (this.trace !== Trace.Off) {
this.output.append(`TypeScript Service: tried to cancel request with sequence number ${seq}. But request got already delivered.`);
this.output.append(`TypeScript Service: tried to cancel request with sequence number ${seq}. But request got already delivered.\n`);
}
return false;
}

View file

@ -40,23 +40,6 @@ suite('commands namespace tests', () => {
}, done);
});
test('api-command: workbench.html.preview', function () {
let registration = workspace.registerTextDocumentContentProvider('speciale', {
provideTextDocumentContent(uri) {
return `content of URI <b>${uri.toString()}</b>`;
}
});
let virtualDocumentUri = Uri.parse('speciale://authority/path');
return commands.executeCommand('vscode.previewHtml', virtualDocumentUri).then(success => {
assert.ok(success);
registration.dispose();
});
});
test('editorCommand with extra args', function () {
let args: IArguments;
@ -77,4 +60,46 @@ suite('commands namespace tests', () => {
});
});
test('api-command: vscode.previewHtm', function () {
let registration = workspace.registerTextDocumentContentProvider('speciale', {
provideTextDocumentContent(uri) {
return `content of URI <b>${uri.toString()}</b>`;
}
});
let virtualDocumentUri = Uri.parse('speciale://authority/path');
return commands.executeCommand('vscode.previewHtml', virtualDocumentUri).then(success => {
assert.ok(success);
registration.dispose();
});
});
test('api-command: vscode.diff', function () {
let registration = workspace.registerTextDocumentContentProvider('sc', {
provideTextDocumentContent(uri) {
return `content of URI <b>${uri.toString()}</b>#${Math.random()}`;
}
});
let a = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b'), 'DIFF').then(value => {
assert.ok(value === void 0);
registration.dispose();
});
let b = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b')).then(value => {
assert.ok(value === void 0);
registration.dispose();
});
let c = commands.executeCommand('vscode.diff').then(() => assert.ok(false), () => assert.ok(true));
let d = commands.executeCommand('vscode.diff', 1, 2, 3).then(() => assert.ok(false), () => assert.ok(true));
return Promise.all([a, b, c]);
});
});

View file

@ -8,7 +8,7 @@
import * as assert from 'assert';
import * as fs from 'fs';
import * as os from 'os';
import {workspace, window, Position} from 'vscode';
import {workspace, window, Position, Range} from 'vscode';
import {createRandomFile, deleteFile, cleanUp} from './utils';
import {join} from 'path';
@ -38,4 +38,27 @@ suite("editor tests", () => {
});
});
});
test('issue #6281: Edits fail to validate ranges correctly before applying', () => {
return createRandomFile('Hello world!').then(file => {
return workspace.openTextDocument(file).then(doc => {
return window.showTextDocument(doc).then((editor) => {
return editor.edit((builder) => {
builder.replace(new Range(0, 0, Number.MAX_VALUE, Number.MAX_VALUE), 'new');
}).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'new');
assert.ok(doc.isDirty);
return doc.save().then(saved => {
assert.ok(saved);
assert.ok(!doc.isDirty);
return deleteFile(file);
});
});
});
});
});
});
});

View file

@ -79,6 +79,55 @@ suite('languages namespace tests', () => {
collection.dispose();
});
test('diagnostics collection, set with dupliclated tuples', function () {
let collection = languages.createDiagnosticCollection('test');
let uri = Uri.parse('sc:hightower');
collection.set([
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]],
[Uri.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]],
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-2')]],
]);
let array = collection.get(uri);
assert.equal(array.length, 2);
let [first, second] = array;
assert.equal(first.message, 'message-1');
assert.equal(second.message, 'message-2');
// clear
collection.delete(uri);
assert.ok(!collection.has(uri));
// bad tuple clears 1/2
collection.set([
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]],
[Uri.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]],
[uri, undefined]
]);
assert.ok(!collection.has(uri));
// clear
collection.delete(uri);
assert.ok(!collection.has(uri));
// bad tuple clears 2/2
collection.set([
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]],
[Uri.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]],
[uri, undefined],
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-2')]],
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-3')]],
]);
array = collection.get(uri);
assert.equal(array.length, 2);
[first, second] = array;
assert.equal(first.message, 'message-2');
assert.equal(second.message, 'message-3');
collection.dispose();
});
test('diagnostics & CodeActionProvider', function (done) {
class D2 extends Diagnostic {

View file

@ -294,6 +294,23 @@ suite('workspace-namespace', () => {
});
});
test('registerTextDocumentContentProvider, empty doc', function () {
let registration = workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return '';
}
});
const uri = Uri.parse('foo:doc/empty');
return workspace.openTextDocument(uri).then(doc => {
assert.equal(doc.getText(), '');
assert.equal(doc.uri.toString(), uri.toString());
registration.dispose();
});
});
test('registerTextDocumentContentProvider, change event', function () {
let callCount = 0;

View file

@ -25,10 +25,12 @@ var sourcemaps = require('gulp-sourcemaps');
var _ = require('underscore');
var assign = require('object-assign');
var quiet = !!process.env['VSCODE_BUILD_QUIET'];
var declaration = !!process.env['VSCODE_BUILD_DECLARATION_FILES'];
var rootDir = path.join(__dirname, 'src');
var tsOptions = {
target: 'ES5',
declaration: declaration,
module: 'amd',
verbose: !quiet,
preserveConstEnums: true,

16
npm-shrinkwrap.json generated
View file

@ -340,6 +340,11 @@
"from": "preserve@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz"
},
"pty.js": {
"version": "0.3.0",
"from": "https://github.com/Tyriar/pty.js/tarball/fffbf86eb9e8051b5b2be4ba9c7b07faa018ce8d",
"resolved": "https://github.com/Tyriar/pty.js/tarball/fffbf86eb9e8051b5b2be4ba9c7b07faa018ce8d"
},
"randomatic": {
"version": "1.1.5",
"from": "randomatic@>=1.1.3 <2.0.0",
@ -390,15 +395,20 @@
"from": "string_decoder@>=0.10.0 <0.11.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
},
"term.js": {
"version": "0.0.7",
"from": "https://github.com/jeremyramin/term.js/tarball/master",
"resolved": "https://github.com/jeremyramin/term.js/tarball/master"
},
"typechecker": {
"version": "2.0.8",
"from": "typechecker@>=2.0.1 <2.1.0",
"resolved": "https://registry.npmjs.org/typechecker/-/typechecker-2.0.8.tgz"
},
"vscode-debugprotocol": {
"version": "1.8.0-pre.3",
"from": "vscode-debugprotocol@1.8.0-pre.3",
"resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.8.0-pre.3.tgz"
"version": "1.8.0",
"from": "vscode-debugprotocol@1.8.0",
"resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.8.0.tgz"
},
"vscode-textmate": {
"version": "1.0.11",

View file

@ -1,5 +1,5 @@
{
"name": "Code",
"name": "code-oss-dev",
"version": "1.1.0",
"electronVersion": "0.37.6",
"author": {
@ -27,9 +27,11 @@
"iconv-lite": "0.4.13",
"minimist": "^1.2.0",
"native-keymap": "0.1.2",
"pty.js": "https://github.com/Tyriar/pty.js/tarball/prebuilt",
"sax": "1.1.2",
"semver": "4.3.6",
"vscode-debugprotocol": "1.8.0-pre.3",
"term.js": "https://github.com/jeremyramin/term.js/tarball/master",
"vscode-debugprotocol": "1.8.0",
"vscode-textmate": "1.0.11",
"winreg": "1.2.0",
"yauzl": "2.3.1"

View file

@ -3,8 +3,6 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
ARGS=$@
# If root, ensure that --user-data-dir is specified
if [ "$(id -u)" = "0" ]; then
while test $# -gt 0
@ -35,5 +33,5 @@ fi
ELECTRON="$VSCODE_PATH/@@NAME@@"
CLI="$VSCODE_PATH/resources/app/out/cli.js"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" $ARGS
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $?

View file

@ -12,6 +12,11 @@ ln -s /usr/share/@@NAME@@/bin/@@NAME@@ /usr/bin/@@NAME@@
# developers would prefer a terminal editor as the default.
update-alternatives --install /usr/bin/editor editor /usr/bin/@@NAME@@ 0
# Install the desktop entry
if hash desktop-file-install 2>/dev/null; then
desktop-file-install /usr/share/applications/@@NAME@@.desktop
fi
if [ "@@NAME@@" != "code-oss" ]; then
# Remove the legacy bin command if this is the stable build
if [ "@@NAME@@" = "code" ]; then

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
#
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
rm -f /usr/bin/@@NAME@@

View file

@ -8,7 +8,7 @@ Packager: Visual Studio Code Team <vscode-linux@microsoft.com>
License: MIT
URL: https://code.visualstudio.com/
Icon: @@NAME@@.xpm
Requires: git
Requires: git, glibc >= 2.15
AutoReq: 0
%description
@ -28,9 +28,9 @@ if [ "@@NAME@@" = "code" ]; then
rm -f /usr/local/bin/code
fi
# Symlink bin command to /usr/bin2
rm -f /usr/bin/@@NAME@@
ln -s /usr/share/@@NAME@@/bin/@@NAME@@ /usr/bin/@@NAME@@
# Symlink bin command to /usr/bin
sudo rm -f /usr/bin/@@NAME@@
sudo ln -s /usr/share/@@NAME@@/bin/@@NAME@@ /usr/bin/@@NAME@@
# Register yum repository
# TODO: #229: Enable once the yum repository is signed
@ -42,6 +42,9 @@ ln -s /usr/share/@@NAME@@/bin/@@NAME@@ /usr/bin/@@NAME@@
# fi
#fi
%postun
sudo rm -f /usr/bin/@@NAME@@
%files
%defattr(-,root,root)

View file

@ -14,7 +14,7 @@ function code() {
test -d node_modules || ./scripts/npm.sh install
# Get electron
./node_modules/.bin/gulp electron
test -d .build/electron || ./node_modules/.bin/gulp electron
# Build
test -d out || ./node_modules/.bin/gulp compile
@ -31,7 +31,7 @@ function code() {
VSCODE_DEV=1 \
ELECTRON_ENABLE_LOGGING=1 \
ELECTRON_ENABLE_STACK_DUMPING=1 \
"$ELECTRON" "$CLI" . $@
"$ELECTRON" "$CLI" . "$@"
}
code "$@"

View file

@ -9,7 +9,7 @@ pushd %~dp0\..
if not exist node_modules call .\scripts\npm.bat install
:: Get electron
node .\node_modules\gulp\bin\gulp.js electron
if not exist .build\electron node .\node_modules\gulp\bin\gulp.js electron
:: Build
if not exist out node .\node_modules\gulp\bin\gulp.js compile

View file

@ -14,7 +14,7 @@ function code() {
test -d node_modules || ./scripts/npm.sh install
# Get electron
./node_modules/.bin/gulp electron
test -d .build/electron || ./node_modules/.bin/gulp electron
# Build
test -d out || ./node_modules/.bin/gulp compile

View file

@ -9,6 +9,8 @@ global.vscodeStart = Date.now();
var app = require('electron').app;
var fs = require('fs');
var path = require('path');
var paths = require('./paths');
var pkg = require('../package.json');
function stripComments(content) {
var regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
@ -50,11 +52,11 @@ function getNLSConfiguration() {
if (!locale) {
var userData = app.getPath('userData');
localeConfig = path.join(userData, 'User', 'locale.json');
var localeConfig = path.join(userData, 'User', 'locale.json');
if (fs.existsSync(localeConfig)) {
try {
var content = stripComments(fs.readFileSync(localeConfig, 'utf8'));
value = JSON.parse(content).locale;
var value = JSON.parse(content).locale;
if (value && typeof value === 'string') {
locale = value;
}
@ -63,7 +65,8 @@ function getNLSConfiguration() {
}
}
locale = locale || app.getLocale();
var appLocale = app.getLocale();
locale = locale || appLocale;
// Language tags are case insensitve however an amd loader is case sensitive
// To make this work on case preserving & insensitive FS we do the following:
// the language bundles have lower case language tags and we always lower case
@ -76,23 +79,38 @@ function getNLSConfiguration() {
if (process.env['VSCODE_DEV']) {
return { locale: locale, availableLanguages: {} };
}
// We have a built version so we have extracted nls file. Try to find
// the right file to use.
while (locale) {
var candidate = path.join(__dirname, 'vs', 'code', 'electron-main', 'main.nls.') + locale + '.js';
if (fs.existsSync(candidate)) {
return { locale: initialLocale, availableLanguages: { '*': locale } };
} else {
var index = locale.lastIndexOf('-');
if (index > 0) {
locale = locale.substring(0, index);
} else {
locale = null;
}
}
// Check if we have an English locale. If so fall to default since that is our
// English translation (we don't ship *.nls.en.json files)
if (locale && (locale == 'en' || locale.startsWith('en-'))) {
return { locale: locale, availableLanguages: {} };
}
return { locale: initialLocale, availableLanguages: {} };
function resolveLocale(locale) {
while (locale) {
var candidate = path.join(__dirname, 'vs', 'code', 'electron-main', 'main.nls.') + locale + '.js';
if (fs.existsSync(candidate)) {
return { locale: initialLocale, availableLanguages: { '*': locale } };
} else {
var index = locale.lastIndexOf('-');
if (index > 0) {
locale = locale.substring(0, index);
} else {
locale = null;
}
}
}
return null;
}
var resolvedLocale = resolveLocale(locale);
if (!resolvedLocale && appLocale && appLocale !== locale) {
resolvedLocale = resolveLocale(appLocale);
}
return resolvedLocale ? resolvedLocale : { locale: initialLocale, availableLanguages: {} };
}
// Update cwd based on environment and platform
@ -107,19 +125,9 @@ try {
console.error(err);
}
// Set path according to being built or not
if (process.env['VSCODE_DEV']) {
var appData = app.getPath('appData');
app.setPath('userData', path.join(appData, 'Code-Development'));
}
// Use custom user data dir if specified, required to run as root on Linux
var args = process.argv;
args.forEach(function (arg) {
if (arg.indexOf('--user-data-dir=') === 0) {
app.setPath('userData', arg.split('=')[1]);
}
});
// Set userData path before app 'ready' event
var userData = paths.getUserDataPath(process.platform, pkg.name, process.argv);
app.setPath('userData', userData);
// Mac: when someone drops a file to the not-yet running VSCode, the open-file event fires even before
// the app-ready event. We listen very early for open-file and remember this upon startup as path to open.

32
src/paths.js Normal file
View file

@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var minimist = require('minimist');
var path = require('path');
var os = require('os');
function getAppDataPath(platform) {
switch (platform) {
case 'win32': return process.env['APPDATA'];
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support');
case 'linux': return process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config');
default: throw new Error('Platform not supported');
}
}
function getUserDataPath(platform, appName, args) {
var argv = minimist(args, { string: ['user-data-dir'] });
var userDataDir = argv['user-data-dir'];
var appData = getAppDataPath(platform);
if (userDataDir) {
return userDataDir;
}
return path.join(appData, appName);
}
exports.getAppDataPath = getAppDataPath;
exports.getUserDataPath = getUserDataPath;

23
src/typings/pty.js.d.ts vendored Normal file
View file

@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'pty.js' {
export function fork(file: string, args: string[], options: any): Terminal;
export function spawn(file: string, args: string[], options: any): Terminal;
export function createTerminal(file: string, args: string[], options: any): Terminal;
export interface Terminal {
/**
* The title of the active process.
*/
process: string;
on(event: string, callback: (data: any) => void): void;
resize(columns: number, rows: number): void;
write(data: string): void;
}
}

17
src/typings/term.js.d.ts vendored Normal file
View file

@ -0,0 +1,17 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'term.js' {
function init(options: any): TermJsTerminal;
// There seems to be no way to export this so it can be referenced outside of this file when a
// module is a function.
interface TermJsTerminal {
on(event: string, callback: (data: any) => void): void;
resize(columns: number, rows: number): void;
}
export = init;
}

View file

@ -6,46 +6,42 @@
import types = require('vs/base/common/types');
import * as Platform from 'vs/base/common/platform';
import Event, {Emitter} from 'vs/base/common/event';
import {IDisposable} from 'vs/base/common/lifecycle';
interface ISafeWindow {
Worker: any;
class ZoomManager {
public static INSTANCE = new ZoomManager();
private _zoomLevel: number = 0;
private _onDidChangeZoomLevel: Emitter<number> = new Emitter<number>();
public onDidChangeZoomLevel:Event<number> = this._onDidChangeZoomLevel.event;
public getZoomLevel(): number {
return this._zoomLevel;
}
public setZoomLevel(zoomLevel:number): void {
if (this._zoomLevel === zoomLevel) {
return;
}
this._zoomLevel = zoomLevel;
this._onDidChangeZoomLevel.fire(this._zoomLevel);
}
}
interface ISafeDocument {
URL: string;
createElement(tagName: 'div'): HTMLDivElement;
createElement(tagName: string): HTMLElement;
export function getZoomLevel(): number {
return ZoomManager.INSTANCE.getZoomLevel();
}
export function setZoomLevel(zoomLevel:number): void {
ZoomManager.INSTANCE.setZoomLevel(zoomLevel);
}
export function onDidChangeZoomLevel(callback:(zoomLevel:number)=>void): IDisposable {
return ZoomManager.INSTANCE.onDidChangeZoomLevel(callback);
}
interface INavigator {
userAgent: string;
}
interface IGlobalScope {
navigator: INavigator;
document: ISafeDocument;
history: {
pushState: any
};
}
const globals = <IGlobalScope><any>(typeof self === 'object' ? self : global);
// MAC:
// chrome: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.100 Safari/535.2"
// safari: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22"
//
// WINDOWS:
// chrome: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.102 Safari/535.2"
// IE: "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; MS-RTC LM 8; InfoPath.3; Zune 4.7)"
// Opera: "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.52"
// FF: "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0"
// LINUX:
// chrome: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36"
// firefox: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0"
const userAgent = globals.navigator ? globals.navigator.userAgent : '';
const userAgent = navigator.userAgent;
// DOCUMENTED FOR FUTURE REFERENCE:
// When running IE11 in IE10 document mode, the code below will identify the browser as being IE10,
@ -68,22 +64,6 @@ export const canUseTranslate3d = !isIE9 && !isFirefox;
export const enableEmptySelectionClipboard = isWebKit;
let _disablePushState = false;
/**
* Returns if the browser supports the history.pushState function or not.
*/
export function canPushState() {
return (!_disablePushState && globals.history && globals.history.pushState);
}
/**
* Helpful when we detect that pushing state does not work for some reason (e.g. FF prevents pushState for security reasons in some cases)
*/
export function disablePushState() {
_disablePushState = true;
}
/**
* Returns if the browser supports CSS 3 animations.
*/
@ -92,12 +72,8 @@ export function hasCSSAnimationSupport() {
return this._hasCSSAnimationSupport;
}
if (!globals.document) {
return false;
}
let supported = false;
let element = globals.document.createElement('div');
let element = document.createElement('div');
let properties = ['animationName', 'webkitAnimationName', 'msAnimationName', 'MozAnimationName', 'OAnimationName'];
for (let i = 0; i < properties.length; i++) {
let property = properties[i];
@ -116,10 +92,6 @@ export function hasCSSAnimationSupport() {
return this._hasCSSAnimationSupport;
}
export function isInWebWorker(): boolean {
return !globals.document && typeof ((<any>globals).importScripts) !== 'undefined';
}
export function supportsExecCommand(command: string): boolean {
return (
(isIE11orEarlier || Platform.isNative)

View file

@ -1,66 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {isInWebWorker} from 'vs/base/browser/browser';
export interface IBrowserServiceData {
document: Document;
window: Window;
isHTMLElement: (o: any) => boolean;
}
export interface IBrowserService extends IBrowserServiceData {
/**
* Mock the DOM with dummy objects
*/
mock(source: IBrowserServiceData): void;
/**
* Restore the normal DOM
*/
restore(): void;
}
export function regularIsHTMLElement(o: any): boolean {
if (typeof HTMLElement === 'object') {
return o instanceof HTMLElement;
}
return o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string';
}
class BrowserService implements IBrowserService {
public document: Document;
public window: Window;
public isHTMLElement: (o: any) => boolean;
constructor() {
this.restore();
}
public mock(source: IBrowserServiceData): void {
this.document = source.document;
this.window = source.window;
this.isHTMLElement = source.isHTMLElement;
}
public restore(): void {
this.isHTMLElement = regularIsHTMLElement;
if (isInWebWorker()) {
this.document = null;
this.window = null;
} else {
this.document = window.document;
this.window = window;
}
}
}
const browserService = new BrowserService();
export function getService(): IBrowserService {
return browserService;
}

View file

@ -11,7 +11,6 @@ import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import strings = require('vs/base/common/strings');
import assert = require('vs/base/common/assert');
import DOM = require('vs/base/browser/dom');
import BrowserService = require('vs/base/browser/browserService');
/**
* Welcome to the monaco builder. The recommended way to use it is:
@ -52,7 +51,7 @@ export interface QuickBuilder {
export function withElementById(id: string, offdom?: boolean): Builder {
assert.ok(types.isString(id), 'Expected String as parameter');
let element = BrowserService.getService().document.getElementById(id);
let element = document.getElementById(id);
if (element) {
return new Builder(element, offdom);
}
@ -136,7 +135,6 @@ export class Builder implements IDisposable {
private createdElements: HTMLElement[];
private toUnbind: { [type: string]: IDisposable[]; };
private captureToUnbind: { [type: string]: IDisposable[]; };
private browserService: BrowserService.IBrowserService;
constructor(element?: HTMLElement, offdom?: boolean) {
this.offdom = offdom;
@ -148,7 +146,6 @@ export class Builder implements IDisposable {
this.toUnbind = {};
this.captureToUnbind = {};
this.browserService = BrowserService.getService();
}
/**
@ -476,7 +473,7 @@ export class Builder implements IDisposable {
private doElement(name: string, attributesOrFn?: any, fn?: (builder: Builder) => void): Builder {
// Create Element
let element = this.browserService.document.createElement(name);
let element = document.createElement(name);
this.currentElement = element;
// Off-DOM: Remember in array of created elements
@ -521,7 +518,7 @@ export class Builder implements IDisposable {
* Returns true if the current element of this builder is the active element.
*/
public hasFocus(): boolean {
let activeElement: Element = this.browserService.document.activeElement;
let activeElement: Element = document.activeElement;
return (activeElement === this.currentElement);
}
@ -1535,7 +1532,7 @@ export class Builder implements IDisposable {
else {
// if there are elements inside this node, append the string as a new text node
// to avoid wiping out the innerHTML and replacing it with only text content
this.currentElement.appendChild(this.browserService.document.createTextNode(text));
this.currentElement.appendChild(document.createTextNode(text));
}
} else {
this.currentElement.textContent = text;
@ -1848,24 +1845,24 @@ export class Builder implements IDisposable {
public getClientArea(): Dimension {
// 0.) Try with DOM getDomNodePosition
if (this.currentElement !== this.browserService.document.body) {
if (this.currentElement !== document.body) {
let dimensions = DOM.getDomNodePosition(this.currentElement);
return new Dimension(dimensions.width, dimensions.height);
}
// 1.) Try innerWidth / innerHeight
if (this.browserService.window.innerWidth && this.browserService.window.innerHeight) {
return new Dimension(this.browserService.window.innerWidth, this.browserService.window.innerHeight);
if (window.innerWidth && window.innerHeight) {
return new Dimension(window.innerWidth, window.innerHeight);
}
// 2.) Try with document.body.clientWidth / document.body.clientHeigh
if (this.browserService.document.body && this.browserService.document.body.clientWidth && this.browserService.document.body.clientWidth) {
return new Dimension(this.browserService.document.body.clientWidth, this.browserService.document.body.clientHeight);
if (document.body && document.body.clientWidth && document.body.clientWidth) {
return new Dimension(document.body.clientWidth, document.body.clientHeight);
}
// 3.) Try with document.documentElement.clientWidth / document.documentElement.clientHeight
if (this.browserService.document.documentElement && this.browserService.document.documentElement.clientWidth && this.browserService.document.documentElement.clientHeight) {
return new Dimension(this.browserService.document.documentElement.clientWidth, this.browserService.document.documentElement.clientHeight);
if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientHeight) {
return new Dimension(document.documentElement.clientWidth, document.documentElement.clientHeight);
}
throw new Error('Unable to figure out browser width and height');
@ -2154,7 +2151,7 @@ export let $: QuickBuilder = function(arg?: any): Builder {
// Use the argument as HTML code
if (arg[0] === '<') {
let element: Node;
let container = BrowserService.getService().document.createElement('div');
let container = document.createElement('div');
container.innerHTML = strings.format.apply(strings, arguments);
if (container.children.length === 0) {

View file

@ -10,7 +10,6 @@ import {EventEmitter} from 'vs/base/common/eventEmitter';
import {Disposable, IDisposable} from 'vs/base/common/lifecycle';
import {isObject} from 'vs/base/common/types';
import {isChrome, isWebKit} from 'vs/base/browser/browser';
import {getService} from 'vs/base/browser/browserService';
import {IKeyboardEvent, StandardKeyboardEvent} from 'vs/base/browser/keyboardEvent';
import {IMouseEvent, StandardMouseEvent} from 'vs/base/browser/mouseEvent';
@ -764,7 +763,10 @@ export function removeCSSRulesWithPrefix(ruleName: string, style = sharedStyle):
}
export function isHTMLElement(o: any): o is HTMLElement {
return getService().isHTMLElement(o);
if (typeof HTMLElement === 'object') {
return o instanceof HTMLElement;
}
return o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string';
}
export const EventType = {

View file

@ -7,7 +7,6 @@
import {TimeoutTimer} from 'vs/base/common/async';
import {EventEmitter} from 'vs/base/common/eventEmitter';
import {Disposable, IDisposable} from 'vs/base/common/lifecycle';
import {getService} from 'vs/base/browser/browserService';
import * as dom from 'vs/base/browser/dom';
export enum UserStatus {
@ -34,8 +33,8 @@ export class IdleMonitor extends Disposable {
this._idleTime = idleTime;
this._eventEmitter = this._register(new EventEmitter());
this._register(dom.addDisposableListener(getService().document, 'mousemove', () => this._onUserActive()));
this._register(dom.addDisposableListener(getService().document, 'keydown', () => this._onUserActive()));
this._register(dom.addDisposableListener(document, 'mousemove', () => this._onUserActive()));
this._register(dom.addDisposableListener(document, 'keydown', () => this._onUserActive()));
this._onUserActive();
}

View file

@ -61,11 +61,12 @@ export class FileLabel {
let parent = paths.dirname(this.path);
if (parent && parent !== '.') {
let pathLabel = getPathLabel(parent, this.basepath);
htmlContent.push('<span class="file-path" title="' + pathLabel + '">');
htmlContent.push('<span class="file-path">');
htmlContent.push(pathLabel);
htmlContent.push('</span>');
}
this.domNode.title = this.path;
this.domNode.innerHTML = htmlContent.join('');
}
}

View file

@ -9,7 +9,6 @@ import 'vs/css!./inputBox';
import nls = require('vs/nls');
import * as Bal from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
import * as browser from 'vs/base/browser/browserService';
import {IHTMLContentElement} from 'vs/base/common/htmlContent';
import {renderHtml} from 'vs/base/browser/htmlContentRenderer';
import aria = require('vs/base/browser/ui/aria/aria');
@ -204,7 +203,7 @@ export class InputBox extends Widget {
}
public hasFocus(): boolean {
return browser.getService().document.activeElement === this.input;
return document.activeElement === this.input;
}
public select(range: IRange = null): void {

View file

@ -8,6 +8,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Gesture } from 'vs/base/browser/touch';
import * as DOM from 'vs/base/browser/dom';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import { RangeMap, IRange } from './rangeMap';
import { IDelegate, IRenderer } from './list';
import { RowCache, IRow } from './rowCache';
@ -87,9 +88,9 @@ export class ListView<T> implements IDisposable {
this.gesture = new Gesture(this.rowsContainer);
this.scrollableElement = new ScrollableElement(this.rowsContainer, {
forbidTranslate3dUse: true,
horizontal: 'hidden',
vertical: 'auto',
canUseTranslate3d: false,
horizontal: ScrollbarVisibility.Hidden,
vertical: ScrollbarVisibility.Auto,
useShadows: false,
saveLastScrollTimeOnClassName: 'monaco-list-row'
});

View file

@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as Browser from 'vs/base/browser/browser';
import * as Platform from 'vs/base/common/platform';
import * as DomUtils from 'vs/base/browser/dom';
import {IMouseEvent, StandardMouseEvent, StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
@ -13,8 +12,9 @@ import {Widget} from 'vs/base/browser/ui/widget';
import {FastDomNode, createFastDomNode} from 'vs/base/browser/styleMutator';
import {ScrollbarState} from 'vs/base/browser/ui/scrollbar/scrollbarState';
import {ScrollbarArrow, ScrollbarArrowOptions} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
import {Visibility, ScrollbarVisibilityController} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
import {ScrollbarVisibilityController} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
import {Scrollable} from 'vs/base/common/scrollable';
import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
/**
* The orthogonal distance to the slider at which dragging "resets". This implements "snapping"
@ -34,18 +34,18 @@ export interface ScrollbarHost {
}
export interface AbstractScrollbarOptions {
forbidTranslate3dUse: boolean;
canUseTranslate3d: boolean;
lazyRender:boolean;
host: ScrollbarHost;
scrollbarState: ScrollbarState;
visibility: Visibility;
visibility: ScrollbarVisibility;
extraScrollbarClassName: string;
scrollable: Scrollable;
}
export abstract class AbstractScrollbar extends Widget {
protected _forbidTranslate3dUse: boolean;
protected _canUseTranslate3d: boolean;
protected _host: ScrollbarHost;
protected _scrollable: Scrollable;
private _lazyRender: boolean;
@ -60,7 +60,7 @@ export abstract class AbstractScrollbar extends Widget {
constructor(opts:AbstractScrollbarOptions) {
super();
this._forbidTranslate3dUse = opts.forbidTranslate3dUse;
this._canUseTranslate3d = opts.canUseTranslate3d;
this._lazyRender = opts.lazyRender;
this._host = opts.host;
this._scrollable = opts.scrollable;
@ -69,10 +69,6 @@ export abstract class AbstractScrollbar extends Widget {
this._mouseMoveMonitor = this._register(new GlobalMouseMoveMonitor<IStandardMouseMoveEventData>());
this._shouldRender = true;
this.domNode = createFastDomNode(document.createElement('div'));
if (!this._forbidTranslate3dUse && Browser.canUseTranslate3d) {
// Put the scrollbar in its own layer
this.domNode.setTransform('translate3d(0px, 0px, 0px)');
}
this._visibilityController.setDomNode(this.domNode);
this.domNode.setPosition('absolute');
@ -110,6 +106,11 @@ export abstract class AbstractScrollbar extends Widget {
// ----------------- Update state
public setCanUseTranslate3d(canUseTranslate3d: boolean): boolean {
this._canUseTranslate3d = canUseTranslate3d;
return true;
}
protected _onElementSize(visibleSize: number): boolean {
if (this._scrollbarState.setVisibleSize(visibleSize)) {
this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
@ -159,6 +160,13 @@ export abstract class AbstractScrollbar extends Widget {
}
this._shouldRender = false;
if (this._canUseTranslate3d) {
// Put the scrollbar in its own layer
this.domNode.setTransform('translate3d(0px, 0px, 0px)');
} else {
this.domNode.setTransform('');
}
this._renderDomNode(this._scrollbarState.getRectangleLargeSize(), this._scrollbarState.getRectangleSmallSize());
this._updateSlider(this._scrollbarState.getSliderSize(), this._scrollbarState.getArrowSize() + this._scrollbarState.getSliderPosition());
}

View file

@ -4,27 +4,25 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as Browser from 'vs/base/browser/browser';
import {AbstractScrollbar, ScrollbarHost, IMouseMoveEventData} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
import {IMouseEvent, StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
import {IDomNodePosition} from 'vs/base/browser/dom';
import {ScrollableElementResolvedOptions} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import {ScrollbarVisibility, ScrollableElementResolvedOptions} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import {Scrollable, ScrollEvent} from 'vs/base/common/scrollable';
import {ScrollbarState} from 'vs/base/browser/ui/scrollbar/scrollbarState';
import {ARROW_IMG_SIZE} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
import {Visibility} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
export class HorizontalScrollbar extends AbstractScrollbar {
constructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {
super({
forbidTranslate3dUse: options.forbidTranslate3dUse,
canUseTranslate3d: options.canUseTranslate3d,
lazyRender: options.lazyRender,
host: host,
scrollbarState: new ScrollbarState(
(options.horizontalHasArrows ? options.arrowSize : 0),
(options.horizontal === Visibility.Hidden ? 0 : options.horizontalScrollbarSize),
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize)
(options.horizontal === ScrollbarVisibility.Hidden ? 0 : options.horizontalScrollbarSize),
(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize)
),
visibility: options.horizontal,
extraScrollbarClassName: 'horizontal',
@ -63,9 +61,11 @@ export class HorizontalScrollbar extends AbstractScrollbar {
protected _updateSlider(sliderSize: number, sliderPosition: number): void {
this.slider.setWidth(sliderSize);
if (!this._forbidTranslate3dUse && Browser.canUseTranslate3d) {
if (this._canUseTranslate3d) {
this.slider.setTransform('translate3d(' + sliderPosition + 'px, 0px, 0px)');
this.slider.setLeft(0);
} else {
this.slider.setTransform('');
this.slider.setLeft(sliderPosition);
}
}

View file

@ -6,13 +6,13 @@
import 'vs/css!./media/scrollbars';
import * as Browser from 'vs/base/browser/browser';
import * as DomUtils from 'vs/base/browser/dom';
import * as Platform from 'vs/base/common/platform';
import {StandardMouseWheelEvent, IMouseEvent} from 'vs/base/browser/mouseEvent';
import {HorizontalScrollbar} from 'vs/base/browser/ui/scrollbar/horizontalScrollbar';
import {VerticalScrollbar} from 'vs/base/browser/ui/scrollbar/verticalScrollbar';
import {ScrollableElementCreationOptions, ScrollableElementResolvedOptions} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import {visibilityFromString} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
import {ScrollbarVisibility, ScrollableElementCreationOptions, ScrollableElementChangeOptions, ScrollableElementResolvedOptions} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {Scrollable, ScrollEvent, INewScrollState} from 'vs/base/common/scrollable';
import {Widget} from 'vs/base/browser/ui/widget';
@ -181,12 +181,18 @@ export class ScrollableElement extends Widget {
* Really this is Editor.IEditorScrollbarOptions, but base shouldn't
* depend on Editor.
*/
public updateOptions(newOptions: ScrollableElementCreationOptions): void {
// only support handleMouseWheel changes for now
public updateOptions(newOptions: ScrollableElementChangeOptions): void {
let massagedOptions = resolveOptions(newOptions);
this._options.handleMouseWheel = massagedOptions.handleMouseWheel;
this._options.mouseWheelScrollSensitivity = massagedOptions.mouseWheelScrollSensitivity;
this._setListeningToMouseWheel(this._options.handleMouseWheel);
this._shouldRender = this._horizontalScrollbar.setCanUseTranslate3d(massagedOptions.canUseTranslate3d) || this._shouldRender;
this._shouldRender = this._verticalScrollbar.setCanUseTranslate3d(massagedOptions.canUseTranslate3d) || this._shouldRender;
if (!this._options.lazyRender) {
this._render();
}
}
// -------------------- mouse wheel scrolling --------------------
@ -400,7 +406,7 @@ export class DomScrollableElement extends ScrollableElement {
function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableElementResolvedOptions {
let result: ScrollableElementResolvedOptions = {
forbidTranslate3dUse: (typeof opts.forbidTranslate3dUse !== 'undefined' ? opts.forbidTranslate3dUse : false),
canUseTranslate3d: opts.canUseTranslate3d && Browser.canUseTranslate3d,
lazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),
className: (typeof opts.className !== 'undefined' ? opts.className : ''),
useShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),
@ -411,12 +417,12 @@ function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableEleme
listenOnDomNode: (typeof opts.listenOnDomNode !== 'undefined' ? opts.listenOnDomNode : null),
horizontal: visibilityFromString(typeof opts.horizontal !== 'undefined' ? opts.horizontal : 'auto'),
horizontal: (typeof opts.horizontal !== 'undefined' ? opts.horizontal : ScrollbarVisibility.Auto),
horizontalScrollbarSize: (typeof opts.horizontalScrollbarSize !== 'undefined' ? opts.horizontalScrollbarSize : 10),
horizontalSliderSize: (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : 0),
horizontalHasArrows: (typeof opts.horizontalHasArrows !== 'undefined' ? opts.horizontalHasArrows : false),
vertical: visibilityFromString(typeof opts.vertical !== 'undefined' ? opts.vertical : 'auto'),
vertical: (typeof opts.vertical !== 'undefined' ? opts.vertical : ScrollbarVisibility.Auto),
verticalScrollbarSize: (typeof opts.verticalScrollbarSize !== 'undefined' ? opts.verticalScrollbarSize : 10),
verticalHasArrows: (typeof opts.verticalHasArrows !== 'undefined' ? opts.verticalHasArrows : false),
verticalSliderSize: (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : 0),

View file

@ -4,13 +4,17 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Visibility} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
export enum ScrollbarVisibility {
Auto = 1,
Hidden = 2,
Visible = 3
}
export interface ScrollableElementCreationOptions {
/**
* Prevent the scrollbar rendering from using translate3d. Defaults to false.
* Allow scrollbar rendering to use translate3d.
*/
forbidTranslate3dUse?: boolean;
canUseTranslate3d: boolean;
/**
* The scrollable element should not do any DOM mutations until renderNow() is called.
* Defaults to false.
@ -55,7 +59,7 @@ export interface ScrollableElementCreationOptions {
* Accepted values: 'auto' (on mouse over), 'visible' (always visible), 'hidden' (never visible)
* Defaults to 'auto'.
*/
horizontal?: string;
horizontal?: ScrollbarVisibility;
/**
* Height (in px) of the horizontal scrollbar.
* Defaults to 10.
@ -76,7 +80,7 @@ export interface ScrollableElementCreationOptions {
* Accepted values: 'auto' (on mouse over), 'visible' (always visible), 'hidden' (never visible)
* Defaults to 'auto'.
*/
vertical?: string;
vertical?: ScrollbarVisibility;
/**
* Width (in px) of the vertical scrollbar.
* Defaults to 10.
@ -98,8 +102,14 @@ export interface ScrollableElementCreationOptions {
saveLastScrollTimeOnClassName?: string;
}
export interface ScrollableElementChangeOptions {
canUseTranslate3d: boolean;
handleMouseWheel?: boolean;
mouseWheelScrollSensitivity?: number;
}
export interface ScrollableElementResolvedOptions {
forbidTranslate3dUse: boolean;
canUseTranslate3d: boolean;
lazyRender: boolean;
className: string;
useShadows: boolean;
@ -108,11 +118,11 @@ export interface ScrollableElementResolvedOptions {
mouseWheelScrollSensitivity: number;
arrowSize: number;
listenOnDomNode: HTMLElement;
horizontal: Visibility;
horizontal: ScrollbarVisibility;
horizontalScrollbarSize: number;
horizontalSliderSize: number;
horizontalHasArrows: boolean;
vertical: Visibility;
vertical: ScrollbarVisibility;
verticalScrollbarSize: number;
verticalSliderSize: number;
verticalHasArrows: boolean;

View file

@ -7,26 +7,10 @@
import {Disposable} from 'vs/base/common/lifecycle';
import {TimeoutTimer} from 'vs/base/common/async';
import {FastDomNode} from 'vs/base/browser/styleMutator';
export enum Visibility {
Auto,
Hidden,
Visible
}
export function visibilityFromString(visibility: string): Visibility {
switch (visibility) {
case 'hidden':
return Visibility.Hidden;
case 'visible':
return Visibility.Visible;
default:
return Visibility.Auto;
}
}
import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
export class ScrollbarVisibilityController extends Disposable {
private _visibility: Visibility;
private _visibility: ScrollbarVisibility;
private _visibleClassName: string;
private _invisibleClassName: string;
private _domNode: FastDomNode;
@ -35,7 +19,7 @@ export class ScrollbarVisibilityController extends Disposable {
private _isVisible: boolean;
private _revealTimer: TimeoutTimer;
constructor(visibility: Visibility, visibleClassName: string, invisibleClassName: string) {
constructor(visibility: ScrollbarVisibility, visibleClassName: string, invisibleClassName: string) {
super();
this._visibility = visibility;
this._visibleClassName = visibleClassName;
@ -50,10 +34,10 @@ export class ScrollbarVisibilityController extends Disposable {
// ----------------- Hide / Reveal
private applyVisibilitySetting(shouldBeVisible: boolean): boolean {
if (this._visibility === Visibility.Hidden) {
if (this._visibility === ScrollbarVisibility.Hidden) {
return false;
}
if (this._visibility === Visibility.Visible) {
if (this._visibility === ScrollbarVisibility.Visible) {
return true;
}
return shouldBeVisible;

View file

@ -4,26 +4,24 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as Browser from 'vs/base/browser/browser';
import {AbstractScrollbar, ScrollbarHost, IMouseMoveEventData} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
import {IMouseEvent, StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
import {IDomNodePosition} from 'vs/base/browser/dom';
import {ScrollableElementResolvedOptions} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import {ScrollbarVisibility, ScrollableElementResolvedOptions} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import {Scrollable, ScrollEvent} from 'vs/base/common/scrollable';
import {ScrollbarState} from 'vs/base/browser/ui/scrollbar/scrollbarState';
import {ARROW_IMG_SIZE} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
import {Visibility} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
export class VerticalScrollbar extends AbstractScrollbar {
constructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {
super({
forbidTranslate3dUse: options.forbidTranslate3dUse,
canUseTranslate3d: options.canUseTranslate3d,
lazyRender: options.lazyRender,
host: host,
scrollbarState: new ScrollbarState(
(options.verticalHasArrows ? options.arrowSize : 0),
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize),
(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),
// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom
0
),
@ -64,9 +62,11 @@ export class VerticalScrollbar extends AbstractScrollbar {
protected _updateSlider(sliderSize: number, sliderPosition: number): void {
this.slider.setHeight(sliderSize);
if (!this._forbidTranslate3dUse && Browser.canUseTranslate3d) {
if (this._canUseTranslate3d) {
this.slider.setTransform('translate3d(0px, ' + sliderPosition + 'px, 0px)');
this.slider.setTop(0);
} else {
this.slider.setTransform('');
this.slider.setTop(sliderPosition);
}
}

View file

@ -14,6 +14,14 @@ function isThenable<T>(obj: any): obj is Thenable<T> {
return obj && typeof (<Thenable<any>>obj).then === 'function';
}
export function toThenable<T>(arg: T | Thenable<T>): Thenable<T> {
if (isThenable(arg)) {
return arg;
} else {
return TPromise.as(arg);
}
}
export function asWinJsPromise<T>(callback: (token: CancellationToken) => T | Thenable<T>): TPromise<T> {
let source = new CancellationTokenSource();
return new TPromise<T>((resolve, reject) => {
@ -28,6 +36,14 @@ export function asWinJsPromise<T>(callback: (token: CancellationToken) => T | Th
});
}
/**
* Hook a cancellation token to a WinJS Promise
*/
export function wireCancellationToken<T>(token: CancellationToken, promise: TPromise<T>): Thenable<T> {
token.onCancellationRequested(() => promise.cancel());
return promise;
}
export interface ITask<T> {
(): T;
}
@ -538,17 +554,10 @@ export class RunOnceScheduler {
this.runner = runner;
}
/**
* Set timeout. This change will only impact new schedule calls.
*/
public setTimeout(timeout: number): void {
this.timeout = timeout;
}
/**
* Cancel previous runner (if any) & schedule a new runner.
*/
public schedule(): void {
public schedule(delay = this.timeout): void {
this.cancel();
this.timeoutToken = platform.setTimeout(this.timeoutHandler, this.timeout);
}

View file

@ -14,7 +14,9 @@ export class IdGenerator {
this._lastId = 0;
}
public generate(): string {
public nextId(): string {
return this._prefix + (++this._lastId);
}
}
export const defaultGenerator = new IdGenerator('id#');

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import {localize} from 'vs/nls';
export enum ScanError {
None,
@ -35,19 +35,50 @@ export enum SyntaxKind {
EOF
}
/**
* The scanner object, representing a JSON scanner at a position in the input string.
*/
export interface JSONScanner {
/**
* Sets the scan position to a new offset. A call to 'scan' is needed to get the first token.
*/
setPosition(pos: number);
/**
* Read the next token. Returns the tolen code.
*/
scan(): SyntaxKind;
/**
* Returns the current scan position, which is after the last read token.
*/
getPosition(): number;
/**
* Returns the last read token.
*/
getToken(): SyntaxKind;
/**
* Returns the last read token value. The value for strings is the decoded string content. For numbers its of type number, for boolean it's true or false.
*/
getTokenValue(): string;
/**
* The start offset of the last read token.
*/
getTokenOffset(): number;
/**
* The length of the last read token.
*/
getTokenLength(): number;
/**
* An error code of the last scan.
*/
getTokenError(): ScanError;
}
/**
* Creates a JSON scanner on the given text.
* If ignoreTrivia is set, whitespaces or comments are ignored.
*/
export function createScanner(text:string, ignoreTrivia:boolean = false):JSONScanner {
var pos = 0,
let pos = 0,
len = text.length,
value:string = '',
tokenOffset = 0,
@ -55,10 +86,10 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
scanError:ScanError = ScanError.None;
function scanHexDigits(count: number, exact?: boolean): number {
var digits = 0;
var value = 0;
let digits = 0;
let value = 0;
while (digits < count || !exact) {
var ch = text.charCodeAt(pos);
let ch = text.charCodeAt(pos);
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
value = value * 16 + ch - CharacterCodes._0;
}
@ -80,8 +111,16 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
return value;
}
function setPosition(newPosition: number) {
pos = newPosition;
value = '';
tokenOffset = 0;
token = SyntaxKind.Unknown;
scanError = ScanError.None;
}
function scanNumber(): string {
var start = pos;
let start = pos;
if (text.charCodeAt(pos) === CharacterCodes._0) {
pos++;
} else {
@ -99,10 +138,10 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
}
} else {
scanError = ScanError.UnexpectedEndOfNumber;
return text.substring(start, end);
return text.substring(start, pos);
}
}
var end = pos;
let end = pos;
if (pos < text.length && (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e)) {
pos++;
if (pos < text.length && text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) {
@ -123,7 +162,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
function scanString(): string {
var result = '',
let result = '',
start = pos;
while (true) {
@ -132,7 +171,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
scanError = ScanError.UnexpectedEndOfString;
break;
}
var ch = text.charCodeAt(pos);
let ch = text.charCodeAt(pos);
if (ch === CharacterCodes.doubleQuote) {
result += text.substring(start, pos);
pos++;
@ -172,7 +211,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
result += '\t';
break;
case CharacterCodes.u:
var ch = scanHexDigits(4, true);
let ch = scanHexDigits(4, true);
if (ch >= 0) {
result += String.fromCharCode(ch);
} else {
@ -208,7 +247,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
return token = SyntaxKind.EOF;
}
var code = text.charCodeAt(pos);
let code = text.charCodeAt(pos);
// trivia: whitespace
if (isWhiteSpace(code)) {
do {
@ -260,7 +299,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
// comments
case CharacterCodes.slash:
var start = pos - 1;
let start = pos - 1;
// Single-line comment
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
pos += 2;
@ -280,10 +319,10 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
pos += 2;
var safeLength = len - 1; // For lookahead.
var commentClosed = false;
let safeLength = len - 1; // For lookahead.
let commentClosed = false;
while (pos < safeLength) {
var ch = text.charCodeAt(pos);
let ch = text.charCodeAt(pos);
if (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) {
pos += 2;
@ -371,7 +410,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
function scanNextNonTrivia():SyntaxKind {
var result : SyntaxKind;
let result : SyntaxKind;
do {
result = scanNext();
} while (result >= SyntaxKind.LineCommentTrivia && result <= SyntaxKind.Trivia);
@ -379,6 +418,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca
}
return {
setPosition: setPosition,
getPosition: () => pos,
scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
getToken: () => token,
@ -403,10 +443,6 @@ function isDigit(ch: number): boolean {
return ch >= CharacterCodes._0 && ch <= CharacterCodes._9;
}
export function isLetter(ch: number): boolean {
return ch >= CharacterCodes.a && ch <= CharacterCodes.z || ch >= CharacterCodes.A && ch <= CharacterCodes.Z;
}
enum CharacterCodes {
nullCharacter = 0,
maxAsciiCharacter = 0x7F,
@ -552,7 +588,7 @@ enum CharacterCodes {
*/
export function stripComments(text:string, replaceCh?:string):string {
var _scanner = createScanner(text),
let _scanner = createScanner(text),
parts: string[] = [],
kind:SyntaxKind,
offset = 0,
@ -579,23 +615,415 @@ export function stripComments(text:string, replaceCh?:string):string {
return parts.join('');
}
export function parse(text:string, errors: string[] = []) : any {
var noMatch = Object();
var _scanner = createScanner(text, true);
export interface ParseError {
error: ParseErrorCode;
}
function scanNext() : SyntaxKind {
var token = _scanner.scan();
while (token === SyntaxKind.Unknown) {
handleError(nls.localize('UnknownSymbol', 'Invalid symbol'));
token = _scanner.scan();
export enum ParseErrorCode {
InvalidSymbol,
InvalidNumberFormat,
PropertyNameExpected,
ValueExpected,
ColonExpected,
CommaExpected,
CloseBraceExpected,
CloseBracketExpected,
EndOfFileExpected
}
export function getParseErrorMessage(errorCode: ParseErrorCode) : string {
switch (errorCode) {
case ParseErrorCode.InvalidSymbol: return localize('error.invalidSymbol', 'Invalid symbol');
case ParseErrorCode.InvalidNumberFormat: return localize('error.invalidNumberFormat', 'Invalid number format');
case ParseErrorCode.PropertyNameExpected: return localize('error.propertyNameExpected', 'Property name expected');
case ParseErrorCode.ValueExpected: return localize('error.valueExpected', 'Value expected');
case ParseErrorCode.ColonExpected: return localize('error.colonExpected', 'Colon expected');
case ParseErrorCode.CommaExpected: return localize('error.commaExpected', 'Comma expected');
case ParseErrorCode.CloseBraceExpected: return localize('error.closeBraceExpected', 'Closing brace expected');
case ParseErrorCode.CloseBracketExpected: return localize('error.closeBracketExpected', 'Closing bracket expected');
case ParseErrorCode.EndOfFileExpected: return localize('error.endOfFileExpected', 'End of file expected');
default:
return '';
}
}
export type NodeType = "object" | "array" | "property" | "string" | "number" | "boolean" | "null";
function getLiteralNodeType(value: any) : NodeType {
switch (typeof value) {
case 'boolean': return 'boolean';
case 'number': return 'number';
case 'string': return 'string';
default: return 'null';
}
}
export interface Node {
type: NodeType;
value?: any;
offset: number;
length: number;
columnOffset?: number;
parent?: Node;
children?: Node[];
}
export type Segment = string | number;
export interface Location {
/**
* The previous property key or literal value (string, number, boolean or null) or undefined.
*/
previousNode?: Node;
/**
* The path describing the location in the JSON document. The path consists of a sequence strings
* representing an object property or numbers for array indices.
*/
path: Segment[];
/**
* Matches the locations path against a pattern consisting of strings (for properties) and numbers (for array indices).
* '*' will match a single segment, of any property name or index.
* '**' will match a sequece of segments or no segment, of any property name or index.
*/
matches: (patterns: Segment[]) => boolean;
/**
* If set, the location's offset is at a property key.
*/
isAtPropertyKey: boolean;
}
/**
* For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.
*/
export function getLocation(text:string, position: number) : Location {
let segments: any[] = []; // strings or numbers
let earlyReturnException = new Object();
let previousNode : Node = void 0;
const previousNodeInst : Node = {
value: void 0,
offset: void 0,
length: void 0,
type: void 0
};
let isAtPropertyKey = false;
function setPreviousNode(value: string, offset: number, length: number, type: NodeType) {
previousNodeInst.value = value;
previousNodeInst.offset = offset;
previousNodeInst.length = length;
previousNodeInst.type = type;
previousNodeInst.columnOffset = void 0;
previousNode = previousNodeInst;
}
try {
visit(text, {
onObjectBegin: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
isAtPropertyKey = position > offset;
segments.push(''); // push a placeholder (will be replaced or removed)
},
onObjectProperty: (name: string, offset: number, length: number) => {
if (position < offset) {
throw earlyReturnException;
}
setPreviousNode(name, offset, length, 'property');
segments[segments.length - 1] = name;
if (position <= offset + length) {
throw earlyReturnException;
}
},
onObjectEnd: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
segments.pop();
},
onArrayBegin: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
segments.push(0);
},
onArrayEnd: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
segments.pop();
},
onLiteralValue: (value: any, offset: number, length: number) => {
if (position < offset) {
throw earlyReturnException;
}
setPreviousNode(value, offset, length, getLiteralNodeType(value));
if (position <= offset + length) {
throw earlyReturnException;
}
},
onSeparator: (sep: string, offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
if (sep === ':' && previousNode.type === 'property') {
previousNode.columnOffset = offset;
isAtPropertyKey = false;
previousNode = void 0;
} else if (sep === ',') {
let last = segments[segments.length - 1];
if (typeof last === 'number') {
segments[segments.length - 1] = last + 1;
} else {
isAtPropertyKey = true;
segments[segments.length - 1] = '';
}
previousNode = void 0;
}
}
});
} catch (e) {
if (e !== earlyReturnException) {
throw e;
}
return token;
}
function handleError(message:string, skipUntilAfter: SyntaxKind[] = [], skipUntil: SyntaxKind[] = []) : void {
errors.push(message);
if (segments[segments.length - 1] === '') {
segments.pop();
}
return {
path: segments,
previousNode,
isAtPropertyKey,
matches: (pattern: string[]) => {
let k = 0;
for (let i = 0; k < pattern.length && i < segments.length; i++) {
if (pattern[k] === segments[i] || pattern[k] === '*') {
k++;
} else if (pattern[k] !== '**') {
return false;
}
}
return k === pattern.length;
}
};
}
export interface ParseOptions {
disallowComments?: boolean;
}
/**
* Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
* Therefore always check the errors list to find out if the input was valid.
*/
export function parse(text:string, errors: ParseError[] = [], options?: ParseOptions) : any {
let currentProperty : string = null;
let currentParent : any = [];
let previousParents : any[] = [];
function onValue(value: any) {
if (Array.isArray(currentParent)) {
(<any[]> currentParent).push(value);
} else if (currentProperty) {
currentParent[currentProperty] = value;
}
}
let visitor : JSONVisitor = {
onObjectBegin: () => {
let object = {};
onValue(object);
previousParents.push(currentParent);
currentParent = object;
currentProperty = null;
},
onObjectProperty: (name: string) => {
currentProperty = name;
},
onObjectEnd: () => {
currentParent = previousParents.pop();
},
onArrayBegin: () => {
let array = [];
onValue(array);
previousParents.push(currentParent);
currentParent = array;
currentProperty = null;
},
onArrayEnd: () => {
currentParent = previousParents.pop();
},
onLiteralValue: onValue,
onError:(error:ParseErrorCode) => {
errors.push({error: error});
}
};
visit(text, visitor, options);
return currentParent[0];
}
/**
* Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
*/
export function parseTree(text:string, errors: ParseError[] = [], options?: ParseOptions) : Node {
let currentParent : Node = { type: 'array', offset: -1, length: -1, children: [] }; // artificial root
function ensurePropertyComplete(endOffset:number) {
if (currentParent.type === 'property') {
currentParent.length = endOffset - currentParent.offset;
currentParent = currentParent.parent;
}
}
function onValue(valueNode: Node) : Node {
currentParent.children.push(valueNode);
ensurePropertyComplete(valueNode.offset + valueNode.length);
return valueNode;
}
let visitor : JSONVisitor = {
onObjectBegin: (offset: number) => {
currentParent = onValue({ type: 'object', offset, length: -1, parent: currentParent, children: [] });
},
onObjectProperty: (name: string, offset: number, length: number) => {
currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] });
currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent});
},
onObjectEnd: (offset: number, length: number) => {
ensurePropertyComplete(offset);
currentParent.length = offset + length - currentParent.offset;
currentParent = currentParent.parent;
},
onArrayBegin: (offset: number, length: number) => {
currentParent = onValue({ type: 'array', offset, length: -1, parent: currentParent, children: [] });
},
onArrayEnd: (offset: number, length: number) => {
currentParent.length = offset + length - currentParent.offset;
currentParent = currentParent.parent;
},
onLiteralValue: (value: any, offset: number, length: number) => {
onValue({ type: getLiteralNodeType(value), offset, length, parent: currentParent, value });
},
onSeparator: (sep: string, offset: number, length: number) => {
if (currentParent.type === 'property') {
if (sep === ':') {
currentParent.columnOffset = offset;
} else if (sep === ',') {
ensurePropertyComplete(offset);
}
}
},
onError:(error:ParseErrorCode) => {
errors.push({error: error});
}
};
visit(text, visitor, options);
let result = currentParent.children[0];
delete result.parent;
return result;
}
export function findNodeAtLocation(root: Node, segments: Segment[]) : Node {
let node = root;
for (let segment of segments) {
if (typeof segment === 'string') {
if (node.type !== 'object') {
return void 0;
}
let found = false;
for (let propertyNode of node.children) {
if (propertyNode.children[0].value === segment) {
node = propertyNode.children[1];
found = true;
break;
}
}
if (!found) {
return void 0;
}
} else {
let index = <number> segment;
if (node.type !== 'array' || index < 0 || index >= node.children.length) {
return void 0;
}
node = node.children[index];
}
}
return node;
}
export function getNodeValue(node: Node) : any {
if (node.type === 'array') {
return node.children.map(getNodeValue);
} else if (node.type === 'object') {
let obj = {};
for (let prop of node.children) {
obj[prop.children[0].value] = getNodeValue(prop.children[1]);
}
return obj;
}
return node.value;
}
/**
* Parses the given text and invokes the visitor functions for each object, array and literal reached.
*/
export function visit(text:string, visitor: JSONVisitor, options?: ParseOptions) : any {
let _scanner = createScanner(text, false);
function toNoArgVisit(visitFunction: (offset: number, length: number) => void) : () => void {
return visitFunction ? () => visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true;
}
function toOneArgVisit<T>(visitFunction: (arg: T, offset: number, length: number) => void) : (arg: T) => void {
return visitFunction ? (arg: T) => visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true;
}
let onObjectBegin = toNoArgVisit(visitor.onObjectBegin),
onObjectProperty = toOneArgVisit(visitor.onObjectProperty),
onObjectEnd = toNoArgVisit(visitor.onObjectEnd),
onArrayBegin = toNoArgVisit(visitor.onArrayBegin),
onArrayEnd = toNoArgVisit(visitor.onArrayEnd),
onLiteralValue = toOneArgVisit(visitor.onLiteralValue),
onSeparator = toOneArgVisit(visitor.onSeparator),
onError = toOneArgVisit(visitor.onError);
let disallowComments = options && options.disallowComments;
function scanNext() : SyntaxKind {
while (true) {
let token = _scanner.scan();
switch (token) {
case SyntaxKind.LineCommentTrivia:
case SyntaxKind.BlockCommentTrivia:
if (disallowComments) {
handleError(ParseErrorCode.InvalidSymbol);
}
break;
case SyntaxKind.Unknown:
handleError(ParseErrorCode.InvalidSymbol);
break;
case SyntaxKind.Trivia:
case SyntaxKind.LineBreakTrivia:
break;
default:
return token;
}
}
}
function handleError(error:ParseErrorCode, skipUntilAfter: SyntaxKind[] = [], skipUntil: SyntaxKind[] = []) : void {
onError(error);
if (skipUntilAfter.length + skipUntil.length > 0) {
var token = _scanner.getToken();
let token = _scanner.getToken();
while (token !== SyntaxKind.EOF) {
if (skipUntilAfter.indexOf(token) !== -1) {
scanNext();
@ -608,156 +1036,186 @@ export function parse(text:string, errors: string[] = []) : any {
}
}
function parseString() : any {
function parseString(isValue: boolean) : boolean {
if (_scanner.getToken() !== SyntaxKind.StringLiteral) {
return noMatch;
return false;
}
let value = _scanner.getTokenValue();
if (isValue) {
onLiteralValue(value);
} else {
onObjectProperty(value);
}
var value = _scanner.getTokenValue();
scanNext();
return value;
return true;
}
function parseLiteral() : any {
var value : any;
function parseLiteral() : boolean {
switch (_scanner.getToken()) {
case SyntaxKind.NumericLiteral:
let value = 0;
try {
value = JSON.parse(_scanner.getTokenValue());
if (typeof value !== 'number') {
handleError(nls.localize('InvalidNumberFormat', 'Invalid number format'));
handleError(ParseErrorCode.InvalidNumberFormat);
value = 0;
}
} catch (e) {
value = 0;
handleError(ParseErrorCode.InvalidNumberFormat);
}
onLiteralValue(value);
break;
case SyntaxKind.NullKeyword:
value = null;
onLiteralValue(null);
break;
case SyntaxKind.TrueKeyword:
value = true;
onLiteralValue(true);
break;
case SyntaxKind.FalseKeyword:
value = false;
onLiteralValue(false);
break;
default:
return noMatch;
return false;
}
scanNext();
return value;
return true;
}
function parseProperty(result: any) : any {
var key = parseString();
if (key === noMatch) {
handleError(nls.localize('PropertyExpected', 'Property name expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
function parseProperty() : boolean {
if (!parseString(false)) {
handleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
return false;
}
if (_scanner.getToken() === SyntaxKind.ColonToken) {
onSeparator(':');
scanNext(); // consume colon
var value = parseValue();
if (value !== noMatch) {
result[key] = value;
} else {
handleError(nls.localize('ValueExpected', 'Value expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
if (!parseValue()) {
handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
}
} else {
handleError(nls.localize('ColonExpected', 'Colon expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
handleError(ParseErrorCode.ColonExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
}
return true;
}
function parseObject() : any {
function parseObject() : boolean {
if (_scanner.getToken() !== SyntaxKind.OpenBraceToken) {
return noMatch;
return false;
}
var obj = {};
onObjectBegin();
scanNext(); // consume open brace
var needsComma = false;
let needsComma = false;
while (_scanner.getToken() !== SyntaxKind.CloseBraceToken && _scanner.getToken() !== SyntaxKind.EOF) {
if (_scanner.getToken() === SyntaxKind.CommaToken) {
if (!needsComma) {
handleError(nls.localize('ValueExpected', 'Value expected'), [], [] );
handleError(ParseErrorCode.ValueExpected, [], [] );
}
onSeparator(',');
scanNext(); // consume comma
} else if (needsComma) {
handleError(nls.localize('CommaExpected', 'Comma expected'), [], [] );
handleError(ParseErrorCode.CommaExpected, [], [] );
}
var propertyParsed = parseProperty(obj);
if (!propertyParsed) {
handleError(nls.localize('ValueExpected', 'Value expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
if (!parseProperty()) {
handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
}
needsComma = true;
}
onObjectEnd();
if (_scanner.getToken() !== SyntaxKind.CloseBraceToken) {
handleError(nls.localize('CloseBraceExpected', 'Closing brace expected'), [SyntaxKind.CloseBraceToken], []);
handleError(ParseErrorCode.CloseBraceExpected, [SyntaxKind.CloseBraceToken], []);
} else {
scanNext(); // consume close brace
}
return obj;
return true;
}
function parseArray() : any {
function parseArray() : boolean {
if (_scanner.getToken() !== SyntaxKind.OpenBracketToken) {
return noMatch;
return false;
}
var arr: any[] = [];
onArrayBegin();
scanNext(); // consume open bracket
var needsComma = false;
let needsComma = false;
while (_scanner.getToken() !== SyntaxKind.CloseBracketToken && _scanner.getToken() !== SyntaxKind.EOF) {
if (_scanner.getToken() === SyntaxKind.CommaToken) {
if (!needsComma) {
handleError(nls.localize('ValeExpected', 'Value expected'), [], [] );
handleError(ParseErrorCode.ValueExpected, [], [] );
}
onSeparator(',');
scanNext(); // consume comma
} else if (needsComma) {
handleError(nls.localize('CommaExpected', 'Comma expected'), [], [] );
handleError(ParseErrorCode.CommaExpected, [], [] );
}
var value = parseValue();
if (value === noMatch) {
handleError(nls.localize('ValueExpected', 'Value expected'), [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken] );
} else {
arr.push(value);
if (!parseValue()) {
handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken] );
}
needsComma = true;
}
onArrayEnd();
if (_scanner.getToken() !== SyntaxKind.CloseBracketToken) {
handleError(nls.localize('CloseBracketExpected', 'Closing bracket expected'), [SyntaxKind.CloseBracketToken], []);
handleError(ParseErrorCode.CloseBracketExpected, [SyntaxKind.CloseBracketToken], []);
} else {
scanNext(); // consume close bracket
}
return arr;
return true;
}
function parseValue() : any {
var result = parseArray();
if (result !== noMatch) {
return result;
}
result = parseObject();
if (result !== noMatch) {
return result;
}
result = parseString();
if (result !== noMatch) {
return result;
}
return parseLiteral();
function parseValue() : boolean {
return parseArray() || parseObject() || parseString(true) || parseLiteral();
}
scanNext();
var value = parseValue();
if (value === noMatch) {
handleError(nls.localize('ValueExpected', 'Value expected'), [], []);
return void 0;
if (!parseValue()) {
handleError(ParseErrorCode.ValueExpected, [], []);
return false;
}
if (_scanner.getToken() !== SyntaxKind.EOF) {
handleError(nls.localize('EOFExpected', 'End of content expected'), [], []);
handleError(ParseErrorCode.EndOfFileExpected, [], []);
}
return value;
return true;
}
export interface JSONVisitor {
/**
* Invoked when an open brace is encountered and an object is started. The offset and length represent the location of the open brace.
*/
onObjectBegin?: (offset:number, length:number) => void;
/**
* Invoked when a property is encountered. The offset and length represent the location of the property name.
*/
onObjectProperty?: (property: string, offset:number, length:number) => void;
/**
* Invoked when a closing brace is encountered and an object is completed. The offset and length represent the location of the closing brace.
*/
onObjectEnd?: (offset:number, length:number) => void;
/**
* Invoked when an open bracket is encountered. The offset and length represent the location of the open bracket.
*/
onArrayBegin?: (offset:number, length:number) => void;
/**
* Invoked when a closing bracket is encountered. The offset and length represent the location of the closing bracket.
*/
onArrayEnd?: (offset:number, length:number) => void;
/**
* Invoked when a literal value is encountered. The offset and length represent the location of the literal value.
*/
onLiteralValue?: (value: any, offset:number, length:number) => void;
/**
* Invoked when a comma or colon separator is encountered. The offset and length represent the location of the separator.
*/
onSeparator?: (charcter: string, offset:number, length:number) => void;
/**
* Invoked on an error.
*/
onError?: (error: ParseErrorCode, offset:number, length:number) => void;
}

View file

@ -0,0 +1,94 @@
/*---------------------------------------------------------------------------------------------
* 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 { ParseError, parseTree, Segment, findNodeAtLocation } from 'vs/base/common/json';
import { Edit, FormattingOptions, format } from 'vs/base/common/jsonFormatter';
export function removeProperty(text: string, segments: Segment[], formattingOptions: FormattingOptions) : Edit[] {
return setProperty(text, segments, void 0, formattingOptions);
}
export function setProperty(text: string, segments: Segment[], value: any, formattingOptions: FormattingOptions, getInsertionIndex?: (properties: string[]) => number) : Edit[] {
let lastSegment = segments.pop();
if (typeof lastSegment !== 'string') {
throw new Error('Last segment must be a property name');
}
let errors: ParseError[] = [];
let node = parseTree(text, errors);
if (segments.length > 0) {
node = findNodeAtLocation(node, segments);
if (node === void 0) {
throw new Error('Cannot find object');
}
}
if (node && node.type === 'object') {
let existing = findNodeAtLocation(node, [ lastSegment ]);
if (existing !== void 0) {
if (value === void 0) { // delete
let propertyIndex = node.children.indexOf(existing.parent);
let removeBegin : number;
let removeEnd = existing.parent.offset + existing.parent.length;
if (propertyIndex > 0) {
// remove the comma of the previous node
let previous = node.children[propertyIndex - 1];
removeBegin = previous.offset + previous.length;
} else {
removeBegin = node.offset + 1;
if (node.children.length > 1) {
// remove the comma of the next node
let next = node.children[1];
removeEnd = next.offset;
}
}
return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: '' }, formattingOptions);
} else {
// set value of existing property
return [{ offset: existing.offset, length: existing.length, content: JSON.stringify(value) }];
}
} else {
if (value === void 0) { // delete
throw new Error(`Property ${lastSegment} does not exist.`);
}
let newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
let index = getInsertionIndex ? getInsertionIndex(node.children.map(p => p.children[0].value)) : node.children.length;
let edit: Edit;
if (index > 0) {
let previous = node.children[index - 1];
edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty};
} else if (node.children.length === 0) {
edit = { offset: node.offset + 1, length: 0, content: newProperty};
} else {
edit = { offset: node.offset + 1, length: 0, content: newProperty + ','};
}
return withFormatting(text, edit, formattingOptions);
}
} else {
throw new Error('Path does not reference an object');
}
}
function withFormatting(text:string, edit: Edit, formattingOptions: FormattingOptions) : Edit[] {
// apply the edit
let newText = text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
// format the new text
let begin = edit.offset;
let end = edit.offset + edit.content.length;
let edits = format(newText, { offset: begin, length: end - begin }, formattingOptions);
// apply the formatting edits and track the begin and end offsets of the changes
for (let i = edits.length - 1; i >= 0; i--) {
let edit = edits[i];
newText = newText.substring(0, edit.offset) + edit.content + newText.substring(edit.offset + edit.length);
begin = Math.min(begin, edit.offset);
end = Math.max(end, edit.offset + edit.length);
end += edit.content.length - edit.length;
}
// create a single edit with all changes
let editLength = text.length - (newText.length - end) - begin;
return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
}

View file

@ -0,0 +1,203 @@
/*---------------------------------------------------------------------------------------------
* 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 Json = require('./json');
export interface FormattingOptions {
/**
* If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent?
*/
tabSize: number;
/**
* Is indentation based on spaces?
*/
insertSpaces: boolean;
/**
* The default end of line line character
*/
eol: string;
}
export interface Edit {
offset: number;
length: number;
content: string;
}
export function format(documentText: string, range: { offset: number, length: number}, options: FormattingOptions): Edit[] {
let initialIndentLevel: number;
let value: string;
let rangeStart: number;
let rangeEnd: number;
if (range) {
rangeStart = range.offset;
rangeEnd = rangeStart + range.length;
while (rangeStart > 0 && !isEOL(documentText, rangeStart - 1)) {
rangeStart--;
}
let scanner = Json.createScanner(documentText, true);
scanner.setPosition(rangeEnd);
scanner.scan();
rangeEnd = scanner.getPosition();
value = documentText.substring(rangeStart, rangeEnd);
initialIndentLevel = computeIndentLevel(value, 0, options);
} else {
value = documentText;
rangeStart = 0;
rangeEnd = documentText.length;
initialIndentLevel = 0;
}
let eol = getEOL(options, documentText);
let lineBreak = false;
let indentLevel = 0;
let indentValue: string;
if (options.insertSpaces) {
indentValue = repeat(' ', options.tabSize);
} else {
indentValue = '\t';
}
let scanner = Json.createScanner(value, false);
function newLineAndIndent(): string {
return eol + repeat(indentValue, initialIndentLevel + indentLevel);
}
function scanNext(): Json.SyntaxKind {
let token = scanner.scan();
lineBreak = false;
while (token === Json.SyntaxKind.Trivia || token === Json.SyntaxKind.LineBreakTrivia) {
lineBreak = lineBreak || (token === Json.SyntaxKind.LineBreakTrivia);
token = scanner.scan();
}
return token;
}
let editOperations: Edit[] = [];
function addEdit(text: string, startOffset: number, endOffset: number) {
if (documentText.substring(startOffset, endOffset) !== text) {
editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
}
}
let firstToken = scanNext();
if (firstToken !== Json.SyntaxKind.EOF) {
let firstTokenStart = scanner.getTokenOffset() + rangeStart;
let initialIndent = repeat(indentValue, initialIndentLevel);
addEdit(initialIndent, rangeStart, firstTokenStart);
}
while (firstToken !== Json.SyntaxKind.EOF) {
let firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + rangeStart;
let secondToken = scanNext();
let replaceContent = '';
while (!lineBreak && (secondToken === Json.SyntaxKind.LineCommentTrivia || secondToken === Json.SyntaxKind.BlockCommentTrivia)) {
// comments on the same line: keep them on the same line, but ignore them otherwise
let commentTokenStart = scanner.getTokenOffset() + rangeStart;
addEdit(' ', firstTokenEnd, commentTokenStart);
firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + rangeStart;
replaceContent = secondToken === Json.SyntaxKind.LineCommentTrivia ? newLineAndIndent() : '';
secondToken = scanNext();
}
if (secondToken === Json.SyntaxKind.CloseBraceToken) {
if (firstToken !== Json.SyntaxKind.OpenBraceToken) {
indentLevel--;
replaceContent = newLineAndIndent();
}
} else if (secondToken === Json.SyntaxKind.CloseBracketToken) {
if (firstToken !== Json.SyntaxKind.OpenBracketToken) {
indentLevel--;
replaceContent = newLineAndIndent();
}
} else if (secondToken !== Json.SyntaxKind.EOF) {
switch (firstToken) {
case Json.SyntaxKind.OpenBracketToken:
case Json.SyntaxKind.OpenBraceToken:
indentLevel++;
replaceContent = newLineAndIndent();
break;
case Json.SyntaxKind.CommaToken:
case Json.SyntaxKind.LineCommentTrivia:
replaceContent = newLineAndIndent();
break;
case Json.SyntaxKind.BlockCommentTrivia:
if (lineBreak) {
replaceContent = newLineAndIndent();
} else {
// symbol following comment on the same line: keep on same line, separate with ' '
replaceContent = ' ';
}
break;
case Json.SyntaxKind.ColonToken:
replaceContent = ' ';
break;
case Json.SyntaxKind.NullKeyword:
case Json.SyntaxKind.TrueKeyword:
case Json.SyntaxKind.FalseKeyword:
case Json.SyntaxKind.NumericLiteral:
if (secondToken === Json.SyntaxKind.NullKeyword || secondToken === Json.SyntaxKind.FalseKeyword || secondToken === Json.SyntaxKind.NumericLiteral) {
replaceContent = ' ';
}
break;
}
if (lineBreak && (secondToken === Json.SyntaxKind.LineCommentTrivia || secondToken === Json.SyntaxKind.BlockCommentTrivia)) {
replaceContent = newLineAndIndent();
}
}
let secondTokenStart = scanner.getTokenOffset() + rangeStart;
addEdit(replaceContent, firstTokenEnd, secondTokenStart);
firstToken = secondToken;
}
return editOperations;
}
function repeat(s: string, count: number): string {
let result = '';
for (let i = 0; i < count; i++) {
result += s;
}
return result;
}
function computeIndentLevel(content: string, offset: number, options: FormattingOptions): number {
let i = 0;
let nChars = 0;
let tabSize = options.tabSize || 4;
while (i < content.length) {
let ch = content.charAt(i);
if (ch === ' ') {
nChars++;
} else if (ch === '\t') {
nChars += tabSize;
} else {
break;
}
i++;
}
return Math.floor(nChars / tabSize);
}
function getEOL(options: FormattingOptions, text: string): string {
for (let i = 0; i < text.length; i++) {
let ch = text.charAt(i);
if (ch === '\r') {
if (i + 1 < text.length && text.charAt(i+1) === '\n') {
return '\r\n';
}
return '\r';
} else if (ch === '\n') {
return '\n';
}
}
return (options && options.eol) || '\n';
}
function isEOL(text: string, offset: number) {
return '\r\n'.indexOf(text.charAt(offset)) !== -1;
}

View file

@ -83,7 +83,15 @@ export abstract class Disposable implements IDisposable {
export class Disposables extends Disposable {
public add(disposable: IDisposable): void {
this._register(disposable);
public add<T extends IDisposable>(e: T): T;
public add(...elements: IDisposable[]): void;
public add<T extends IDisposable>(arg: T | T[]): T {
if (!Array.isArray(arg)) {
return this._register(arg);
} else {
for (let element of arg) {
return this._register(element);
}
}
}
}

View file

@ -151,14 +151,6 @@ export function toObject<T,R>(arr: T[], keyMap: (T) => string, valueMap: (T) =>
return arr.reduce((o, d) => assign(o, { [keyMap(d)]: valueMap(d) }), Object.create(null));
}
/**
* Returns a new object that has all values of {{obj}}
* plus those from {{defaults}}.
*/
export function withDefaults<T>(obj: T, defaults: T): T {
return mixin(clone(defaults), obj || {});
}
export function equals(one: any, other: any): boolean {
if (one === other) {
return true;

View file

@ -6,6 +6,14 @@
import {TPromise} from 'vs/base/common/winjs.base';
const _typeof = {
number: 'number',
string: 'string',
undefined: 'undefined',
object: 'object',
function: 'function'
};
/**
* @returns whether the provided parameter is a JavaScript Array or not.
*/
@ -14,7 +22,7 @@ export function isArray(array: any): array is any[] {
return Array.isArray(array);
}
if (array && typeof (array.length) === 'number' && array.constructor === Array) {
if (array && typeof (array.length) === _typeof.number && array.constructor === Array) {
return true;
}
@ -25,7 +33,7 @@ export function isArray(array: any): array is any[] {
* @returns whether the provided parameter is a JavaScript String or not.
*/
export function isString(str: any): str is string {
if (typeof (str) === 'string' || str instanceof String) {
if (typeof (str) === _typeof.string|| str instanceof String) {
return true;
}
@ -40,23 +48,24 @@ export function isStringArray(value: any): value is string[] {
}
/**
* @returns whether the provided parameter is a JavaScript Object or not.
*
* @returns whether the provided parameter is of type `object` but **not**
* `null`, an `array`, a `regexp`, nor a `date`.
*/
export function isObject(obj: any): obj is any {
// Needed for IE8
if (typeof obj === 'undefined' || obj === null) {
return false;
}
return Object.prototype.toString.call(obj) === '[object Object]';
return typeof obj === _typeof.object
&& obj !== null
&& !Array.isArray(obj)
&& !(obj instanceof RegExp)
&& !(obj instanceof Date);
}
/**
* In **contrast** to just checking `typeof` this will return `false` for `NaN`.
* @returns whether the provided parameter is a JavaScript Number or not.
*/
export function isNumber(obj: any): obj is number {
if ((typeof (obj) === 'number' || obj instanceof Number) && !isNaN(obj)) {
if ((typeof (obj) === _typeof.number || obj instanceof Number) && !isNaN(obj)) {
return true;
}
@ -74,7 +83,7 @@ export function isBoolean(obj: any): obj is boolean {
* @returns whether the provided parameter is undefined.
*/
export function isUndefined(obj: any): boolean {
return typeof (obj) === 'undefined';
return typeof (obj) === _typeof.undefined;
}
/**
@ -108,14 +117,14 @@ export function isEmptyObject(obj: any): obj is any {
* @returns whether the provided parameter is a JavaScript Function or not.
*/
export function isFunction(obj: any): obj is Function {
return Object.prototype.toString.call(obj) === '[object Function]';
return typeof obj === _typeof.function;
}
/**
* @returns whether the provided parameters is are JavaScript Function or not.
*/
export function areFunctions(...objects: any[]): boolean {
return objects && objects.length > 0 && objects.every((object) => isFunction(object));
return objects && objects.length > 0 && objects.every(isFunction);
}
export type TypeConstraint = string | Function;
@ -129,11 +138,11 @@ export function validateConstraints(args: any[], constraints: TypeConstraint[]):
export function validateConstraint(arg: any, constraint: TypeConstraint): void {
if (typeof constraint === 'string') {
if (isString(constraint)) {
if (typeof arg !== constraint) {
throw new Error(`argument does not match constraint: typeof ${constraint}`);
}
} else if (typeof constraint === 'function') {
} else if (isFunction(constraint)) {
if (arg instanceof constraint) {
return;
}

View file

@ -95,6 +95,7 @@ export declare class TPromise<V> {
public static is(value: any): value is TPromise<any>;
public static timeout(delay:number):TPromise<void>;
public static join<ValueType>(promises:TPromise<ValueType>[]):TPromise<ValueType[]>;
public static join<ValueType>(promises:Thenable<ValueType>[]):Thenable<ValueType[]>;
public static join<ValueType>(promises: {[n:string]:TPromise<ValueType>}):TPromise<{[n:string]:ValueType}>;
public static any<ValueType>(promises:TPromise<ValueType>[]):TPromise<{ key:string; value:TPromise<ValueType>;}>;
public static wrapError<ValueType>(error:any):TPromise<ValueType>;

View file

@ -157,9 +157,10 @@ class SimpleWorkerProtocol {
export class SimpleWorkerClient<T> extends Disposable {
private _worker:IWorker;
private _onModuleLoaded:TPromise<void>;
private _onModuleLoaded:TPromise<string[]>;
private _protocol: SimpleWorkerProtocol;
private _proxy: T;
private _lazyProxy: TPromise<T>;
private _lastRequestTimestamp = -1;
constructor(workerFactory:IWorkerFactory, moduleId:string, ctor:any) {
@ -190,13 +191,30 @@ export class SimpleWorkerClient<T> extends Disposable {
loaderConfiguration = (<any>window).requirejs.s.contexts._.config;
}
let lazyProxyFulfill : (v:T)=>void = null;
let lazyProxyReject: (err:any)=>void = null;
this._lazyProxy = new TPromise((c, e, p) => {
lazyProxyFulfill = c;
lazyProxyReject = e;
}, () => { /* no cancel */ });
// Send initialize message
this._onModuleLoaded = this._protocol.sendMessage(INITIALIZE, [
this._worker.getId(),
moduleId,
loaderConfiguration
]);
this._onModuleLoaded.then(null, (e) => this._onError('Worker failed to load ' + moduleId, e));
this._onModuleLoaded.then((availableMethods:string[]) => {
let proxy = <T><any>{};
for (let i = 0; i < availableMethods.length; i++) {
proxy[availableMethods[i]] = createProxyMethod(availableMethods[i], proxyMethodRequest);
}
lazyProxyFulfill(proxy);
}, (e) => {
lazyProxyReject(e);
this._onError('Worker failed to load ' + moduleId, e);
});
// Create proxy to loaded code
let proxyMethodRequest = (method:string, args:any[]):TPromise<any> => {
@ -211,10 +229,13 @@ export class SimpleWorkerClient<T> extends Disposable {
};
this._proxy = <T><any>{};
for (let prop in ctor.prototype) {
if (ctor.prototype.hasOwnProperty(prop)) {
if (typeof ctor.prototype[prop] === 'function') {
this._proxy[prop] = createProxyMethod(prop, proxyMethodRequest);
if (ctor) {
// console.warn('deprecated');
for (let prop in ctor.prototype) {
if (ctor.prototype.hasOwnProperty(prop)) {
if (typeof ctor.prototype[prop] === 'function') {
this._proxy[prop] = createProxyMethod(prop, proxyMethodRequest);
}
}
}
}
@ -224,6 +245,10 @@ export class SimpleWorkerClient<T> extends Disposable {
return this._proxy;
}
public getProxyObject(): TPromise<T> {
return this._lazyProxy;
}
public getLastRequestTimestamp(): number {
return this._lastRequestTimestamp;
}
@ -323,7 +348,15 @@ export class SimpleWorkerServer {
require([moduleId], (...result:any[]) => {
let handlerModule = result[0];
this._requestHandler = handlerModule.create();
cc(null);
let methods: string[] = [];
for (let prop in this._requestHandler) {
if (typeof this._requestHandler[prop] === 'function') {
methods.push(prop);
}
}
cc(methods);
}, ee);
return r;

View file

@ -1,158 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import types = require('vs/base/common/types');
import {safeStringify, mixin} 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,
private additionalDataToLog?: 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 {
if (this.additionalDataToLog) {
data = mixin(data, this.additionalDataToLog);
}
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;
}
}

16
src/vs/base/node/paths.ts Normal file
View file

@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import uri from 'vs/base/common/uri';
interface IPaths {
getAppDataPath(platform: string): string;
getUserDataPath(platform: string, appName: string, args: string[]): string;
}
const pathsPath = uri.parse(require.toUrl('paths')).fsPath;
const paths = require.__$__nodeRequire<IPaths>(pathsPath);
export const getAppDataPath = paths.getAppDataPath;
export const getUserDataPath = paths.getUserDataPath;

View file

@ -25,7 +25,7 @@ export function findFreePort(startPort: number, giveUpAfter: number, timeout: nu
doFindFreePort(startPort, giveUpAfter, (port) => {
if (!done) {
done = true;
window.clearInterval(timeoutHandle);
window.clearTimeout(timeoutHandle);
return clb(port);
}

View file

@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------------------------
* 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 {IServer} from 'vs/base/parts/ipc/common/ipc';
import {AIAdapter} from './aiAdapter';
import {IAIChannel} from './ai.ipc';
const adapter: { [handle: number]: AIAdapter } = Object.create(null);
let idPool = 0;
export function registerAIChannel(server: IServer) {
server.registerChannel('ai', <IAIChannel>{
call(command: string, arg: any): TPromise<any> {
switch (command) {
case 'create': {
let handle = idPool++;
let {key, eventPrefix, data} = arg;
adapter[handle] = new AIAdapter(eventPrefix, data, key);
return TPromise.as(handle);
}
case 'log': {
let {handle, eventName, data} = arg;
adapter[handle].log(eventName, data);
return TPromise.as(undefined);
}
case 'dispose': {
let {handle} = arg;
adapter[handle].dispose();
delete adapter[handle];
return TPromise.as(undefined);
}
}
}
});
}
// It is important to dispose the AI adapter properly because
// only then they flush remaining data.
process.on('SIGTERM', function () {
console.log('HERE');
let promises: TPromise<any>[] = [];
for (let handle in adapter) {
let ai = adapter[handle];
promises.push(ai.dispose());
}
TPromise.join(promises).then(_ => process.exit(0));
});

View file

@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* 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 {IChannel} from 'vs/base/parts/ipc/common/ipc';
export interface IAIChannel extends IChannel {
call(command: 'create', data: { key: string; eventPrefix: string; data: { [k: string]: any }; }): TPromise<number>;
call(command: 'log', data: { handle: number; eventName: string; data: { [k: string]: any }; }): TPromise<any>;
call(command: 'dispose', data: { handle: number; }): TPromise<any>;
call(command: string, arg: any): TPromise<any>;
}

View file

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------------------------
* 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 {IAIChannel} from './ai.ipc';
import {TPromise} from 'vs/base/common/winjs.base';
import {connect} from 'vs/base/parts/ipc/node/ipc.net';
export interface IAIAdapter {
log(eventName: string, data?: any): void;
dispose(): void;
}
export function createAIAdapter(key: string, eventPrefix: string, data: { [key: string]: any }): IAIAdapter {
let beforeReadyMessages: { type: string; args: any }[] = [];
let handle: number = undefined;
let channel: IAIChannel = {
call(type: string, args: any): TPromise<any> {
beforeReadyMessages.push({ type, args });
return TPromise.as(void 0);
}
};
connect(process.env['VSCODE_SHARED_IPC_HOOK']).then(client => client.getChannel<IAIChannel>('ai')).then(actualChannel => {
return actualChannel.call('create', { key, eventPrefix, data }).then(actualHandle => {
// channel has been created, store handle etc,
// and flush all early messages
handle = actualHandle;
channel = actualChannel;
for (let m of beforeReadyMessages) {
let {type, args} = m;
args.handle = handle;
channel.call(type, args);
}
beforeReadyMessages.length = 0;
});
});
return <IAIAdapter>{
log(eventName: string, data?: any) {
channel.call('log', { handle, eventName, data });
},
dispose() {
channel.call('dispose', { handle });
}
};
}

View file

@ -0,0 +1,153 @@
/*---------------------------------------------------------------------------------------------
* 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 appInsights from 'applicationinsights';
import {isObject} from 'vs/base/common/types';
import {safeStringify, mixin} from 'vs/base/common/objects';
import {TPromise} from 'vs/base/common/winjs.base';
namespace AI {
let _initialized = false;
function ensureAIEngineIsInitialized(): void {
if (_initialized === false) {
// we need to pass some fake key, otherwise AI throws an exception
appInsights.setup('2588e01f-f6c9-4cd6-a348-143741f8d702')
.setAutoCollectConsole(false)
.setAutoCollectExceptions(false)
.setAutoCollectPerformance(false)
.setAutoCollectRequests(false);
_initialized = true;
}
}
export function getClient(aiKey: string): typeof appInsights.client {
ensureAIEngineIsInitialized();
const client = appInsights.getClient(aiKey);
client.channel.setOfflineMode(true);
client.context.tags[client.context.keys.deviceMachineName] = ''; //prevent App Insights from reporting machine name
if (aiKey.indexOf('AIF-') === 0) {
client.config.endpointUrl = 'https://vortex.data.microsoft.com/collect/v1';
}
return client;
}
}
interface Properties {
[key: string]: string;
}
interface Measurements {
[key: string]: number;
}
export class AIAdapter {
private _aiClient: typeof appInsights.client;
constructor(
private _eventPrefix: string,
private _defaultData: { [key: string]: any },
aiKeyOrClientFactory: string | (() => typeof appInsights.client) // allow factory function for testing
) {
if (!this._defaultData) {
this._defaultData = Object.create(null);
}
if (typeof aiKeyOrClientFactory === 'string') {
this._aiClient = AI.getClient(aiKeyOrClientFactory);
} else if (typeof aiKeyOrClientFactory === 'function') {
this._aiClient = aiKeyOrClientFactory();
}
}
private static _getData(data?: any): { properties: Properties, measurements: Measurements } {
const properties: Properties = Object.create(null);
const measurements: Measurements = Object.create(null);
const flat = Object.create(null);
AIAdapter._flaten(data, flat);
for (let prop in flat) {
// enforce property names less than 150 char, take the last 150 char
prop = prop.length > 150 ? prop.substr(prop.length - 149) : prop;
var value = flat[prop];
if (typeof value === 'number') {
measurements[prop] = value;
} else if (typeof value === 'boolean') {
measurements[prop] = value ? 1 : 0;
} else if (typeof value === 'string') {
//enforce property value to be less than 1024 char, take the first 1024 char
properties[prop] = value.substring(0, 1023);
} else if (typeof value !== 'undefined' && value !== null) {
properties[prop] = value;
}
}
return {
properties,
measurements
};
}
private static _flaten(obj: any, result: {[key: string]: any }, order: number = 0, prefix?: string): void {
if (!obj) {
return;
}
for(var item of Object.getOwnPropertyNames(obj)){
const value = obj[item];
const index = prefix ? prefix + item : item;
if (Array.isArray(value)) {
result[index] = safeStringify(value);
} else if (value instanceof Date) {
// TODO unsure why this is here and not in _getData
result[index] = value.toISOString();
} else if (isObject(value)) {
if (order < 2) {
AIAdapter._flaten(value, result, order + 1, index + '.');
} else {
result[index] = safeStringify(value);
}
} else {
result[index] = value;
}
}
}
public log(eventName: string, data?: any): void {
if (!this._aiClient) {
return;
}
data = mixin(data, this._defaultData);
let {properties, measurements} = AIAdapter._getData(data);
this._aiClient.trackEvent(this._eventPrefix + '/' + eventName, properties, measurements);
}
public dispose(): TPromise<any> {
if (this._aiClient) {
return new TPromise(resolve => {
this._aiClient.sendPendingData(() => {
// all data flushed
this._aiClient = undefined;
resolve(void 0);
});
});
}
}
}

View file

@ -5,7 +5,7 @@
import { ChildProcess, fork } from 'child_process';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Promise} from 'vs/base/common/winjs.base';
import { TPromise, Promise} from 'vs/base/common/winjs.base';
import { Delayer } from 'vs/base/common/async';
import { clone, assign } from 'vs/base/common/objects';
import { Server as IPCServer, Client as IPCClient, IClient, IChannel } from 'vs/base/parts/ipc/common/ipc';
@ -58,15 +58,13 @@ export class Client implements IClient, IDisposable {
private disposeDelayer: Delayer<void>;
private activeRequests: Promise[];
private child: ChildProcess;
private _client: IPCClient;
private channels: { [name: string]: IChannel };
private _client: TPromise<[IPCClient, ChildProcess]>;
private channels: { [name: string]: TPromise<IChannel> };
constructor(private modulePath: string, private options: IIPCOptions) {
const timeout = options && options.timeout ? options.timeout : 60000;
this.disposeDelayer = new Delayer<void>(timeout);
this.activeRequests = [];
this.child = null;
this._client = null;
this.channels = Object.create(null);
}
@ -79,8 +77,8 @@ export class Client implements IClient, IDisposable {
protected request(channelName: string, name: string, arg: any): Promise {
this.disposeDelayer.cancel();
const channel = this.channels[channelName] || (this.channels[channelName] = this.client.getChannel(channelName));
const request: Promise = channel.call(name, arg);
const channel = this.channels[channelName] || (this.channels[channelName] = this.client.then(value => value[0].getChannel(channelName)));
const request: Promise = channel.then(channel => channel.call(name, arg));
// Progress doesn't propagate across 'then', we need to create a promise wrapper
const result = new Promise((c, e, p) => {
@ -98,72 +96,78 @@ export class Client implements IClient, IDisposable {
return result;
}
private get client(): IPCClient {
private get client(): TPromise<[IPCClient, ChildProcess]> {
if (!this._client) {
const args = this.options && this.options.args ? this.options.args : [];
let forkOpts:any = undefined;
this._client = TPromise.timeout(0).then(() => { // since fork is expensive and we end up here often
// during startup, we do a timeout(0) which is a setImmediate
if (this.options) {
forkOpts = Object.create(null);
const args = this.options && this.options.args ? this.options.args : [];
let forkOpts:any = undefined;
if (this.options.env) {
forkOpts.env = assign(clone(process.env), this.options.env);
if (this.options) {
forkOpts = Object.create(null);
if (this.options.env) {
forkOpts.env = assign(clone(process.env), this.options.env);
}
if (typeof this.options.debug === 'number') {
forkOpts.execArgv = ['--nolazy', '--debug=' + this.options.debug];
}
if (typeof this.options.debugBrk === 'number') {
forkOpts.execArgv = ['--nolazy', '--debug-brk=' + this.options.debugBrk];
}
}
if (typeof this.options.debug === 'number') {
forkOpts.execArgv = ['--nolazy', '--debug=' + this.options.debug];
}
const child = fork(this.modulePath, args, forkOpts);
const client = new IPCClient({
send: r => child && child.connected && child.send(r),
onMessage: cb => {
child.on('message', (msg) => {
if (typeof this.options.debugBrk === 'number') {
forkOpts.execArgv = ['--nolazy', '--debug-brk=' + this.options.debugBrk];
}
}
// Handle console logs specially
if (msg && msg.type === '__$console') {
let args = ['%c[IPC Library: ' + this.options.serverName + ']', 'color: darkgreen'];
try {
const parsed = JSON.parse(msg.arguments);
args = args.concat(Object.getOwnPropertyNames(parsed).map(o => parsed[o]));
} catch (error) {
args.push(msg.arguments);
}
this.child = fork(this.modulePath, args, forkOpts);
this._client = new IPCClient({
send: r => this.child && this.child.connected && this.child.send(r),
onMessage: cb => {
this.child.on('message', (msg) => {
// Handle console logs specially
if (msg && msg.type === '__$console') {
let args = ['%c[IPC Library: ' + this.options.serverName + ']', 'color: darkgreen'];
try {
const parsed = JSON.parse(msg.arguments);
args = args.concat(Object.getOwnPropertyNames(parsed).map(o => parsed[o]));
} catch (error) {
args.push(msg.arguments);
console[msg.severity].apply(console, args);
}
console[msg.severity].apply(console, args);
}
// Anything else goes to the outside
else {
cb(msg);
}
});
}
});
// Anything else goes to the outside
else {
cb(msg);
}
});
}
});
const onExit = () => this.disposeClient();
process.once('exit', onExit);
const onExit = () => this.disposeClient();
process.once('exit', onExit);
child.on('error', err => console.warn('IPC "' + this.options.serverName + '" errored with ' + err));
this.child.on('error', err => console.warn('IPC "' + this.options.serverName + '" errored with ' + err));
child.on('exit', (code: any, signal: any) => {
process.removeListener('exit', onExit);
this.child.on('exit', (code: any, signal: any) => {
process.removeListener('exit', onExit);
if (this.activeRequests) {
this.activeRequests.forEach(req => req.cancel());
this.activeRequests = [];
}
if (this.activeRequests) {
this.activeRequests.forEach(req => req.cancel());
this.activeRequests = [];
}
if (code && signal !== 'SIGTERM') {
console.warn('IPC "' + this.options.serverName + '" crashed with exit code ' + code);
this.disposeDelayer.cancel();
this.disposeClient();
}
});
if (code && signal !== 'SIGTERM') {
console.warn('IPC "' + this.options.serverName + '" crashed with exit code ' + code);
this.disposeDelayer.cancel();
this.disposeClient();
}
return [client, child];
});
}
@ -172,10 +176,12 @@ export class Client implements IClient, IDisposable {
private disposeClient() {
if (this._client) {
this.child.kill();
this.child = null;
this._client = null;
this._client.done(value => {
let [, child] = value;
child.kill();
});
this.channels = Object.create(null);
this._client = null;
}
}

View file

@ -27,6 +27,7 @@ import DOM = require('vs/base/browser/dom');
import {IActionProvider} from 'vs/base/parts/tree/browser/actionsRenderer';
import {KeyCode} from 'vs/base/common/keyCodes';
import {IDisposable,dispose} from 'vs/base/common/lifecycle';
import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
export interface IQuickOpenCallbacks {
onOk: () => void;
@ -190,7 +191,7 @@ export class QuickOpenWidget implements IModelProvider {
twistiePixels: 11,
indentPixels: 0,
alwaysFocused: true,
verticalScrollMode: 'visible',
verticalScrollMode: ScrollbarVisibility.Visible,
ariaLabel: nls.localize('treeAriaLabel', "Quick Picker")
});

View file

@ -10,6 +10,7 @@ import Events = require('vs/base/common/eventEmitter');
import Mouse = require('vs/base/browser/mouseEvent');
import Keyboard = require('vs/base/browser/keyboardEvent');
import { INavigator } from 'vs/base/common/iterator';
import { ScrollbarVisibility } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
export interface ITree extends Events.IEventEmitter {
@ -614,8 +615,7 @@ export interface ITreeConfiguration {
export interface ITreeOptions {
twistiePixels?: number;
indentPixels?: number;
horizontalScrollMode?: string;
verticalScrollMode?: string;
verticalScrollMode?: ScrollbarVisibility;
alwaysFocused?: boolean;
autoExpandSingleChildren?: boolean;
bare?:boolean;

View file

@ -17,7 +17,8 @@ import Keyboard = require('vs/base/browser/keyboardEvent');
import Model = require('vs/base/parts/tree/browser/treeModel');
import dnd = require('./treeDnd');
import { ArrayIterator, MappedIterator } from 'vs/base/common/iterator';
import ScrollableElementImpl = require('vs/base/browser/ui/scrollbar/scrollableElement');
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
import { HeightMap } from 'vs/base/parts/tree/browser/treeViewModel';
import _ = require('vs/base/parts/tree/browser/tree');
import { IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
@ -407,7 +408,7 @@ export class TreeView extends HeightMap {
private domNode: HTMLElement;
private wrapper: HTMLElement;
private rowsContainer: HTMLElement;
private scrollableElement: ScrollableElementImpl.ScrollableElement;
private scrollableElement: ScrollableElement;
private wrapperGesture: Touch.Gesture;
private msGesture: MSGesture;
private lastPointerType:string;
@ -486,10 +487,10 @@ export class TreeView extends HeightMap {
this.wrapper = document.createElement('div');
this.wrapper.className = 'monaco-tree-wrapper';
this.scrollableElement = new ScrollableElementImpl.ScrollableElement(this.wrapper, {
forbidTranslate3dUse: true,
horizontal: 'hidden',
vertical: context.options.verticalScrollMode || 'auto',
this.scrollableElement = new ScrollableElement(this.wrapper, {
canUseTranslate3d: false,
horizontal: ScrollbarVisibility.Hidden,
vertical: (typeof context.options.verticalScrollMode !== 'undefined' ? context.options.verticalScrollMode : ScrollbarVisibility.Auto),
useShadows: context.options.useShadows,
saveLastScrollTimeOnClassName: 'monaco-tree-row'
});

View file

@ -19,35 +19,29 @@ suite('Browsers', () => {
var isChrome = browser.isChrome;
var isSafari = browser.isSafari;
var canPushState = browser.canPushState();
var hasCSSAnimations = browser.hasCSSAnimationSupport();
var browserCount = 0;
if (isOpera) {
browserCount++;
assert(canPushState);
}
if (isIE11orEarlier) {
browserCount++;
}
if (isFirefox) {
browserCount++;
assert(canPushState);
assert(hasCSSAnimations);
}
if (isWebKit) {
browserCount++;
assert(canPushState);
assert(hasCSSAnimations);
}
if (isChrome) {
browserCount++;
assert(canPushState);
assert(hasCSSAnimations);
}
if (isSafari) {
browserCount++;
assert(canPushState);
assert(hasCSSAnimations);
}
});

View file

@ -1,28 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import BrowserService = require('vs/base/browser/browserService');
import { MockBrowserServiceData } from 'vs/base/test/browser/mockBrowserService';
suite('BrowserService', () => {
test('Mocking of Window', () => {
try {
var service = BrowserService.getService();
service.mock(new MockBrowserServiceData());
var w = <any> service.window;
w.testValue = 42;
service.restore();
w = <any> service.window;
assert.strictEqual(w.testValue, undefined);
}
finally {
if(service) {
service.restore();
}
}
});
});

View file

@ -1,28 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { MockDocument, MockWindow, MockElement } from 'vs/base/test/browser/mockDom';
import browserService = require('vs/base/browser/browserService');
function mockedIsHTMLElement(o:any): boolean {
if (typeof HTMLElement === 'object') {
return o instanceof HTMLElement || o instanceof MockElement;
}
return o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string';
}
export class MockBrowserServiceData implements browserService.IBrowserServiceData {
public document:Document;
public window:Window;
public isHTMLElement: (o:any)=>boolean;
constructor() {
this.document = <any> new MockDocument();
this.window = <any> new MockWindow();
this.isHTMLElement = mockedIsHTMLElement;
}
}

View file

@ -1,73 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import MockDom = require('vs/base/test/browser/mockDom');
suite('MockDom', () => {
test('Create Element', () => {
var doc = new MockDom.MockDocument();
var div = doc.createElement('div');
div.textContent = 'test';
assert.strictEqual(div.textContent, 'test');
assert.strictEqual(div.tagName, 'div');
});
test('Events', () => {
var doc = new MockDom.MockDocument();
var div = doc.createElement('div');
var fakeEvent = <Event>{ type: 'test'};
var count = 0;
var callback = function(event:any) {
assert.strictEqual(event, fakeEvent);
count++;
};
div.addEventListener('test', callback);
div.dispatchEvent(fakeEvent);
assert.strictEqual(count, 1);
div.removeEventListener('test', callback);
div.dispatchEvent(fakeEvent);
assert.strictEqual(count, 1);
});
test('Create elements via innerHTML', () => {
var doc = new MockDom.MockDocument();
var div = doc.createElement('div');
div.innerHTML = '<div id="testId"><span class="testClass">test</span></div>';
assert.strictEqual(div.children.length, 1);
assert.strictEqual(div.childNodes[0], div.children[0]);
assert.strictEqual(div.children[0], div.firstElementChild);
assert.strictEqual(div.firstElementChild, div.firstChild);
var child = <HTMLElement> div.children[0];
assert.strictEqual(child.id, 'testId');
assert.strictEqual(child.getAttribute('id'), 'testId');
assert.strictEqual(child.childElementCount, 1);
var grandchild = <HTMLElement> child.firstElementChild;
assert.strictEqual(grandchild.tagName, 'span');
assert.strictEqual(grandchild.className, 'testClass');
assert.strictEqual(grandchild.textContent, 'test');
});
test('Convert elements to innerHTML', () => {
var doc = new MockDom.MockDocument();
var div = doc.createElement('div');
var child = doc.createElement('div');
child.id = 'testId';
var grandchild = doc.createElement('span');
grandchild.className = 'testClass';
grandchild.textContent = 'test';
child.appendChild(grandchild);
div.appendChild(child);
assert.strictEqual(div.innerHTML, '<div id="testId"><span class="testClass">test</span></div>');
assert.strictEqual(div.outerHTML, '<div><div id="testId"><span class="testClass">test</span></div></div>');
});
});

View file

@ -1,914 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
interface IEventMap {
[name: string]: EventListener[];
}
export class MockEventTarget implements EventTarget {
private eventMap:IEventMap;
constructor() {
this.eventMap = {};
}
removeEventListener(type: string, listener: EventListener, useCapture?: boolean): void {
if(type in this.eventMap) {
var a = this.eventMap[type];
a.splice(a.indexOf(listener), 1);
}
}
addEventListener(type: string, listener: EventListener, useCapture?: boolean): void {
if(type in this.eventMap) {
this.eventMap[type].push(listener);
}
else {
this.eventMap[type] = [listener];
}
}
dispatchEvent(evt: Event): boolean {
var listeners = this.eventMap[evt.type];
if (listeners) {
listeners.forEach((listener) => {
listener(evt);
});
}
return evt.defaultPrevented;
}
}
export class MockNode extends MockEventTarget implements Node {
// Added to make compiler happy. No real mocking
classList: DOMTokenList;
baseURI: string;
parentElement: HTMLElement;
nodeType: number;
previousSibling: Node;
localName: string;
namespaceURI: string;
parentNode: Node;
nextSibling: Node;
nodeValue: string;
public _childNodes: Node[];
nodeName: string;
ownerDocument: Document;
_attributes: Attr[];
prefix: string;
constructor(name:string) {
super();
this.nodeName = name;
this._childNodes = [];
this._attributes = [];
}
public get attributes(): NamedNodeMap {
return <any> this._attributes;
}
public get lastChild(): Node {
return this._childNodes[this._childNodes.length - 1];
}
public get firstChild(): Node {
return this._childNodes[0];
}
public get childNodes(): NodeList {
var a = <any>this._childNodes;
if(!a.item) {
a.item = (function(index:number) {
return this[index];
}).bind(a);
}
return a;
}
public get textContent(): string {
return this._childNodes.filter((node) => {
return node.nodeType === this.TEXT_NODE;
}).map((node) => {
return (<Text>node).wholeText;
}).join('');
}
public set textContent(value:string) {
this._childNodes = [];
this.appendChild(this.ownerDocument.createTextNode(value));
}
public removeChild(oldChild: Node): Node {
var i = this._childNodes.indexOf(oldChild);
if(i >= 0) {
var removed = this._childNodes.splice(i, 1);
return removed[0];
}
return null;
}
public contains(node: Node): boolean {
return this._childNodes.indexOf(node) !== -1;
}
appendChild(newChild: Node): Node {
this._childNodes.push(newChild);
return newChild;
}
isSupported(feature: string, version: string): boolean {
throw new Error('Not implemented!');
}
isEqualNode(arg: Node): boolean {
throw new Error('Not implemented!');
}
lookupPrefix(namespaceURI: string): string {
throw new Error('Not implemented!');
}
isDefaultNamespace(namespaceURI: string): boolean {
throw new Error('Not implemented!');
}
compareDocumentPosition(other: Node): number {
throw new Error('Not implemented!');
}
normalize(): void {
throw new Error('Not implemented!');
}
isSameNode(other: Node): boolean {
return this === other;
}
hasAttributes(): boolean {
return this.attributes.length > 0;
}
lookupNamespaceURI(prefix: string): string {
throw new Error('Not implemented!');
}
cloneNode(deep?: boolean): Node {
throw new Error('Not implemented!');
}
hasChildNodes(): boolean {
return this.childNodes.length > 0;
}
replaceChild(newChild: Node, oldChild: Node): Node {
throw new Error('Not implemented!');
}
insertBefore(newChild: Node, refChild?: Node): Node {
throw new Error('Not implemented!');
}
ENTITY_REFERENCE_NODE: number = Node.ENTITY_REFERENCE_NODE;
ATTRIBUTE_NODE: number = Node.ATTRIBUTE_NODE;
DOCUMENT_FRAGMENT_NODE: number = Node.DOCUMENT_FRAGMENT_NODE;
TEXT_NODE: number = Node.TEXT_NODE;
ELEMENT_NODE: number = Node.ELEMENT_NODE;
COMMENT_NODE: number = Node.COMMENT_NODE;
DOCUMENT_POSITION_DISCONNECTED: number = Node.DOCUMENT_POSITION_DISCONNECTED;
DOCUMENT_POSITION_CONTAINED_BY: number = Node.DOCUMENT_POSITION_CONTAINED_BY;
DOCUMENT_POSITION_CONTAINS: number = Node.DOCUMENT_POSITION_CONTAINS;
DOCUMENT_TYPE_NODE: number = Node.DOCUMENT_TYPE_NODE;
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number = Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
DOCUMENT_NODE: number = Node.DOCUMENT_NODE;
ENTITY_NODE: number = Node.ENTITY_NODE;
PROCESSING_INSTRUCTION_NODE: number = Node.PROCESSING_INSTRUCTION_NODE;
CDATA_SECTION_NODE: number = Node.CDATA_SECTION_NODE;
NOTATION_NODE: number = Node.NOTATION_NODE;
DOCUMENT_POSITION_FOLLOWING: number = Node.DOCUMENT_POSITION_FOLLOWING;
DOCUMENT_POSITION_PRECEDING: number = Node.DOCUMENT_POSITION_PRECEDING;
}
export class MockAttribute extends MockNode implements Attr {
ownerElement: Element;
value: string;
name: string;
// MSAttrExtensions
expando: boolean;
constructor(name:string) {
super(name);
this.name = name;
this.expando = false;
}
public get specified(): boolean {
return !!this.value;
}
}
export interface ClientRect {
left: number;
width: number;
right: number;
top: number;
bottom: number;
height: number;
}
export class MockElement extends MockNode implements Element {
// Added to make compiler happy. No real mocking
classList: DOMTokenList;
id: string;
className: string;
scrollTop: number;
clientLeft: number;
scrollLeft: number;
tagName: string;
clientWidth: number;
scrollWidth: number;
clientHeight: number;
clientTop: number;
scrollHeight: number;
constructor(tagName: string) {
super(tagName);
this.tagName = tagName;
}
getAttribute(name?: string): string {
var filter = this._attributes.filter((attr) => {
return attr.name === name;
});
return filter.length ? filter[0].value : '';
}
get innerHTML(): string {
throw new Error('Not implemented!');
}
set innerHTML(value: string) {
throw new Error('Not implemented!');
}
getElementsByTagNameNS(namespaceURI: string, localName: string): NodeListOf<Element> {
throw new Error('Not implemented!');
}
getElementsByClassName(classNames: string): NodeListOf<Element> {
throw new Error('Not implemented!');
}
hasAttributeNS(namespaceURI: string, localName: string): boolean {
throw new Error('Not implemented!');
}
getBoundingClientRect(): ClientRect {
throw new Error('Not implemented!');
}
getAttributeNS(namespaceURI: string, localName: string): string {
throw new Error('Not implemented!');
}
getAttributeNodeNS(namespaceURI: string, localName: string): Attr {
throw new Error('Not implemented!');
}
setAttributeNodeNS(newAttr: Attr): Attr {
throw new Error('Not implemented!');
}
hasAttribute(name: string): boolean {
var filter = this._attributes.filter((attr) => {
return attr.name === name;
});
return filter.length > 0;
}
removeAttribute(name?: string): void {
this._attributes = this._attributes.filter((attr) => {
return attr.name !== name;
});
}
setAttributeNS(namespaceURI: string, qualifiedName: string, value: string): void {
throw new Error('Not implemented!');
}
getAttributeNode(name: string): Attr {
throw new Error('Not implemented!');
}
getElementsByTagName(name: string): NodeListOf<Element> {
throw new Error('Not implemented!');
}
setAttributeNode(newAttr: Attr): Attr {
throw new Error('Not implemented!');
}
getClientRects(): ClientRectList {
throw new Error('Not implemented!');
}
removeAttributeNode(oldAttr: Attr): Attr {
throw new Error('Not implemented!');
}
setAttribute(name?: string, value?: string): void {
if(this.hasAttribute(name)) {
this.removeAttribute(name);
}
var attr = this.ownerDocument.createAttribute(name);
attr.ownerElement = this;
attr.value = value;
this._attributes.push(attr);
}
removeAttributeNS(namespaceURI: string, localName: string): void {
throw new Error('Not implemented!');
}
matches(selector: string): boolean {
throw new Error('Not implemented!');
}
// interface NodeSelector
querySelectorAll(selectors: string): NodeListOf<Element> {
throw new Error('Not implemented!');
}
querySelector(selectors: string): Element {
throw new Error('Not implemented!');
}
// interface ElementTraversal
public get childElementCount(): number {
return this._childNodes.filter((node) => {
return node.nodeType === this.ELEMENT_NODE;
}).length;
}
previousElementSibling: Element;
public get lastElementChild(): Element {
var a = this._childNodes.filter((node) => {
return node.nodeType === this.ELEMENT_NODE;
});
return <any>a[a.length - 1];
}
nextElementSibling: Element;
public get firstElementChild(): Element {
var a = this._childNodes.filter((node) => {
return node.nodeType === this.ELEMENT_NODE;
});
return <any>a[0];
}
// interface MSElementExtensions
msMatchesSelector(selectors: string): boolean {
throw new Error('Not implemented!');
}
fireEvent(eventName: string, eventObj?: any): boolean {
throw new Error('Not implemented!');
}
// other interface msElementExtensions
msZoomTo(args: any) {}
msRequestFullscreen() {}
msGetUntransformedBounds():ClientRect {
throw new Error('Not implemented!');
}
msRegionOverflow: string;
requestFullscreen(): void { throw new Error('Not implemented!'); }
requestPointerLock(): void { throw new Error('Not implemented!'); }
webkitMatchesSelector(selectors: string): boolean { throw new Error('Not implemented!'); }
webkitRequestFullScreen(): void { throw new Error('Not implemented!'); }
webkitRequestFullscreen(): void { throw new Error('Not implemented!'); }
remove(): void { throw new Error('Not implemented!'); }
onariarequest: (ev: any) => any;
oncommand: (ev: any) => any;
// Pointer events new in IE 11
onlostpointercapture: (ev: any) => any;
ongotpointercapture: (ev: any) => any;
setPointerCapture: (ev: any) => any;
releasePointerCapture: (ev: any) => any;
onpointerenter: (ev: any) => any;
onpointerout: (ev: any) => any;
onpointerdown: (ev: any) => any;
onpointerup: (ev: any) => any;
onpointercancel: (ev: any) => any;
onpointerover: (ev: any) => any;
onpointermove: (ev: any) => any;
onpointerleave: (ev: any) => any;
onwheel: (ev: any) => any;
ontouchcancel: (ev: any) => any;
ontouchend: (ev: any) => any;
ontouchmove: (ev: any) => any;
ontouchstart: (ev: any) => any;
onmspointerenter: (ev:any) => any;
onmspointerleave: (ev:any) => any;
onmspointerdown: (ev: any) => any;
onmsgotpointercapture: (ev: any) => any;
onmsgesturedoubletap: (ev: any) => any;
onmspointerhover: (ev: any) => any;
onmsgesturehold: (ev: any) => any;
onmspointermove: (ev: any) => any;
onmsgesturechange: (ev: any) => any;
onmsgesturestart: (ev: any) => any;
onmspointercancel: (ev: any) => any;
onmsgestureend: (ev: any) => any;
onmsgesturetap: (ev: any) => any;
onmspointerout: (ev: any) => any;
onmsinertiastart: (ev: any) => any;
onmslostpointercapture: (ev: any) => any;
onmspointerover: (ev: any) => any;
msContentZoomFactor: number;
onmspointerup: (ev: any) => any;
onwebkitfullscreenchange: (ev: Event) => any;
onwebkitfullscreenerror: (ev: Event) => any;
msGetRegionContent(): MSRangeCollection {
throw new Error('Not implemented!');
}
msReleasePointerCapture(pointerId: number): void {
throw new Error('Not implemented!');
}
msSetPointerCapture(pointerId: number): void {
throw new Error('Not implemented!');
}
}
export class MockCharacterData extends MockNode implements CharacterData {
length: number;
data: string;
constructor(text:string) {
super(text);
this.nodeType = this.TEXT_NODE;
this.length = text.length;
this.data = text;
}
deleteData(offset: number, count: number): void {
throw new Error('Not implemented!');
}
replaceData(offset: number, count: number, arg: string): void {
throw new Error('Not implemented!');
}
appendData(arg: string): void {
throw new Error('Not implemented!');
}
insertData(offset: number, arg: string): void {
throw new Error('Not implemented!');
}
substringData(offset: number, count: number): string {
throw new Error('Not implemented!');
}
remove(): void { throw new Error('Not implemented!'); }
}
export class MockText extends MockCharacterData implements Text {
wholeText: string;
constructor(text:string) {
super(text);
this.wholeText = text;
}
splitText(offset: number): Text {
throw new Error('Not implemented!');
}
replaceWholeText(content: string): Text {
throw new Error('Not implemented!');
}
swapNode(otherNode: Node): Node {
throw new Error('Not implemented!');
}
removeNode(deep?: boolean): Node {
throw new Error('Not implemented!');
}
replaceNode(replacement: Node): Node {
throw new Error('Not implemented!');
}
}
export class MockHTMLElement extends MockElement /* implements HTMLElement */ {
public style: CSSStyleDeclaration;
constructor(tagName: string) {
super(tagName);
this.style = <any> {};
this.nodeType = this.ELEMENT_NODE;
}
public get className(): string {
return this.getAttribute('class');
}
public set className(value:string) {
this.setAttribute('class', value);
}
public get id():string {
return this.getAttribute('id');
}
public set id(value:string) {
this.setAttribute('id', value);
}
public get children(): HTMLCollection {
var a = <any> this._childNodes.filter((node) => {
return node.nodeType === this.ELEMENT_NODE;
});
if(!a.item) {
a.item = (function(index:number) {
return this[index];
}).bind(a);
}
return a;
}
get outerHTML(): string {
var stringer = new DOMStringer(this);
return stringer.toString(true);
}
get innerHTML(): string {
var stringer = new DOMStringer(this);
return stringer.toString();
}
set innerHTML(value:string) {
var parser = new DOMParser(this.ownerDocument);
var nodes = parser.parse(value);
nodes.forEach((node) => {
this.appendChild(node);
});
}
}
export class MockDocument extends MockEventTarget /*implements Document*/ {
public createElement(tagName: string): HTMLElement {
var e = new MockHTMLElement(tagName);
e.ownerDocument = <any> this;
return <any> e;
}
public createTextNode(data: string): Text {
var n = new MockText(data);
n.ownerDocument = <any> this;
return n;
}
public createAttribute(name: string): Attr {
var a = new MockAttribute(name);
a.ownerDocument = <any> this;
return a;
}
}
export class MockWindow /*implements Window*/ {
}
interface IParserState {
name: string;
consumeCharacter(stream:StringStream):IParserState;
onTransition(parser:DOMParser, nextState:string):void;
}
class ErrorState implements IParserState {
public name: string;
public message:string;
constructor(message:string) {
this.name = 'error';
this.message = message;
}
consumeCharacter(stream:StringStream):IParserState {
return this;
}
onTransition(parser:DOMParser, nextState:string):void {
}
}
class TextParser implements IParserState {
public name: string;
private textContent: string;
constructor() {
this.name = 'text';
this.textContent = '';
}
consumeCharacter(stream:StringStream):IParserState {
var char = stream.next();
switch(char) {
case '<':
return new TagParser();
case '>':
return new ErrorState('Unexpected >');
default:
this.textContent += char;
return this;
}
}
onTransition(parser:DOMParser, nextState:string):void {
if(this.textContent) {
var node = parser.document.createTextNode(this.textContent);
if(parser.currentNode) {
parser.currentNode.appendChild(node);
} else {
parser.root.push(node);
}
}
}
}
interface IMap {
[name: string]:string;
}
class TagParser implements IParserState {
public name: string;
private isClosing:boolean;
private tagName:string;
public attributes: IMap;
constructor() {
this.name = 'tag';
this.tagName = '';
this.isClosing = false;
this.attributes = {};
}
consumeCharacter(stream:StringStream):IParserState {
var char = stream.next();
switch(char) {
case '/':
this.isClosing = true;
return this;
case '>':
if(this.tagName) {
return new TextParser();
}
else {
return new ErrorState('No tag name specified');
}
case ' ':
if(this.tagName) {
if(this.isClosing) {
return new ErrorState('Closing tags cannot have attributes');
}
return new AttributeParser(this);
} else {
return new ErrorState('Tag name must be first.');
}
default:
this.tagName += char;
return this;
}
}
onTransition(parser:DOMParser, nextState:string):void {
if(this.tagName && nextState !== 'attribute') {
if(this.isClosing) {
if(parser.openElements[parser.openElements.length - 1].tagName !== this.tagName) {
throw new Error('Mismatched closing tag:' + this.tagName);
} else {
parser.openElements.pop();
if(parser.openElements.length) {
parser.currentNode = parser.openElements[parser.openElements.length - 1];
} else {
parser.currentNode = null;
}
}
} else {
var node = parser.document.createElement(this.tagName);
Object.keys(this.attributes).forEach((key) => {
node.setAttribute(key, this.attributes[key]);
});
if(parser.currentNode) {
parser.currentNode.appendChild(node);
} else {
parser.root.push(node);
}
parser.openElements.push(node);
parser.currentNode = node;
}
}
}
}
class AttributeParser implements IParserState {
public name: string;
private tag: TagParser;
private attributeName:string;
public attributeValue:string;
private inValue:boolean;
constructor(tag: TagParser) {
this.name = 'attribute';
this.tag = tag;
this.inValue = false;
this.attributeName = '';
}
consumeCharacter(stream:StringStream):IParserState {
var char = stream.next();
switch(char) {
case ' ':
if(this.inValue) {
return this.tag;
} else {
return this;
}
case '=':
this.inValue = true;
return new AttributeValueParser(this);
case '>':
stream.back();
return this.tag;
default:
if(this.inValue === false) {
this.attributeName += char;
}
return this;
}
}
onTransition(parser:DOMParser, nextState:string):void {
if(nextState !== 'attributeValue') {
this.tag.attributes[this.attributeName] = this.attributeValue;
}
}
}
class AttributeValueParser implements IParserState {
public name: string;
private attribute: AttributeParser;
private value:string;
private quote:boolean;
constructor(attribute:AttributeParser) {
this.name = 'attributeValue';
this.attribute = attribute;
this.value = '';
this.quote = false;
}
consumeCharacter(stream:StringStream):IParserState {
var char = stream.next();
switch(char) {
case '"':
if(this.quote === false) {
this.quote = true;
return this;
}
else {
return this.attribute;
}
default:
if(this.quote === false) {
return new ErrorState('Expected " character');
} else {
this.value += char;
}
return this;
}
}
onTransition(parser:DOMParser, nextState:string):void {
this.attribute.attributeValue = this.value;
}
}
class StringStream {
private text: string;
private index = 0;
constructor(text:string) {
this.text = text;
}
public more():boolean {
return this.index < this.text.length;
}
public next():string {
if(this.index >= this.text.length) {
throw new Error('Past end of string!');
}
return this.text[this.index++];
}
public back() {
this.index--;
}
}
class DOMParser {
public activeState: IParserState;
public currentNode: Node;
public openElements: Element[];
public root:Node[];
public document:Document;
constructor(document:Document) {
this.document = document;
this.root = [];
this.openElements = [];
this.currentNode = null;
this.activeState = new TextParser();
}
public parse(text:string):Node[] {
var stream = new StringStream(text);
while(stream.more()) {
var nextState = this.activeState.consumeCharacter(stream);
if(nextState !== this.activeState) {
this.activeState.onTransition(this, nextState.name);
this.activeState = nextState;
}
}
if(this.activeState.name === 'error') {
throw new Error((<ErrorState> this.activeState).message);
}
if(this.openElements.length !== 0) {
throw new Error('Elements not closed: ' + this.openElements.map((element) => {
return element.tagName;
}).join());
}
return this.root;
}
}
class DOMStringer {
private root:Node;
constructor(root:Node) {
this.root = root;
}
private print(node:Node):string {
var result = '';
switch(node.nodeType) {
case node.ELEMENT_NODE:
result += this.printElement(<any>node);
break;
case node.TEXT_NODE:
result += this.printText(<any>node);
break;
}
return result;
}
private printChildren(node:Node):string {
var result = '';
if(node.hasChildNodes()) {
for(var i = 0; i < node.childNodes.length; i++) {
result += this.print(node.childNodes.item(i));
}
}
return result;
}
private printElement(element:Element):string {
var result = ['<'];
result.push(element.tagName);
if(element.hasAttributes()) {
var attributes:Attr[] = <any>element.attributes;
result.push(attributes.reduce((prev:string, current:Attr) => {
var attr = [prev, current.name];
if(current.value) {
attr.push('="', current.value, '"');
}
return attr.join('');
}, ' '));
}
result.push('>');
result.push(this.printChildren(element));
result.push('</');
result.push(element.tagName);
result.push('>');
return result.join('');
}
private printText(text:Text):string {
return text.wholeText;
}
public toString(includeRoot?:boolean):string {
if(includeRoot) {
return this.print(this.root);
} else {
return this.printChildren(this.root);
}
}
}

View file

@ -5,7 +5,8 @@
'use strict';
import * as assert from 'assert';
import { SyntaxKind, createScanner, parse } from 'vs/base/common/json';
import { SyntaxKind, createScanner, parse, getLocation, Node, ParseError, parseTree, ParseErrorCode,
getParseErrorMessage, ParseOptions, Segment, findNodeAtLocation, getNodeValue } from 'vs/base/common/json';
function assertKinds(text:string, ...kinds:SyntaxKind[]):void {
var _json = createScanner(text);
@ -17,24 +18,60 @@ function assertKinds(text:string, ...kinds:SyntaxKind[]):void {
}
function assertValidParse(input:string, expected:any) : void {
var errors : string[] = [];
var actual = parse(input, errors);
function assertValidParse(input:string, expected:any, options?: ParseOptions) : void {
var errors : {error: ParseErrorCode}[] = [];
var actual = parse(input, errors, options);
if (errors.length !== 0) {
assert(false, errors[0]);
assert(false, getParseErrorMessage(errors[0].error));
}
assert.deepEqual(actual, expected);
}
function assertInvalidParse(input:string, expected:any) : void {
var errors : string[] = [];
var actual = parse(input, errors);
function assertInvalidParse(input:string, expected:any, options?: ParseOptions) : void {
var errors : {error: ParseErrorCode}[] = [];
var actual = parse(input, errors, options);
assert(errors.length > 0);
assert.deepEqual(actual, expected);
}
function assertTree(input:string, expected:any) : void {
var errors : ParseError[] = [];
var actual = parseTree(input, errors);
assert.equal(errors.length, 0);
let checkParent = (node: Node) => {
if (node.children) {
for (let child of node.children) {
assert.equal(node, child.parent);
delete child.parent; // delete to avoid recursion in deep equal
checkParent(child);
}
}
}
checkParent(actual);
assert.deepEqual(actual, expected);
}
function assertNodeAtLocation(input:Node, segments: Segment[], expected: any) {
let actual = findNodeAtLocation(input, segments);
assert.deepEqual(actual ? getNodeValue(actual) : void 0, expected);
}
function assertLocation(input:string, expectedSegments: Segment[], expectedNodeType: string, expectedCompleteProperty: boolean) : void {
var errors : {error: ParseErrorCode}[] = [];
var offset = input.indexOf('|');
input = input.substring(0, offset) + input.substring(offset+1, input.length);
var actual = getLocation(input, offset);
assert(actual);
assert.deepEqual(actual.path, expectedSegments, input);
assert.equal(actual.previousNode && actual.previousNode.type, expectedNodeType, input);
assert.equal(actual.isAtPropertyKey, expectedCompleteProperty, input);
}
suite('JSON', () => {
test('tokens', () => {
assertKinds('{', SyntaxKind.OpenBraceToken);
@ -147,7 +184,7 @@ suite('JSON', () => {
assertValidParse('23e3', 23e3);
assertValidParse('1.2E+3', 1.2E+3);
assertValidParse('1.2E-3', 1.2E-3);
assertValidParse('1.2E-3 // comment', 1.2E-3);
});
test('parse: objects', () => {
@ -157,6 +194,9 @@ suite('JSON', () => {
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} });
assertValidParse('{ "a": false, "b": true, "c": [ 7.4 ] }', { a: false, b: true, c: [ 7.4 ]});
assertValidParse('{ "lineComment": "//", "blockComment": ["/*", "*/"], "brackets": [ ["{", "}"], ["[", "]"], ["(", ")"] ] }', { lineComment: '//', blockComment: ["/*", "*/"], brackets: [ ["{", "}"], ["[", "]"], ["(", ")"] ] });
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} });
assertValidParse('{ "hello": { "again": { "inside": 5 }, "world": 1 }}', { hello: { again: { inside: 5 }, world: 1 }});
assertValidParse('{ "foo": /*hello*/true }', { foo: true });
});
test('parse: arrays', () => {
@ -183,4 +223,105 @@ suite('JSON', () => {
assertInvalidParse('[ ,1, 2, 3 ]', [ 1, 2, 3 ]);
assertInvalidParse('[ ,1, 2, 3, ]', [ 1, 2, 3 ]);
});
test('parse: disallow commments', () => {
let options = { disallowComments: true };
assertValidParse('[ 1, 2, null, "foo" ]', [ 1, 2, null, "foo"], options);
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} }, options);
assertInvalidParse('{ "foo": /*comment*/ true }', { foo: true }, options);
});
test('location: properties', () => {
assertLocation('|{ "foo": "bar" }', [], void 0, false);
assertLocation('{| "foo": "bar" }', [], void 0, true);
assertLocation('{ |"foo": "bar" }', ["foo" ], "property", true);
assertLocation('{ "foo|": "bar" }', [ "foo" ], "property", true);
assertLocation('{ "foo"|: "bar" }', ["foo" ], "property", true);
assertLocation('{ "foo": "bar"| }', ["foo" ], "string", false);
assertLocation('{ "foo":| "bar" }', ["foo" ], void 0, false);
assertLocation('{ "foo": {"bar|": 1, "car": 2 } }', ["foo", "bar" ], "property", true);
assertLocation('{ "foo": {"bar": 1|, "car": 3 } }', ["foo", "bar" ], "number", false);
assertLocation('{ "foo": {"bar": 1,| "car": 4 } }', ["foo"], void 0, true);
assertLocation('{ "foo": {"bar": 1, "ca|r": 5 } }', ["foo", "car" ], "property", true);
assertLocation('{ "foo": {"bar": 1, "car": 6| } }', ["foo", "car" ], "number", false);
assertLocation('{ "foo": {"bar": 1, "car": 7 }| }', ["foo"], void 0, false);
assertLocation('{ "foo": {"bar": 1, "car": 8 },| "goo": {} }', [], void 0, true);
assertLocation('{ "foo": {"bar": 1, "car": 9 }, "go|o": {} }', ["goo" ], "property", true);
assertLocation('{ "dep": {"bar": 1, "car": |', ["dep", "car" ], void 0, false);
assertLocation('{ "dep": {"bar": 1,, "car": |', ["dep", "car" ], void 0, false);
assertLocation('{ "dep": {"bar": "na", "dar": "ma", "car": | } }', ["dep", "car" ], void 0, false);
});
test('location: arrays', () => {
assertLocation('|["foo", null ]', [], void 0, false);
assertLocation('[|"foo", null ]', [0], "string", false);
assertLocation('["foo"|, null ]', [0], "string", false);
assertLocation('["foo",| null ]', [1], void 0, false);
assertLocation('["foo", |null ]', [1], "null", false);
assertLocation('["foo", null,| ]', [2], void 0, false);
assertLocation('["foo", null,,| ]', [3], void 0, false);
assertLocation('[["foo", null,, ],|', [1], void 0, false);
});
test('tree: literals', () => {
assertTree('true', { type: 'boolean', offset: 0, length: 4, value: true });
assertTree('false', { type: 'boolean', offset: 0, length: 5, value: false });
assertTree('null', { type: 'null', offset: 0, length: 4, value: null });
assertTree('23', { type: 'number', offset: 0, length: 2, value: 23 });
assertTree('-1.93e-19', { type: 'number', offset: 0, length: 9, value: -1.93e-19 });
assertTree('"hello"', { type: 'string', offset: 0, length: 7, value: 'hello' });
});
test('tree: arrays', () => {
assertTree('[]', { type: 'array', offset: 0, length: 2, children: [] });
assertTree('[ 1 ]', { type: 'array', offset: 0, length: 5, children: [{ type: 'number', offset: 2, length: 1, value: 1 }] });
assertTree('[ 1,"x"]', { type: 'array', offset: 0, length: 8, children: [
{ type: 'number', offset: 2, length: 1, value: 1 },
{ type: 'string', offset: 4, length: 3, value: 'x' }
]});
assertTree('[[]]', { type: 'array', offset: 0, length: 4, children: [
{ type: 'array', offset: 1, length: 2, children: []}
]});
});
test('tree: objects', () => {
assertTree('{ }', { type: 'object', offset: 0, length: 3, children: [] });
assertTree('{ "val": 1 }', { type: 'object', offset: 0, length: 12, children: [
{ type: 'property', offset: 2, length: 8, columnOffset: 7, children: [
{ type: 'string', offset: 2, length: 5, value: 'val' },
{ type: 'number', offset: 9, length: 1, value: 1 }
]}
]});
assertTree('{"id": "$", "v": [ null, null] }',
{ type: 'object', offset: 0, length: 32, children: [
{ type: 'property', offset: 1, length: 9, columnOffset: 5, children: [
{ type: 'string', offset: 1, length: 4, value: 'id' },
{ type: 'string', offset: 7, length: 3, value: '$' }
]},
{ type: 'property', offset: 12, length: 19, columnOffset: 15, children: [
{ type: 'string', offset: 12, length: 3, value: 'v' },
{ type: 'array', offset: 17, length: 13, children: [
{ type: 'null', offset: 19, length: 4, value: null },
{ type: 'null', offset: 25, length: 4, value: null }
]}
]}
]}
);
});
test('tree: find location', () => {
let root = parseTree('{ "key1": { "key11": [ "val111", "val112" ] }, "key2": [ { "key21": false, "key22": 221 }, null, [{}] ] }');
assertNodeAtLocation(root, [ "key1"], { key11: [ 'val111', 'val112' ]});
assertNodeAtLocation(root, [ "key1", "key11"], [ 'val111', 'val112' ]);
assertNodeAtLocation(root, [ "key1", "key11", 0], 'val111');
assertNodeAtLocation(root, [ "key1", "key11", 1], 'val112');
assertNodeAtLocation(root, [ "key1", "key11", 2], void 0);
assertNodeAtLocation(root, [ "key2", 0, "key21"], false);
assertNodeAtLocation(root, [ "key2", 0, "key22"], 221);
assertNodeAtLocation(root, [ "key2", 1], null);
assertNodeAtLocation(root, [ "key2", 2], [{}]);
assertNodeAtLocation(root, [ "key2", 2, 0], {});
});
});

View file

@ -0,0 +1,90 @@
/*---------------------------------------------------------------------------------------------
* 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 json = require('vs/base/common/json');
import {FormattingOptions, Edit} from 'vs/base/common/jsonFormatter';
import {setProperty, removeProperty} from 'vs/base/common/jsonEdit';
import assert = require('assert');
suite('JSON - edits', () => {
function assertEdit(content: string, edits: Edit[], expected: string) {
assert(edits);
let lastEditOffset = content.length;
for (let i = edits.length - 1; i >= 0; i--) {
let edit = edits[i];
assert(edit.offset >= 0 && edit.length >= 0 && edit.offset + edit.length <= content.length)
assert(typeof edit.content === 'string');
assert(lastEditOffset >= edit.offset + edit.length); // make sure all edits are ordered
lastEditOffset = edit.offset;
content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length);
}
assert.equal(content, expected);
}
let formatterOptions : FormattingOptions = {
insertSpaces: true,
tabSize: 2,
eol: '\n'
}
test('set property', () => {
let content = '{\n "x": "y"\n}';
let edits = setProperty(content, ['x'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": "bar"\n}');
});
test('insert property', () => {
let content = "{}";
let edits = setProperty(content, ['foo'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "foo": "bar"\n}');
content = "{\n}";
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "foo": "bar"\n}');
content = " {\n }";
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
assertEdit(content, edits, ' {\n "foo": "bar"\n }');
content = '{\n "x": "y"\n}';
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": "y",\n "foo": "bar"\n}');
edits = setProperty(content, ['x'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": "bar"\n}');
content = '{\n "x": {\n "a": 1,\n "b": true\n }\n}\n';
edits = setProperty(content, ['x'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": "bar"\n}\n');
edits = setProperty(content, ['x', 'b'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "b": "bar"\n }\n}\n');
edits = setProperty(content, ['x', 'c'], 'bar', formatterOptions, () => 0);
assertEdit(content, edits, '{\n "x": {\n "c": "bar",\n "a": 1,\n "b": true\n }\n}\n');
edits = setProperty(content, ['x', 'c'], 'bar', formatterOptions, () => 1);
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "c": "bar",\n "b": true\n }\n}\n');
edits = setProperty(content, ['x', 'c'], 'bar', formatterOptions, () => 2);
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "b": true,\n "c": "bar"\n }\n}\n');
});
test('remove property', () => {
let content = '{\n "x": "y"\n}';
let edits = removeProperty(content, ['x'], formatterOptions);
assertEdit(content, edits, '{}');
content = '{\n "x": "y", "a": []\n}';
edits = removeProperty(content, ['x'], formatterOptions);
assertEdit(content, edits, '{\n "a": []\n}');
content = '{\n "x": "y", "a": []\n}';
edits = removeProperty(content, ['a'], formatterOptions);
assertEdit(content, edits, '{\n "x": "y"\n}');
});
});

View file

@ -4,46 +4,33 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import EditorCommon = require('vs/editor/common/editorCommon');
import {Range} from 'vs/editor/common/core/range';
import {Model} from 'vs/editor/common/model/model';
import ModesTestUtils = require('vs/editor/test/common/modesTestUtils');
import Formatter = require('vs/languages/json/common/features/jsonFormatter');
import MirrorModel = require('vs/editor/common/model/mirrorModel');
import Formatter = require('vs/base/common/jsonFormatter');
import assert = require('assert');
suite('JSON - formatter', () => {
function format(unformatted: string, expected: string, insertSpaces = true) {
var range : EditorCommon.IRange = null;
var mirrorModel = MirrorModel.createTestMirrorModelFromString(unformatted);
var rangeStart = unformatted.indexOf('|');
var rangeEnd = unformatted.lastIndexOf('|');
function format(content: string, expected: string, insertSpaces = true) {
let range = void 0;
var rangeStart = content.indexOf('|');
var rangeEnd = content.lastIndexOf('|');
if (rangeStart !== -1 && rangeEnd !== -1) {
unformatted = unformatted.substring(0, rangeStart) + unformatted.substring(rangeStart + 1, rangeEnd) + unformatted.substring(rangeEnd + 1);
var startPos = mirrorModel.getPositionFromOffset(rangeStart);
var endPos = mirrorModel.getPositionFromOffset(rangeEnd);
range = { startLineNumber: startPos.lineNumber, startColumn: startPos.column, endLineNumber: endPos.lineNumber, endColumn: endPos.column };
mirrorModel = MirrorModel.createTestMirrorModelFromString(unformatted);
content = content.substring(0, rangeStart) + content.substring(rangeStart + 1, rangeEnd) + content.substring(rangeEnd + 1);
range = { offset: rangeStart, length: rangeEnd - rangeStart };
}
var operations = Formatter.format(mirrorModel, range, { tabSize: 2, insertSpaces: insertSpaces });
var edits = Formatter.format(content, range, { tabSize: 2, insertSpaces: insertSpaces, eol: '\n' });
var model = new Model(unformatted, Model.DEFAULT_CREATION_OPTIONS, null);
model.pushEditOperations([], operations.map(o => {
return {
range: Range.lift(o.range),
text: o.text,
identifier: null,
forceMoveMarkers: false
};
}), () => []);
var newContent = model.getValue(EditorCommon.EndOfLinePreference.LF);
assert.equal(newContent, expected);
model.dispose();
let lastEditOffset = content.length;
for (let i = edits.length - 1; i >= 0; i--) {
let edit = edits[i];
assert(edit.offset >= 0 && edit.length >= 0 && edit.offset + edit.length <= content.length)
assert(typeof edit.content === 'string');
assert(lastEditOffset >= edit.offset + edit.length); // make sure all edits are ordered
lastEditOffset = edit.offset;
content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length);
}
assert.equal(content, expected);
}
test('object - single property', () => {

View file

@ -5,7 +5,7 @@
'use strict';
import * as assert from 'assert';
import { AIAdapter } from 'vs/base/node/aiAdapter';
import {AIAdapter} from 'vs/base/parts/ai/node/aiAdapter';
interface IAppInsightsEvent {
eventName: string;
@ -21,9 +21,9 @@ class AppInsightsMock {
public trackEvent(eventName: string, properties?: { string?: string; }, measurements?: { string?: number; }): void {
this.events.push({
eventName: eventName,
properties: properties,
measurements: measurements
eventName,
properties,
measurements
});
}
public trackPageView(): void {
@ -33,6 +33,10 @@ class AppInsightsMock {
public trackException(exception: any): void {
this.exceptions.push(exception);
}
public sendPendingData(callback): void {
// called on dispose
}
}
suite('AIAdapter', () => {
@ -42,7 +46,7 @@ suite('AIAdapter', () => {
setup(() => {
appInsightsMock = new AppInsightsMock();
adapter = new AIAdapter(null, prefix, appInsightsMock);
adapter = new AIAdapter(prefix, undefined, () => appInsightsMock);
});
teardown(() => {
@ -56,11 +60,16 @@ suite('AIAdapter', () => {
assert.equal(appInsightsMock.events[0].eventName, `${prefix}/testEvent`);
});
test('Track UnhandledError as exception and events', () => {
var sampleError = new Error('test');
test('addional data', () => {
adapter = new AIAdapter(prefix, { first: '1st', second: 2, third: true }, () => appInsightsMock);
adapter.log('testEvent');
adapter.logException(sampleError);
assert.equal(appInsightsMock.exceptions.length, 1);
assert.equal(appInsightsMock.events.length, 1);
let [first] = appInsightsMock.events;
assert.equal(first.eventName, `${prefix}/testEvent`);
assert.equal(first.properties['first'], '1st');
assert.equal(first.measurements['second'], '2');
assert.equal(first.measurements['third'], 1);
});
test('property limits', () => {

View file

@ -19,6 +19,7 @@ exports.collectModules= function() {
return [
createModuleDescription('vs/code/electron-main/main', []),
createModuleDescription('vs/code/node/cli', []),
createModuleDescription('vs/code/node/cliProcessMain', ['vs/code/node/cli']),
createModuleDescription('vs/code/node/sharedProcessMain', [])
];
};

View file

@ -17,9 +17,9 @@ import * as platform from 'vs/base/common/platform';
import URI from 'vs/base/common/uri';
import * as types from 'vs/base/common/types';
import { ServiceIdentifier, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import product, { IProductConfiguration } from 'vs/code/node/product';
import product, { IProductConfiguration } from 'vs/platform/product';
import { parseArgs } from 'vs/code/node/argv';
import pkg from 'vs/code/node/package';
import pkg from 'vs/platform/package';
export interface IProcessEnvironment {
[key: string]: string;
@ -46,7 +46,7 @@ export interface ICommandLineArguments {
waitForWindowClose?: boolean;
}
export const IEnvironmentService = createDecorator<IEnvironmentService>('environmentService');
export const IEnvironmentService = createDecorator<IEnvironmentService>('mainEnvironmentService');
export interface IEnvironmentService {
serviceId: ServiceIdentifier<any>;

View file

@ -409,10 +409,6 @@ export class VSCodeMenu {
// Files
let files = recentList.files;
if (platform.isMacintosh && recentList.files.length > 0) {
files = recentList.files.filter(f => recentList.folders.indexOf(f) < 0); // TODO@Ben migration (remove in the future)
}
if (files.length > 0) {
openRecentMenu.append(__separator__());
@ -828,7 +824,7 @@ function __separator__(): Electron.MenuItem {
function mnemonicLabel(label: string): string {
if (platform.isMacintosh) {
return label.replace(/&&/g, ''); // no mnemonic support on mac
return label.replace(/\(&&\w\)|&&/g, ''); // no mnemonic support on mac/linux
}
return label.replace(/&&/g, '&');

View file

@ -5,57 +5,21 @@
import * as cp from 'child_process';
import URI from 'vs/base/common/uri';
import pkg from 'vs/code/node/package';
import { IDisposable } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { IEnvironment } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/code/electron-main/env';
import { ISettingsService } from 'vs/code/electron-main/settings';
import { IUpdateService } from 'vs/code/electron-main/update-manager';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
const boostrapPath = URI.parse(require.toUrl('bootstrap')).fsPath;
function getEnvironment(envService: IEnvironmentService, updateManager: IUpdateService): IEnvironment {
let configuration: IEnvironment = assign({}, envService.cliArgs);
configuration.execPath = process.execPath;
configuration.appName = envService.product.nameLong;
configuration.appRoot = envService.appRoot;
configuration.version = pkg.version;
configuration.commitHash = envService.product.commit;
configuration.appSettingsHome = envService.appSettingsHome;
configuration.appSettingsPath = envService.appSettingsPath;
configuration.appKeybindingsPath = envService.appKeybindingsPath;
configuration.userExtensionsHome = envService.userExtensionsHome;
configuration.isBuilt = envService.isBuilt;
configuration.updateFeedUrl = updateManager.feedUrl;
configuration.updateChannel = updateManager.channel;
configuration.extensionsGallery = envService.product.extensionsGallery;
function _spawnSharedProcess(): cp.ChildProcess {
const env = assign({}, process.env, {
AMD_ENTRYPOINT: 'vs/code/node/sharedProcessMain'
});
return configuration;
}
function _spawnSharedProcess(envService: IEnvironmentService, updateManager: IUpdateService, settingsManager: ISettingsService): cp.ChildProcess {
// Make sure the nls configuration travels to the shared process.
const opts = {
env: assign(assign({}, process.env), {
AMD_ENTRYPOINT: 'vs/code/node/sharedProcessMain'
})
};
const result = cp.fork(boostrapPath, ['--type=SharedProcess'], opts);
const result = cp.fork(boostrapPath, ['--type=SharedProcess'], { env });
// handshake
result.once('message', () => {
result.send({
configuration: {
env: getEnvironment(envService, updateManager)
},
contextServiceOptions: {
globalSettings: settingsManager.globalSettings
}
});
});
result.once('message', () => result.send('hey'));
return result;
}
@ -63,10 +27,6 @@ function _spawnSharedProcess(envService: IEnvironmentService, updateManager: IUp
let spawnCount = 0;
export function spawnSharedProcess(accessor: ServicesAccessor): IDisposable {
const envService = accessor.get(IEnvironmentService);
const updateManager = accessor.get(IUpdateService);
const settingsManager = accessor.get(ISettingsService);
let child: cp.ChildProcess;
const spawn = () => {
@ -74,7 +34,7 @@ export function spawnSharedProcess(accessor: ServicesAccessor): IDisposable {
return;
}
child = _spawnSharedProcess(envService, updateManager, settingsManager);
child = _spawnSharedProcess();
child.on('exit', spawn);
};

View file

@ -12,7 +12,7 @@ import * as nls from 'vs/nls';
import * as paths from 'vs/base/common/paths';
import * as arrays from 'vs/base/common/arrays';
import * as objects from 'vs/base/common/objects';
import pkg from 'vs/code/node/package';
import pkg from 'vs/platform/package';
import { EventEmitter } from 'events';
import { IStorageService } from 'vs/code/electron-main/storage';
import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState } from 'vs/code/electron-main/window';
@ -789,10 +789,6 @@ export class WindowsManager implements IWindowsService {
files = arrays.distinct(files);
folders = arrays.distinct(folders);
if (platform.isMacintosh && files.length > 0) {
files = files.filter(f => folders.indexOf(f) < 0); // TODO@Ben migration (remove in the future)
}
// Make sure it is bounded
files = files.slice(0, 10);
folders = folders.slice(0, 10);

View file

@ -5,7 +5,7 @@
import * as os from 'os';
import * as minimist from 'minimist';
import pkg from 'vs/code/node/package';
import pkg from 'vs/platform/package';
export interface ParsedArgs extends minimist.ParsedArgs {
help: boolean;
@ -28,6 +28,9 @@ export interface ParsedArgs extends minimist.ParsedArgs {
timestamp: string;
debugBrkPluginHost: string;
debugPluginHost: string;
'list-extensions': boolean;
'install-extension': string | string[];
'uninstall-extension': string | string[];
}
const options: minimist.Opts = {
@ -37,7 +40,9 @@ const options: minimist.Opts = {
'extensionHomePath',
'extensionDevelopmentPath',
'extensionTestsPath',
'timestamp'
'timestamp',
'install-extension',
'uninstall-extension'
],
boolean: [
'help',
@ -50,7 +55,8 @@ const options: minimist.Opts = {
'performance',
'verbose',
'logExtensionHostCommunication',
'disable-extensions'
'disable-extensions',
'list-extensions'
],
alias: {
help: 'h',
@ -89,4 +95,9 @@ ${ indent } window.
${ indent }--user-data-dir <dir> Specifies the directory that user data is kept in,
${ indent } useful when running as root.
${ indent }-v, --version Print version.
${ indent }-w, --wait Wait for the window to be closed before returning.`;
${ indent }-w, --wait Wait for the window to be closed before returning.
${ indent }--list-extensions List the installed extensions.
${ indent }--install-extension <extension>
${ indent } Installs an extension.
${ indent }--uninstall-extension <extension>
${ indent } Uninstalls an extension.`;

View file

@ -4,17 +4,29 @@
*--------------------------------------------------------------------------------------------*/
import { spawn } from 'child_process';
import { TPromise } from 'vs/base/common/winjs.base';
import { assign } from 'vs/base/common/objects';
import { parseArgs, helpMessage } from 'vs/code/node/argv';
import pkg from 'vs/code/node/package';
import { parseArgs, helpMessage, ParsedArgs } from 'vs/code/node/argv';
import pkg from 'vs/platform/package';
export function main(args: string[]) {
function shouldSpawnCliProcess(argv: ParsedArgs): boolean {
return argv['list-extensions'] || !!argv['install-extension'] || !!argv['uninstall-extension'];
}
interface IMainCli {
main: (argv: ParsedArgs) => TPromise<void>;
}
export function main(args: string[]): TPromise<void> {
const argv = parseArgs(args);
if (argv.help) {
console.log(helpMessage);
} else if (argv.version) {
console.log(pkg.version);
} else if (shouldSpawnCliProcess(argv)) {
const mainCli = new TPromise<IMainCli>(c => require(['vs/code/node/cliProcessMain'], c));
return mainCli.then(cli => cli.main(argv));
} else {
const env = assign({}, process.env, {
// this will signal Code that it was spawned from this module
@ -30,12 +42,16 @@ export function main(args: string[]) {
});
if (argv.wait) {
child.on('exit', process.exit);
return;
return new TPromise<void>(c => child.once('exit', ()=> c(null)));
}
}
process.exit(0);
return TPromise.as(null);
}
main(process.argv.slice(2));
main(process.argv.slice(2))
.then(() => process.exit(0))
.then(null, err => {
console.error(err.stack ? err.stack : err);
process.exit(1);
});

View file

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { ParsedArgs } from 'vs/code/node/argv';
import { TPromise } from 'vs/base/common/winjs.base';
import { sequence } from 'vs/base/common/async';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IEventService } from 'vs/platform/event/common/event';
import { EventService } from 'vs/platform/event/common/eventService';
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { getExtensionId } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { ITelemetryService, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IRequestService } from 'vs/platform/request/common/request';
import { NodeRequestService } from 'vs/platform/request/node/nodeRequestService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NodeConfigurationService } from 'vs/platform/configuration/node/nodeConfigurationService';
const notFound = id => localize('notFound', "Extension '{0}' not found.", id);
const notInstalled = id => localize('notInstalled', "Extension '{0}' is not installed.", id);
const useId = localize('useId', "Make sure you use the full extension id, eg: {0}", 'ms-vscode.csharp');
class Main {
constructor(
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IExtensionGalleryService private extensionGalleryService: IExtensionGalleryService
) {}
run(argv: ParsedArgs): TPromise<any> {
// TODO@joao - make this contributable
if (argv['list-extensions']) {
return this.listExtensions();
} else if (argv['install-extension']) {
const arg = argv['install-extension'];
const ids: string[] = typeof arg === 'string' ? [arg] : arg;
return this.installExtension(ids);
} else if (argv['uninstall-extension']) {
const arg = argv['uninstall-extension'];
const ids: string[] = typeof arg === 'string' ? [arg] : arg;
return this.uninstallExtension(ids);
}
}
private listExtensions(): TPromise<any> {
return this.extensionManagementService.getInstalled().then(extensions => {
extensions.forEach(e => console.log(getExtensionId(e)));
});
}
private installExtension(ids: string[]): TPromise<any> {
return this.extensionManagementService.getInstalled().then(installed => {
return sequence(ids.map(id => () => {
const isInstalled = installed.some(e => getExtensionId(e) === id);
if (isInstalled) {
return TPromise.wrapError(localize('alreadyInstalled', "Extension '{0}' is already installed.", id));
}
return this.extensionGalleryService.query({ ids: [id] }).then(result => {
const [extension] = result.firstPage;
if (!extension) {
return TPromise.wrapError(`${ notFound(id) }\n${ useId }`);
}
console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id));
console.log(localize('installing', "Installing..."));
return this.extensionManagementService.install(extension).then(extension => {
console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version));
});
});
}));
});
}
private uninstallExtension(ids: string[]): TPromise<any> {
return sequence(ids.map(id => () => {
return this.extensionManagementService.getInstalled().then(installed => {
const [extension] = installed.filter(e => getExtensionId(e) === id);
if (!extension) {
return TPromise.wrapError(`${ notInstalled(id) }\n${ useId }`);
}
console.log(localize('uninstalling', "Uninstalling {0}...", id));
return this.extensionManagementService.uninstall(extension).then(() => {
console.log(localize('successUninstall', "Extension '{0}' was successfully uninstalled!", id));
});
});
}));
}
}
export function main(argv: ParsedArgs): TPromise<void> {
const services = new ServiceCollection();
services.set(IEventService, new SyncDescriptor(EventService));
services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService));
services.set(ITelemetryService, NullTelemetryService);
services.set(IConfigurationService, new SyncDescriptor(NodeConfigurationService));
services.set(IRequestService, new SyncDescriptor(NodeRequestService));
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
const instantiationService: IInstantiationService = new InstantiationService(services);
const main = instantiationService.createInstance(Main);
return main.run(argv);
}

View file

@ -7,16 +7,17 @@ import * as fs from 'fs';
import * as platform from 'vs/base/common/platform';
import { serve, Server, connect } from 'vs/base/parts/ipc/node/ipc.net';
import { TPromise } from 'vs/base/common/winjs.base';
import { IConfiguration } from 'vs/platform/workspace/common/workspace';
import { WorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
import { registerAIChannel } from 'vs/base/parts/ai/node/ai.app';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IEventService } from 'vs/platform/event/common/event';
import { EventService } from 'vs/platform/event/common/eventService';
import { ExtensionsChannel } from 'vs/workbench/parts/extensions/common/extensionsIpc';
import { ExtensionsService } from 'vs/workbench/parts/extensions/node/extensionsService';
interface IInitData {
configuration: IConfiguration;
contextServiceOptions: { settings: any };
}
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
function quit(err?: Error) {
if (err) {
@ -39,16 +40,24 @@ function setupPlanB(parentPid: number): void {
}, 5000);
}
function main(server: Server, initData: IInitData): void {
const eventService = new EventService();
const contextService = new WorkspaceContextService(eventService, null, initData.configuration, initData.contextServiceOptions);
const extensionService = new ExtensionsService(contextService);
const channel = new ExtensionsChannel(extensionService);
function main(server: Server): void {
const services = new ServiceCollection();
server.registerChannel('extensions', channel);
services.set(IEventService, new SyncDescriptor(EventService));
services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService));
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
// eventually clean up old extensions
setTimeout(() => extensionService.removeDeprecatedExtensions(), 5000);
const instantiationService = new InstantiationService(services);
instantiationService.invokeFunction(accessor => {
const extensionManagementService = accessor.get(IExtensionManagementService);
const channel = new ExtensionManagementChannel(extensionManagementService);
server.registerChannel('extensions', channel);
registerAIChannel(server);
// eventually clean up old extensions
setTimeout(() => (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(), 5000);
});
}
function setupIPC(hook: string): TPromise<Server> {
@ -85,8 +94,8 @@ function setupIPC(hook: string): TPromise<Server> {
return setup(true);
}
function handshake(): TPromise<IInitData> {
return new TPromise<IInitData>((c, e) => {
function handshake(): TPromise<void> {
return new TPromise<void>((c, e) => {
process.once('message', c);
process.once('error', e);
process.send('hello');
@ -94,6 +103,6 @@ function handshake(): TPromise<IInitData> {
}
TPromise.join<any>([setupIPC(process.env['VSCODE_SHARED_IPC_HOOK']), handshake()])
.then(r => main(r[0], r[1]))
.then(r => main(r[0]))
.then(() => setupPlanB(process.env['VSCODE_PID']))
.done(null, quit);

View file

@ -13,8 +13,6 @@
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*--------------------------------------------------------------------------------------------*/
/// <reference path="declares.ts" />
/// <reference path="loader.ts" />
'use strict';
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
@ -100,7 +98,7 @@ var CSSLoaderPlugin;
this._insertLinkNode(linkNode);
};
return BrowserCSSLoader;
})();
}());
/**
* Prior to IE10, IE could not go above 31 stylesheets in a page
* http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/internet-explorer-stylesheet-rule-selector-import-sheet-limit-maximum.aspx
@ -201,7 +199,7 @@ var CSSLoaderPlugin;
}
};
return IE9CSSLoader;
})(BrowserCSSLoader);
}(BrowserCSSLoader));
var IE8CSSLoader = (function (_super) {
__extends(IE8CSSLoader, _super);
function IE8CSSLoader() {
@ -214,7 +212,7 @@ var CSSLoaderPlugin;
};
};
return IE8CSSLoader;
})(IE9CSSLoader);
}(IE9CSSLoader));
var NodeCSSLoader = (function () {
function NodeCSSLoader() {
this.fs = require.nodeRequire('fs');
@ -229,7 +227,7 @@ var CSSLoaderPlugin;
};
NodeCSSLoader.BOM_CHAR_CODE = 65279;
return NodeCSSLoader;
})();
}());
// ------------------------------ Finally, the plugin
var CSSPlugin = (function () {
function CSSPlugin(cssLoader) {
@ -279,7 +277,7 @@ var CSSLoaderPlugin;
};
CSSPlugin.BUILD_MAP = {};
return CSSPlugin;
})();
}());
CSSLoaderPlugin.CSSPlugin = CSSPlugin;
var Utilities = (function () {
function Utilities() {
@ -411,7 +409,7 @@ var CSSLoaderPlugin;
});
};
return Utilities;
})();
}());
CSSLoaderPlugin.Utilities = Utilities;
(function () {
var cssLoader = null;

View file

@ -207,15 +207,15 @@ class CSSBasedConfiguration extends Disposable {
maxDigitWidth = Math.max(maxDigitWidth, digits[i].width);
}
return new FontInfo(
bareFontInfo.fontFamily,
bareFontInfo.fontSize,
bareFontInfo.lineHeight,
typicalHalfwidthCharacter.width,
typicalFullwidthCharacter.width,
space.width,
maxDigitWidth
);
return new FontInfo({
fontFamily: bareFontInfo.fontFamily,
fontSize: bareFontInfo.fontSize,
lineHeight: bareFontInfo.lineHeight,
typicalHalfwidthCharacterWidth: typicalHalfwidthCharacter.width,
typicalFullwidthCharacterWidth: typicalFullwidthCharacter.width,
spaceWidth: space.width,
maxDigitWidth: maxDigitWidth
});
}
}
@ -241,6 +241,8 @@ export class Configuration extends CommonEditorConfiguration {
if (this._configWithDefaults.getEditorOptions().automaticLayout) {
this._elementSizeObserver.startObserving();
}
this._register(browser.onDidChangeZoomLevel(_ => this._recomputeOptions()));
}
private _onReferenceDomElementSizeChanged(): void {
@ -287,6 +289,10 @@ export class Configuration extends CommonEditorConfiguration {
return this._elementSizeObserver.getHeight();
}
protected _getCanUseTranslate3d(): boolean {
return browser.canUseTranslate3d && browser.getZoomLevel() === 0;
}
protected readConfiguration(bareFontInfo:BareFontInfo): FontInfo {
return CSSBasedConfiguration.INSTANCE.readConfiguration(bareFontInfo);
}

View file

@ -12,7 +12,7 @@ import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent';
import {StyleMutator} from 'vs/base/browser/styleMutator';
import {GlobalScreenReaderNVDA} from 'vs/editor/common/config/commonEditorConfig';
import {TextAreaHandler} from 'vs/editor/common/controller/textAreaHandler';
import {IClipboardEvent, IKeyboardEventWrapper, ITextAreaWrapper, TextAreaStrategy} from 'vs/editor/common/controller/textAreaState';
import {IClipboardEvent, ICompositionEvent, IKeyboardEventWrapper, ITextAreaWrapper, TextAreaStrategy} from 'vs/editor/common/controller/textAreaState';
import {Range} from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {ViewEventHandler} from 'vs/editor/common/viewModel/viewEventHandler';
@ -114,11 +114,14 @@ class TextAreaWrapper extends Disposable implements ITextAreaWrapper {
private _onKeyPress = this._register(new Emitter<IKeyboardEventWrapper>());
public onKeyPress: Event<IKeyboardEventWrapper> = this._onKeyPress.event;
private _onCompositionStart = this._register(new Emitter<void>());
public onCompositionStart: Event<void> = this._onCompositionStart.event;
private _onCompositionStart = this._register(new Emitter<ICompositionEvent>());
public onCompositionStart: Event<ICompositionEvent> = this._onCompositionStart.event;
private _onCompositionEnd = this._register(new Emitter<void>());
public onCompositionEnd: Event<void> = this._onCompositionEnd.event;
private _onCompositionUpdate = this._register(new Emitter<ICompositionEvent>());
public onCompositionUpdate: Event<ICompositionEvent> = this._onCompositionUpdate.event;
private _onCompositionEnd = this._register(new Emitter<ICompositionEvent>());
public onCompositionEnd: Event<ICompositionEvent> = this._onCompositionEnd.event;
private _onInput = this._register(new Emitter<void>());
public onInput: Event<void> = this._onInput.event;
@ -139,8 +142,9 @@ class TextAreaWrapper extends Disposable implements ITextAreaWrapper {
this._register(dom.addStandardDisposableListener(this._textArea, 'keydown', (e) => this._onKeyDown.fire(new KeyboardEventWrapper(e))));
this._register(dom.addStandardDisposableListener(this._textArea, 'keyup', (e) => this._onKeyUp.fire(new KeyboardEventWrapper(e))));
this._register(dom.addStandardDisposableListener(this._textArea, 'keypress', (e) => this._onKeyPress.fire(new KeyboardEventWrapper(e))));
this._register(dom.addDisposableListener(this._textArea, 'compositionstart', (e) => this._onCompositionStart.fire()));
this._register(dom.addDisposableListener(this._textArea, 'compositionend', (e) => this._onCompositionEnd.fire()));
this._register(dom.addDisposableListener(this._textArea, 'compositionstart', (e) => this._onCompositionStart.fire(e)));
this._register(dom.addDisposableListener(this._textArea, 'compositionupdate', (e) => this._onCompositionUpdate.fire(e)));
this._register(dom.addDisposableListener(this._textArea, 'compositionend', (e) => this._onCompositionEnd.fire(e)));
this._register(dom.addDisposableListener(this._textArea, 'input', (e) => this._onInput.fire()));
this._register(dom.addDisposableListener(this._textArea, 'cut', (e:ClipboardEvent) => this._onCut.fire(new ClipboardEventWrapper(e))));
this._register(dom.addDisposableListener(this._textArea, 'copy', (e:ClipboardEvent) => this._onCopy.fire(new ClipboardEventWrapper(e))));
@ -213,6 +217,8 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
private contentWidth:number;
private scrollLeft:number;
private visibleRange:VisibleRange;
constructor(context:ViewContext, viewController:IViewController, viewHelper:IKeyboardHandlerHelper) {
super();
@ -252,11 +258,11 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
this._context.privateViewEventBus.emit(editorCommon.ViewEventNames.RevealRangeEvent, revealPositionEvent);
// Find range pixel position
let visibleRange = this.viewHelper.visibleRangeForPositionRelativeToEditor(lineNumber, column);
this.visibleRange = this.viewHelper.visibleRangeForPositionRelativeToEditor(lineNumber, column);
if (visibleRange) {
StyleMutator.setTop(this.textArea.actual, visibleRange.top);
StyleMutator.setLeft(this.textArea.actual, this.contentLeft + visibleRange.left - this.scrollLeft);
if (this.visibleRange) {
StyleMutator.setTop(this.textArea.actual, this.visibleRange.top);
StyleMutator.setLeft(this.textArea.actual, this.contentLeft + this.visibleRange.left - this.scrollLeft);
}
if (browser.isIE11orEarlier) {
@ -267,12 +273,24 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
StyleMutator.setHeight(this.textArea.actual, this._context.configuration.editor.lineHeight);
dom.addClass(this.viewHelper.viewDomNode, 'ime-input');
}));
this._toDispose.push(this.textAreaHandler.onCompositionUpdate((e) => {
// adjust width by its size
let canvasElem = <HTMLCanvasElement>document.createElement('canvas');
let context = canvasElem.getContext('2d');
context.font = window.getComputedStyle(this.textArea.actual).font;
let metrics = context.measureText(e.data);
StyleMutator.setWidth(this.textArea.actual, metrics.width);
}));
this._toDispose.push(this.textAreaHandler.onCompositionEnd((e) => {
this.textArea.actual.style.height = '';
this.textArea.actual.style.width = '';
StyleMutator.setLeft(this.textArea.actual, 0);
StyleMutator.setTop(this.textArea.actual, 0);
dom.removeClass(this.viewHelper.viewDomNode, 'ime-input');
this.visibleRange = null;
}));
this._toDispose.push(GlobalScreenReaderNVDA.onChange((value) => {
this.textAreaHandler.setStrategy(this._getStrategy());
@ -293,7 +311,7 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
if (GlobalScreenReaderNVDA.getValue()) {
return TextAreaStrategy.NVDA;
}
if (this._context.configuration.editor.experimentalScreenReader) {
if (this._context.configuration.editor.viewInfo.experimentalScreenReader) {
return TextAreaStrategy.NVDA;
}
return TextAreaStrategy.IENarrator;
@ -308,7 +326,7 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
if (e.fontInfo) {
Configuration.applyFontInfoSlow(this.textArea.actual, this._context.configuration.editor.fontInfo);
}
if (e.experimentalScreenReader) {
if (e.viewInfo.experimentalScreenReader) {
this.textAreaHandler.setStrategy(this._getStrategy());
}
return false;
@ -316,6 +334,10 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
public onScrollChanged(e:editorCommon.IScrollEvent): boolean {
this.scrollLeft = e.scrollLeft;
if (this.visibleRange) {
StyleMutator.setTop(this.textArea.actual, this.visibleRange.top);
StyleMutator.setLeft(this.textArea.actual, this.contentLeft + this.visibleRange.left - this.scrollLeft);
}
return false;
}
@ -335,7 +357,7 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
return false;
}
public onLayoutChanged(layoutInfo:editorCommon.IEditorLayoutInfo): boolean {
public onLayoutChanged(layoutInfo:editorCommon.EditorLayoutInfo): boolean {
this.contentLeft = layoutInfo.contentLeft;
this.contentWidth = layoutInfo.contentWidth;
return false;

View file

@ -179,8 +179,8 @@ export class MouseHandler extends ViewEventHandler implements IDisposable {
}
// --- begin event handlers
_layoutInfo:editorCommon.IEditorLayoutInfo;
public onLayoutChanged(layoutInfo:editorCommon.IEditorLayoutInfo): boolean {
_layoutInfo:editorCommon.EditorLayoutInfo;
public onLayoutChanged(layoutInfo:editorCommon.EditorLayoutInfo): boolean {
this._layoutInfo = layoutInfo;
return false;
}
@ -260,7 +260,7 @@ export class MouseHandler extends ViewEventHandler implements IDisposable {
let targetIsContent = (t.type === editorCommon.MouseTargetType.CONTENT_TEXT || t.type === editorCommon.MouseTargetType.CONTENT_EMPTY);
let targetIsGutter = (t.type === editorCommon.MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === editorCommon.MouseTargetType.GUTTER_LINE_NUMBERS || t.type === editorCommon.MouseTargetType.GUTTER_LINE_DECORATIONS);
let targetIsLineNumbers = (t.type === editorCommon.MouseTargetType.GUTTER_LINE_NUMBERS);
let selectOnLineNumbers = this._context.configuration.editor.selectOnLineNumbers;
let selectOnLineNumbers = this._context.configuration.editor.viewInfo.selectOnLineNumbers;
let targetIsViewZone = (t.type === editorCommon.MouseTargetType.CONTENT_VIEW_ZONE || t.type === editorCommon.MouseTargetType.GUTTER_VIEW_ZONE);
let shouldHandle = e.leftButton;

View file

@ -6,7 +6,7 @@
import {Position} from 'vs/editor/common/core/position';
import {Range as EditorRange} from 'vs/editor/common/core/range';
import {IEditorLayoutInfo, IEditorPosition, IEditorRange, IPosition, MouseTargetType} from 'vs/editor/common/editorCommon';
import {EditorLayoutInfo, IEditorPosition, IEditorRange, IPosition, MouseTargetType} from 'vs/editor/common/editorCommon';
import {ClassNames, IMouseTarget, IViewZoneData} from 'vs/editor/browser/editorBrowser';
import {IDomNodePosition} from 'vs/base/browser/dom';
import {ViewContext} from 'vs/editor/common/view/viewContext';
@ -177,7 +177,7 @@ export class MouseTargetFactory {
return false;
}
public createMouseTarget(layoutInfo:IEditorLayoutInfo, editorContent:IDomNodePosition, e:ISimplifiedMouseEvent, testEventTarget:boolean): IMouseTarget {
public createMouseTarget(layoutInfo:EditorLayoutInfo, editorContent:IDomNodePosition, e:ISimplifiedMouseEvent, testEventTarget:boolean): IMouseTarget {
try {
var r = this._unsafeCreateMouseTarget(layoutInfo, editorContent, e, testEventTarget);
return r;
@ -186,7 +186,7 @@ export class MouseTargetFactory {
}
}
private _unsafeCreateMouseTarget(layoutInfo:IEditorLayoutInfo, editorContent:IDomNodePosition, e:ISimplifiedMouseEvent, testEventTarget:boolean): IMouseTarget {
private _unsafeCreateMouseTarget(layoutInfo:EditorLayoutInfo, editorContent:IDomNodePosition, e:ISimplifiedMouseEvent, testEventTarget:boolean): IMouseTarget {
var mouseVerticalOffset = Math.max(0, this._viewHelper.getScrollTop() + (e.posy - editorContent.top));
var mouseContentHorizontalOffset = this._viewHelper.getScrollLeft() + (e.posx - editorContent.left) - layoutInfo.contentLeft;
let mouseColumn = this._getMouseColumn(mouseContentHorizontalOffset);
@ -213,9 +213,9 @@ export class MouseTargetFactory {
// Is it the textarea cover?
if (REGEX.IS_TEXTAREA_COVER.test(path)) {
if (this._context.configuration.editor.glyphMargin) {
if (this._context.configuration.editor.viewInfo.glyphMargin) {
return this.createMouseTargetFromGlyphMargin(t, mouseVerticalOffset, mouseColumn);
} else if (this._context.configuration.editor.lineNumbers) {
} else if (this._context.configuration.editor.viewInfo.lineNumbers) {
return this.createMouseTargetFromLineNumbers(t, mouseVerticalOffset, mouseColumn);
} else {
return this.createMouseTargetFromLinesDecorationsChild(t, mouseVerticalOffset, mouseColumn);
@ -359,8 +359,8 @@ export class MouseTargetFactory {
if (adjustedPosy <= editorContent.top) {
adjustedPosy = editorContent.top + 1;
}
if (adjustedPosy >= editorContent.top + this._context.configuration.editor.observedOuterHeight) {
adjustedPosy = editorContent.top + this._context.configuration.editor.observedOuterHeight - 1;
if (adjustedPosy >= editorContent.top + this._context.configuration.editor.layoutInfo.height) {
adjustedPosy = editorContent.top + this._context.configuration.editor.layoutInfo.height - 1;
}
var hitx = e.posx - document.body.scrollLeft;
@ -594,7 +594,7 @@ export class MouseTargetFactory {
};
}
public getMouseColumn(layoutInfo:IEditorLayoutInfo, editorContent:IDomNodePosition, e:ISimplifiedMouseEvent): number {
public getMouseColumn(layoutInfo:EditorLayoutInfo, editorContent:IDomNodePosition, e:ISimplifiedMouseEvent): number {
let mouseContentHorizontalOffset = this._viewHelper.getScrollLeft() + (e.posx - editorContent.left) - layoutInfo.contentLeft;
return this._getMouseColumn(mouseContentHorizontalOffset);
}

View file

@ -30,7 +30,7 @@ import 'vs/editor/contrib/outlineMarker/browser/outlineMarker';
import 'vs/editor/contrib/parameterHints/browser/parameterHints';
import 'vs/editor/contrib/quickFix/browser/quickFix';
import 'vs/editor/contrib/referenceSearch/browser/referenceSearch';
import 'vs/editor/contrib/rename/browser/rename2';
import 'vs/editor/contrib/rename/browser/rename';
import 'vs/editor/contrib/smartSelect/common/smartSelect';
import 'vs/editor/contrib/smartSelect/common/jumpToBracket';
import 'vs/editor/contrib/snippet/common/snippet';
@ -40,7 +40,6 @@ import 'vs/editor/contrib/toggleTabFocusMode/common/toggleTabFocusMode';
import 'vs/editor/contrib/toggleWordWrap/common/toggleWordWrap';
import 'vs/css!vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
import 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
import 'vs/editor/contrib/workerStatusReporter/browser/workerStatusReporter';
import 'vs/editor/contrib/defineKeybinding/browser/defineKeybinding';
import 'vs/editor/contrib/folding/browser/folding';
import 'vs/editor/contrib/indentation/common/indentation';

View file

@ -459,7 +459,7 @@ export interface IOverviewRuler {
getDomNode(): HTMLElement;
dispose(): void;
setZones(zones:OverviewRulerZone[]): void;
setLayout(position:editorCommon.IOverviewRulerPosition): void;
setLayout(position:editorCommon.OverviewRulerPosition): void;
}
/**
* A rich code editor.

View file

@ -139,7 +139,7 @@ export class SimpleEditorService implements IEditorService {
private findModel(editor:editorCommon.ICommonCodeEditor, data:IResourceInput): editorCommon.IModel {
var model = editor.getModel();
if(model.getAssociatedResource().toString() !== data.resource.toString()) {
if(model.uri.toString() !== data.resource.toString()) {
return null;
}

View file

@ -24,7 +24,7 @@ import {RemoteTelemetryServiceHelper} from 'vs/platform/telemetry/common/remoteT
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {DefaultConfig} from 'vs/editor/common/config/defaultConfig';
import {IActionDescriptor, ICodeEditorWidgetCreationOptions, IDiffEditorOptions, IModel, IModelChangedEvent, EventType} from 'vs/editor/common/editorCommon';
import {IMode} from 'vs/editor/common/modes';
import {HoverProvider, IMode} from 'vs/editor/common/modes';
import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry';
import {ILanguage} from 'vs/editor/common/modes/monarch/monarchTypes';
import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService';
@ -38,6 +38,11 @@ import {SimpleEditorService, StandaloneKeybindingService} from 'vs/editor/browse
import {IEditorContextViewService, IEditorOverrideServices, ensureDynamicPlatformServices, ensureStaticPlatformServices, getOrCreateStaticServices} from 'vs/editor/browser/standalone/standaloneServices';
import {CodeEditorWidget} from 'vs/editor/browser/widget/codeEditorWidget';
import {DiffEditorWidget} from 'vs/editor/browser/widget/diffEditorWidget';
import * as modes from 'vs/editor/common/modes';
import {EditorModelManager} from 'vs/editor/common/services/editorWorkerServiceImpl';
import {SimpleWorkerClient} from 'vs/base/common/worker/simpleWorker';
import {DefaultWorkerFactory} from 'vs/base/worker/defaultWorkerFactory';
import {StandaloneWorker} from 'vs/editor/browser/standalone/standaloneWorker';
// Set defaults for standalone editor
DefaultConfig.editor.wrappingIndent = 'none';
@ -101,7 +106,7 @@ class StandaloneEditor extends CodeEditorWidget {
if (model) {
let e: IModelChangedEvent = {
oldModelUrl: null,
newModelUrl: model.getAssociatedResource().toString()
newModelUrl: model.uri.toString()
};
this.emit(EventType.ModelChanged, e);
}
@ -457,6 +462,87 @@ export function createCustomMode(language:ILanguage): TPromise<IMode> {
return modeService.getOrCreateMode(modeId);
}
export function registerTokensProvider(languageId:string, support:modes.ITokenizationSupport2): IDisposable {
startup.initStaticServicesIfNecessary();
let staticPlatformServices = ensureStaticPlatformServices(null);
return staticPlatformServices.modeService.registerTokenizationSupport2(languageId, support);
}
export function registerHoverProvider(languageId:string, support:HoverProvider): IDisposable {
return modes.HoverProviderRegistry.register(languageId, support);
}
interface IMonacoWebWorkerState<T> {
myProxy:StandaloneWorker;
foreignProxy:T;
modelMananger: EditorModelManager;
}
export class MonacoWebWorker<T> {
private _loaded: TPromise<IMonacoWebWorkerState<T>>;
private _client: SimpleWorkerClient<StandaloneWorker>;
constructor(modelService: IModelService, opts:IWebWorkerOptions) {
this._client = new SimpleWorkerClient<StandaloneWorker>(new DefaultWorkerFactory(), 'vs/editor/browser/standalone/standaloneWorker', null);
this._loaded = this._client.getProxyObject().then((proxy) => {
let proxyMethodRequest = (method:string, args:any[]): TPromise<any> => {
return proxy.fmr(method, args);
};
let createProxyMethod = (method:string, proxyMethodRequest:(method:string, args:any[])=>TPromise<any>): Function => {
return function () {
let args = Array.prototype.slice.call(arguments, 0);
return proxyMethodRequest(method, args);
};
};
const manager = new EditorModelManager(proxy, modelService, true);
return proxy.loadModule(opts.moduleId).then((foreignMethods): IMonacoWebWorkerState<T> => {
let foreignProxy = <T><any>{};
for (let i = 0; i < foreignMethods.length; i++) {
foreignProxy[foreignMethods[i]] = createProxyMethod(foreignMethods[i], proxyMethodRequest);
}
return {
myProxy: proxy,
foreignProxy: foreignProxy,
modelMananger: manager
};
});
});
}
public dispose(): void {
console.log('TODO: I should dispose now');
}
public getProxy(): TPromise<T> {
return this._loaded.then(data => data.foreignProxy);
}
public withSyncedResources(resources: URI[]): TPromise<void> {
return this._loaded.then(data => data.modelMananger.withSyncedResources(resources));
}
}
export interface IWebWorkerOptions {
moduleId: string;
}
export function createWebWorker<T>(opts:IWebWorkerOptions): MonacoWebWorker<T> {
startup.initStaticServicesIfNecessary();
let staticPlatformServices = ensureStaticPlatformServices(null);
let modelService = staticPlatformServices.modelService;
return new MonacoWebWorker(modelService, opts);
}
export function registerMonarchStandaloneLanguage(language:ILanguageExtensionPoint, defModule:string): void {
ModesRegistry.registerLanguage(language);
@ -501,6 +587,10 @@ export function registerStandaloneLanguage(language:ILanguageExtensionPoint, def
});
}
export function registerStandaloneLanguage2(language:ILanguageExtensionPoint, defModule:string): void {
ModesRegistry.registerLanguage(language);
}
export function registerStandaloneSchema(uri:string, schema:IJSONSchema) {
let schemaRegistry = <IJSONContributionRegistry>Registry.as(Extensions.JSONContribution);
schemaRegistry.registerSchema(uri, schema);

View file

@ -7,12 +7,15 @@
import 'vs/editor/standalone-languages/all';
import './standaloneSchemas';
import 'vs/css!./media/standalone-tokens';
import {Emitter} from 'vs/base/common/event';
import {IJSONSchema} from 'vs/base/common/jsonSchema';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {ClassNames, ContentWidgetPositionPreference, OverlayWidgetPositionPreference} from 'vs/editor/browser/editorBrowser';
import {Colorizer} from 'vs/editor/browser/standalone/colorizer';
import * as standaloneCodeEditor from 'vs/editor/browser/standalone/standaloneCodeEditor';
import {ILanguageDef} from 'vs/editor/standalone-languages/types';
// import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry';
import {ExtensionsRegistry} from 'vs/platform/extensions/common/extensionsRegistry';
var global:any = self;
if (!global.Monaco) {
@ -77,3 +80,34 @@ if (!Monaco.Languages) {
Monaco.Languages = {};
}
Monaco.Languages.register = standaloneCodeEditor.registerStandaloneLanguage;
Monaco.Languages.register2 = standaloneCodeEditor.registerStandaloneLanguage2;
Monaco.Languages.onLanguage = (languageId:string, callback:()=>void) => {
let isDisposed = false;
ExtensionsRegistry.registerOneTimeActivationEventListener('onLanguage:' + languageId, () => {
if (!isDisposed) {
callback();
}
});
return {
dispose: () => { isDisposed = true; }
};
};
Monaco.createWebWorker = standaloneCodeEditor.createWebWorker;
Monaco.Languages.registerTokensProvider = standaloneCodeEditor.registerTokensProvider;
Monaco.Languages.registerHoverProvider = standaloneCodeEditor.registerHoverProvider;
Monaco.Emitter = Emitter;
// let handlePlugin = (plugin) => {
// if (Array.isArray(plugin.languages)) {
// ModesRegistry.registerLanguages(plugin.languages);
// }
// if (plugin.activate) {
// try {
// plugin.activate();
// } catch(err) {
// console.error(err);
// }
// }
// };
// let MonacoPlugins = this.MonacoPlugins || [];
// MonacoPlugins.forEach(handlePlugin);
// this.MonacoPlugins = { push: handlePlugin };

Some files were not shown because too many files have changed in this diff Show more