提交 711ef2ec 编写于 作者: A Alex Dima

Merge remote-tracking branch 'origin/master' into alex/perf

......@@ -104,7 +104,7 @@ var config = {
name: product.nameLong + ' document',
role: 'Editor',
ostypes: ["TEXT", "utxt", "TUTX", "****"],
extensions: ["ascx", "asp", "aspx", "bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "bat", "bowerrc", "c", "cc", "clj", "cljs", "cljx", "clojure", "cmd", "coffee", "config", "cpp", "cs", "cshtml", "csproj", "css", "csx", "ctp", "cxx", "dockerfile", "dot", "dtd", "editorconfig", "edn", "eyaml", "eyml", "fs", "fsi", "fsscript", "fsx", "gemspec", "gitattributes", "gitconfig", "gitignore", "go", "h", "handlebars", "hbs", "hh", "hpp", "htm", "html", "hxx", "ini", "jade", "jav", "java", "js", "jscsrc", "jshintrc", "jshtm", "json", "jsp", "less", "lua", "m", "makefile", "markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn", "ml", "mli", "nqp", "p6", "php", "phtml", "pl", "pl6", "pm", "pm6", "pod", "pp", "profile", "properties", "ps1", "psd1", "psgi", "psm1", "py", "r", "rb", "rhistory", "rprofile", "rs", "rt", "scss", "sh", "shtml", "sql", "svg", "svgz", "t", "ts", "txt", "vb", "wxi", "wxl", "wxs", "xaml", "xml", "yaml", "yml", "zsh"],
extensions: ["ascx", "asp", "aspx", "bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "bat", "bowerrc", "c", "cc", "clj", "cljs", "cljx", "clojure", "cmd", "coffee", "config", "cpp", "cs", "cshtml", "csproj", "css", "csx", "ctp", "cxx", "dockerfile", "dot", "dtd", "editorconfig", "edn", "eyaml", "eyml", "fs", "fsi", "fsscript", "fsx", "gemspec", "gitattributes", "gitconfig", "gitignore", "go", "h", "handlebars", "hbs", "hh", "hpp", "htm", "html", "hxx", "ini", "jade", "jav", "java", "js", "jscsrc", "jshintrc", "jshtm", "json", "jsp", "less", "lua", "m", "makefile", "markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn", "ml", "mli", "nqp", "p6", "php", "phtml", "pl", "pl6", "pm", "pm6", "pod", "pp", "profile", "properties", "ps1", "psd1", "psgi", "psm1", "py", "r", "rb", "rhistory", "rprofile", "rs", "rt", "scss", "sh", "shtml", "sql", "svg", "svgz", "t", "ts", "txt", "vb", "wxi", "wxl", "wxs", "xaml", "xml", "yaml", "yml", "zlogin", "zlogout", "zprofile", "zsh", "zshenv", "zshrc"],
iconFile: 'resources/darwin/code_file.icns'
}],
darwinCredits: darwinCreditsTemplate ? new Buffer(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : void 0,
......
......@@ -9,42 +9,132 @@
"properties": {
"compilerOptions": {
"type": "object",
"description": "Instructs the JavaScript language service how to validate .js files",
"description": "Instructs the JavaScript language service how to validate and down level compile .js files",
"properties": {
"charset": {
"description": "The character set of the input files",
"type": "string"
},
"diagnostics": {
"description": "Show diagnostic information.",
"description": "When down-level compiling, show diagnostic information.",
"type": "boolean"
},
"locale": {
"description": "The locale to use to show error messages, e.g. en-us.",
"emitBOM": {
"description": "When down-level compiling, emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files.",
"type": "boolean"
},
"inlineSourceMap": {
"description": "When down-level compiling, emit a single file with source maps instead of having a separate file.",
"type": "boolean"
},
"inlineSources": {
"description": "When down-level compiling, emit the source alongside the sourcemaps within a single file; requires --inlineSourceMap to be set.",
"type": "boolean"
},
"jsx": {
"description": "When down-level compiling, specify JSX code generation: 'preserve' or 'react'.",
"enum": [
"preserve",
"react"
]
},
"reactNamespace": {
"description": "When down-level compiling, specifies the object invoked for createElement and __spread when targeting 'react' JSX emit.",
"type": "string"
},
"listFiles": {
"description": "When down-level compiling, print names of files part of the compilation.",
"type": "boolean"
},
"mapRoot": {
"description": "Specifies the location where debugger should locate map files instead of generated locations",
"description": "When down-level compiling, specifies the location where debugger should locate map files instead of generated locations",
"type": "string",
"format": "uri"
},
"module": {
"description": "Specify used module type: 'commonjs', 'system', 'umd', 'es6', or 'es2015'. Note: 'amd' is currently not supported.",
"description": "When down-level compiling, specify module code generation: 'commonjs', 'system', 'umd', 'amd', 'es6', or 'es2015'.",
"enum": [
"commonjs",
"umd",
"amd",
"system",
"es6",
"es2015"
]
},
"newLine": {
"description": "When down-level compiling, specifies the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).",
"enum": [
"CRLF",
"LF"
]
},
"noEmit": {
"description": "When down-level compiling, do not emit output.",
"type": "boolean"
},
"noEmitHelpers": {
"description": "When down-level compiling, do not generate custom helper functions like __extends in compiled output.",
"type": "boolean"
},
"noEmitOnError": {
"description": "When down-level compiling, do not emit outputs if any type checking errors were reported.",
"type": "boolean"
},
"noLib": {
"description": "Do not include the default library file (lib.d.ts).",
"type": "boolean"
},
"noResolve": {
"description": "When down-level compiling, do not resolve triple-slash references or module import targets to the input files.",
"type": "boolean"
},
"skipDefaultLibCheck": {
"description": "Do not check for the default library (lib.d.ts).",
"type": "boolean"
},
"outFile": {
"description": "When down-level compiling, concatenate and emit output to single file.",
"type": "string",
"format": "uri"
},
"outDir": {
"description": "When down-level compiling, redirect output structure to the directory.",
"type": "string",
"format": "uri"
},
"pretty": {
"description": "When down-level compiling, stylize errors and messages using color and context. (experimental)",
"type": "boolean"
},
"removeComments": {
"description": "When down-level compiling, do not emit comments to output.",
"type": "boolean"
},
"rootDir": {
"description": "When down-level compiling, specifies the root directory of input files. Use to control the output directory structure with --outDir.",
"type": "string",
"format": "uri"
},
"isolatedModules": {
"description": "When down-level compiling, unconditionally emit imports for unresolved files.",
"type": "boolean"
},
"sourceMap": {
"description": "When down-level compiling, generates corresponding '.map' file.",
"type": "boolean"
},
"sourceRoot": {
"description": "When down-level compiling, specifies the location where debugger should locate JavaScript files instead of source locations.",
"type": "string",
"format": "uri"
},
"stripInternal": {
"description": "When down-level compiling, do not emit declarations for code that has an '@internal' annotation.",
"type": "boolean"
},
"target": {
"description": "Specify ECMAScript target version.",
"description": "Specifies which default library (lib.d.ts) to use. When down-level compiling, specifies the code being generated.",
"enum": [
"ES3",
"ES5",
......@@ -56,9 +146,41 @@
],
"default": "ES6"
},
"watch": {
"description": "When down-level compiling, watch input files.",
"type": "boolean"
},
"experimentalDecorators": {
"description": "Enables experimental support for ES7 decorators.",
"description": "Enables experimental support for proposed ES decorators.",
"type": "boolean"
},
"emitDecoratorMetadata": {
"description": "When down-level compiling, emit design-type metadata for decorated declarations in source.",
"type": "boolean"
},
"allowUnusedLabels": {
"type": "boolean",
"description": "Do not report errors on unused labels."
},
"noFallthroughCasesInSwitch": {
"type": "boolean",
"description": "Report errors for fallthrough cases in switch statement."
},
"allowUnreachableCode": {
"type": "boolean",
"description": "Do not report errors on unreachable code."
},
"forceConsistentCasingInFileNames": {
"type": "boolean",
"description": "Disallow inconsistently-cased references to the same file."
},
"allowSyntheticDefaultImports": {
"type": "boolean",
"description": "Allow default imports from modules with no default export. This does not affect code emit, just typechecking."
},
"noImplicitUseStrict": {
"type": "boolean",
"description": "When down-level compiling, do not emit \"use strict\" directives in module output."
}
}
},
......@@ -79,4 +201,4 @@
}
}
}
}
\ No newline at end of file
}
......@@ -7,7 +7,7 @@
"languages": [{
"id": "shellscript",
"aliases": ["Shell Script (Bash)", "shellscript", "bash", "sh", "zsh"],
"extensions": [".sh", ".bash", ".bashrc", ".bash_profile", ".bash_login", ".profile", ".bash_logout", ".zsh", ".zshrc"],
"extensions": [".sh", ".bash", ".bashrc", ".bash_profile", ".bash_login", ".profile", ".bash_logout", ".zsh", ".zshrc", ".zprofile", ".zlogin", ".zlogout", ".zshenv"],
"firstLine": "^#!.*\\b(bash|zsh|sh|tcsh)|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-",
"configuration": "./shellscript.configuration.json",
"mimetypes": ["text/x-shellscript"]
......
......@@ -190,7 +190,7 @@ const defaultConfig = `{
// See http://go.microsoft.com/fwlink/?LinkId=759670
// for the documentation about the jsconfig.json format
"compilerOptions": {
"module": "commonjs"
"target": "es6"
},
"exclude": [
"node_modules",
......
......@@ -25,4 +25,4 @@ CODE_SOURCE_LIST=$APT_SOURCE_PARTS/visual-studio-@@NAME@@.list
rm -f $CODE_SOURCE_LIST
# TODO: #2973: Enable once the apt repository is signed
#echo "deb @@UPDATEURL@@/api/deb/@@QUALITY@@/ @@ARCHITECTURE@@/" > $CODE_SOURCE_LIST
#echo "deb @@UPDATEURL@@/api/deb/@@QUALITY@@/@@ARCHITECTURE@@/ /" > $CODE_SOURCE_LIST
......@@ -15,14 +15,20 @@ Visual Studio Code is a new choice of tool that combines the simplicity of a cod
%install
mkdir -p %{buildroot}/usr/bin
cp -r usr/bin/@@NAME@@ %{buildroot}/usr/bin
mkdir -p %{buildroot}/usr/share/@@NAME@@
cp -r usr/share/@@NAME@@/* %{buildroot}/usr/share/@@NAME@@
mkdir -p %{buildroot}/usr/share/applications
cp -r usr/share/applications/@@NAME@@.desktop %{buildroot}/usr/share/applications
mkdir -p %{buildroot}/usr/share/pixmaps
cp -r usr/bin/@@NAME@@ %{buildroot}/usr/bin
cp -r usr/share/@@NAME@@/* %{buildroot}/usr/share/@@NAME@@
cp -r usr/share/applications/@@NAME@@.desktop %{buildroot}/usr/share/applications
cp -r usr/share/pixmaps/@@NAME@@.png %{buildroot}/usr/share/pixmaps
%post
# Remove the legacy bin command if this is the stable build
if [ "@@NAME@@" = "code" ]; then
rm -f /usr/local/bin/code
fi
%files
%defattr(-,root,root)
......
......@@ -8,9 +8,6 @@ import { globals } from 'vs/base/common/platform';
export const enableTasks = environment('enableTasks');
export const enableSendASmile = environment('enableSendASmile');
export const enableJavaScriptRewriting = environment('enableJavaScriptRewriting');
export const enableTypeScriptServiceMode = environment('enableTypeScriptServiceMode');
export const enableTypeScriptServiceModeForJS = environment('enableTypeScriptServiceModeForJS');
// Telemetry endpoint (used in the standalone editor) for hosts that want to collect editor telemetry
export const standaloneEditorTelemetryEndpoint:string = environment('telemetryEndpoint', null);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// copied from TypeScript/src/compiler/core/hash.ts and adjusted to external module syntax
'use strict';
export function computeMurmur2StringHashCode(key: string): number {
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
var m = 0x5bd1e995;
var r = 24;
var start = 0;
var len = key.length;
var numberOfCharsLeft = len;
// Initialize the hash to a 'random' value.
var h = (0 ^ numberOfCharsLeft);
// Mix 4 bytes at a time into the hash. NOTE: 4 bytes is two chars, so we iterate
// through the string two chars at a time.
var index = start;
while (numberOfCharsLeft >= 2) {
var c1 = key.charCodeAt(index);
var c2 = key.charCodeAt(index + 1);
var k = c1 | (c2 << 16);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
index += 2;
numberOfCharsLeft -= 2;
}
// Handle the last char (or 2 bytes) if they exist. This happens if the original string had
// odd length.
if (numberOfCharsLeft === 1) {
h ^= key.charCodeAt(index);
h *= m;
}
// Do a few final mixes of the hash to ensure the last few bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
export function combine(value:number, currentHash:number): number {
// Ensure we stay within 31 bits.
return (((currentHash << 5) + currentHash) + value) & 0x7FFFFFFF;
}
\ No newline at end of file
......@@ -39,6 +39,8 @@ export default class URI {
private _path: string;
private _query: string;
private _fragment: string;
private _formatted: string;
private _fsPath: string;
constructor() {
this._scheme = URI._empty;
......@@ -46,6 +48,9 @@ export default class URI {
this._path = URI._empty;
this._query = URI._empty;
this._fragment = URI._empty;
this._formatted = null;
this._fsPath = null;
}
/**
......@@ -87,8 +92,6 @@ export default class URI {
// ---- filesystem path -----------------------
private _fsPath: string;
/**
* Returns a string representing the corresponding file system path of this URI.
* Will handle UNC paths and normalize windows drive letters to lower-case. Also
......@@ -232,8 +235,6 @@ export default class URI {
// ---- printing/externalize ---------------------------
private _formatted: string;
public toString(): string {
if (!this._formatted) {
var parts: string[] = [];
......
......@@ -650,21 +650,21 @@ class Renderer implements IRenderer<QuickOpenEntry> {
public disposeTemplate(templateId: string, templateData: any): void {
if (templateId === templateEntryItem) {
this.entryItemRenderer.disposeTemplate(null, templateId, templateData);
} else {
const data = templateData as IQuickOpenEntryGroupTemplateData;
data.actionBar.dispose();
data.actionBar = null;
data.container = null;
data.description.dispose();
data.description = null;
data.detail.dispose();
data.detail = null;
data.group = null;
data.icon = null;
data.label.dispose();
data.label = null;
data.prefix = null;
}
const data = templateData as IQuickOpenEntryGroupTemplateData;
data.actionBar.dispose();
data.actionBar = null;
data.container = null;
data.description.dispose();
data.description = null;
data.detail.dispose();
data.detail = null;
data.group = null;
data.icon = null;
data.label.dispose();
data.label = null;
data.prefix = null;
}
}
......
......@@ -135,7 +135,7 @@ class SortLinesDescendingAction extends SortLinesAction {
}
}
class TrimTrailingWhitespaceAction extends EditorAction {
export class TrimTrailingWhitespaceAction extends EditorAction {
static ID = 'editor.action.trimTrailingWhitespace';
......
......@@ -4,9 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import platform = require('vs/platform/platform');
import typescript = require('vs/languages/typescript/common/typescript');
import {AsyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
import ts = require('vs/languages/typescript/common/lib/typescriptServices');
export namespace Defaults {
......@@ -20,24 +18,4 @@ export namespace Defaults {
export function setCompilerOptions(options: ts.CompilerOptions): void {
ProjectResolver.setCompilerOptions(options);
}
}
// ----- JavaScript extension ---------------------------------------------------------------
export namespace Extensions {
export var Identifier = 'javascript';
platform.Registry.add(Identifier, Extensions);
var projectResolver: AsyncDescriptor<typescript.IProjectResolver2>;
export function setProjectResolver(desc: AsyncDescriptor<typescript.IProjectResolver2>): void {
projectResolver = desc;
}
export function getProjectResolver(): AsyncDescriptor<typescript.IProjectResolver2> {
return projectResolver;
}
}
......@@ -122,7 +122,7 @@ export class JSMode extends typescriptMode.TypeScriptMode<javascriptWorker.JavaS
// ---- specialize by override
protected _getProjectResolver(): AsyncDescriptor<typescript.IProjectResolver2>|typescript.IProjectResolver2 {
return extensions.Extensions.getProjectResolver() || extensions.Defaults.ProjectResolver;
return extensions.Defaults.ProjectResolver;
}
_shouldBeValidated(model: EditorCommon.IModel): boolean {
......
/*---------------------------------------------------------------------------------------------
* 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 env = require('vs/base/common/flags');
import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry';
import javascript = require('vs/languages/javascript/common/javascript.extensions');
import typescript = require('vs/languages/typescript/common/typescript');
import {AsyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
// contributes the project resolver logic to TypeScript and JavaScript
// this guy is for the workbench, but not for the standalone editor
if (env.enableJavaScriptRewriting && !env.enableTypeScriptServiceModeForJS) {
ModesRegistry.registerWorkerParticipant('javascript', 'vs/languages/typescript/common/js/globalVariableRewriter', 'GlobalVariableCollector');
ModesRegistry.registerWorkerParticipant('javascript', 'vs/languages/typescript/common/js/angularServiceRewriter', 'AngularServiceRewriter');
ModesRegistry.registerWorkerParticipant('javascript', 'vs/languages/typescript/common/js/requireRewriter');
ModesRegistry.registerWorkerParticipant('javascript', 'vs/languages/typescript/common/js/defineRewriter');
ModesRegistry.registerWorkerParticipant('javascript', 'vs/languages/typescript/common/js/es6PropertyDeclarator');
ModesRegistry.registerWorkerParticipant('javascript', 'vs/languages/typescript/common/js/importAndExportRewriter', 'ImportsAndExportsCollector');
}
typescript.Extensions.setProjectResolver(new AsyncDescriptor<typescript.IProjectResolver2>(
'vs/languages/typescript.workbench/common/projectResolver', undefined, { files: '**/*.ts', projects: '**/tsconfig.json', maxFilesPerProject: 1500 }));
javascript.Extensions.setProjectResolver(new AsyncDescriptor<typescript.IProjectResolver2>(
'vs/languages/typescript.workbench/common/projectResolver', undefined, { files: '{**/*.js,**/*.d.ts}', projects: '**/jsconfig.json', maxFilesPerProject: 750 }));
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* 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 glob from 'vs/base/common/glob';
import * as nls from 'vs/nls';
import * as objects from 'vs/base/common/objects';
import * as typescript from 'vs/languages/typescript/common/typescript';
import * as lifecycle from 'vs/base/common/lifecycle';
import * as errors from 'vs/base/common/errors';
import * as collections from 'vs/base/common/collections';
import * as async from 'vs/base/common/async';
import * as winjs from 'vs/base/common/winjs.base';
import Severity from 'vs/base/common/severity';
import URI from 'vs/base/common/uri';
import * as paths from 'vs/base/common/paths';
import * as ts from 'vs/languages/typescript/common/lib/typescriptServices';
import {IModelService} from 'vs/editor/common/services/modelService';
import {IEventService} from 'vs/platform/event/common/event';
import * as Files from 'vs/platform/files/common/files';
import {IMarkerService} from 'vs/platform/markers/common/markers';
import {IMessageService} from 'vs/platform/message/common/message';
import {ISearchService, QueryType} from 'vs/platform/search/common/search';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
interface $ProjectPerf {
start: number;
d: number;
files: number;
projects: number;
}
const defaultExcludeSegments: string[] = [
'/.git/',
'/node_modules/',
'/bower_components/',
'/jspm_packages/',
'/tmp/',
'/temp/',
];
class ProjectFileEventListener {
private static _ignores = defaultExcludeSegments.map(s => paths.normalize(s, true));
private _excludes: string[];
private _includes: string[];
constructor(private _baseDir: string, files: string[], exclude: string[]) {
this._baseDir = paths.normalize(this._baseDir, true);
if (Array.isArray(files)) {
this._includes = [];
for (let relativePath of files) {
this._includes.push(paths.normalize(paths.join(this._baseDir, relativePath), true));
}
}
if (Array.isArray(exclude)) {
this._excludes = [];
for (let relativePath of exclude) {
this._excludes.push(paths.normalize(paths.join(this._baseDir, relativePath), true));
}
}
}
handleChange(resource:URI):boolean {
// hard-coded list of folders to ignore
for(let ignore of ProjectFileEventListener._ignores) {
if(resource.fsPath.indexOf(ignore) !== -1) {
return false;
}
}
// must be in the project dir
if(this._baseDir && resource.fsPath.indexOf(this._baseDir) !== 0) {
return false;
}
// the resource is not on the include list
if(this._includes && this._includes.indexOf(resource.fsPath) < 0) {
return false;
}
// the resource matches an item from the exclude list
if(this._excludes && this._excludes
.some(exclude => resource.fsPath.indexOf(exclude) === 0)) {
return false;
}
return true;
}
}
class VirtualProjectFileEventListener extends ProjectFileEventListener {
handleChange(resource: URI): boolean {
return /\.d\.ts$/.test(resource.fsPath) && super.handleChange(resource);
}
}
class ProjectResolver implements typescript.IProjectResolver2 {
private static _defaultExcludePattern = `{${defaultExcludeSegments.map(s => `**${s}**`).join(',')}}`;
private static _defaultExcludePatternForVirtualProject = `{**/lib*.d.ts,${defaultExcludeSegments.map(s => `**${s}**`).join(',')}}`;
private _fileService: Files.IFileService;
private _searchService: ISearchService;
private _eventService: IEventService;
private _markerService: IMarkerService;
private _messageService: IMessageService;
private _modelService: IModelService;
private _telemetryService: ITelemetryService;
private _workspace: URI;
private _consumer: typescript.IProjectConsumer;
private _configuration: { files: string; projects: string; maxFilesPerProject: number;};
private _projectsIndex: {[dirname:string]:URI};
private _projectDiscovery: winjs.TPromise<void>;
private _fileChangesHandler: async.RunOnceScheduler;
private _fileChangeEvents: Files.IFileChange[] = [];
private _projectFileEventListener: { [r: string]: ProjectFileEventListener } = Object.create(null);
private _projectPromises: { [r: string]: winjs.TPromise<typescript.IProjectChange> } = Object.create(null);
private _pendingFiles: { [r: string]: { resource: URI; kind: typescript.ChangeKind } } = Object.create(null);
private _unbindListener: Function;
constructor(configuration: { files: string; projects: string; maxFilesPerProject: number; },
consumer: typescript.IProjectConsumer,
@Files.IFileService fileService: Files.IFileService,
@ISearchService searchService: ISearchService,
@IEventService eventService: IEventService,
@IMarkerService markerService: IMarkerService,
@IMessageService messageService: IMessageService,
@IModelService modelService: IModelService,
@ITelemetryService telemetryService: ITelemetryService,
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
this._fileService = fileService;
this._searchService = searchService;
this._eventService = eventService;
this._markerService = markerService;
this._messageService = messageService;
this._modelService = modelService;
this._telemetryService = telemetryService;
this._workspace = contextService.getWorkspace() && contextService.getWorkspace().resource;
this._consumer = consumer;
this._configuration = configuration;
this._fileChangesHandler = new async.RunOnceScheduler(this._processFileChangesEvents.bind(this), 1000);
this._unbindListener = this._eventService.addListener(Files.EventType.FILE_CHANGES,
this._onFileChangesEvent.bind(this));
}
public dispose(): void {
lifecycle.cAll(this._unbindListener);
}
public setConsumer(consumer:typescript.IProjectConsumer):void {
this._consumer = consumer;
}
public resolveProjects(): winjs.TPromise<any> {
if (this._workspace) {
var result = this._resolve;
if (!result) {
result = this._resolve = this._doResolve();
async.always(this._resolve, ():void => this._resolve = null);
}
return new async.ShallowCancelThenPromise(result);
}
}
public resolveFiles(resources: URI[]): winjs.TPromise<any> {
// fetch only file-resources from disk
resources = resources.filter(resource => resource.scheme === 'file');
if (resources.length) {
var handle = this._messageService.setStatusMessage(
nls.localize('resolve.files.N', "Loading additional files..."), undefined, 250);
var result = this._fileService.resolveContents(resources).then(contents => {
var changes = contents.map(c => {
return <typescript.IFileChange> {
kind: typescript.ChangeKind.Added,
content: c.value,
resource: c.resource
};
});
return this._consumer.acceptFileChanges(changes)
.then(undefined, err => this._messageService.show(Severity.Warning, err));
});
return async.always(result, () => handle.dispose());
}
}
private _resolve: winjs.TPromise<any>;
private _doResolve(): winjs.TPromise<any> {
var $perf: $ProjectPerf = {
start: Date.now(),
d: 0,
projects: 0,
files: 0
};
var p = this.projectDiscovery().then(_ => {
// [read] all tsconfig.json files
var promises: winjs.TPromise<typescript.IProjectChange>[] = [];
for (var key in this._projectPromises) {
promises.push(this._projectPromises[key]);
delete this._projectPromises[key];
}
return winjs.TPromise.join(promises);
}).then(projectChanges => {
// [send] all project changes to worker
$perf.projects = projectChanges.length;
if (projectChanges.length) {
return this._consumer.acceptProjectChanges(projectChanges).then(projectsIndex => {
// TODO@Alex AllThreads returns falsy result
this._projectsIndex = (<any>projectsIndex)[0];
});
}
}).then(_ => {
// [read] all project source files, persist change kind
var toFetch: URI[] = [],
changes: typescript.IFileChange[] = [],
pendingFiles = objects.clone(this._pendingFiles);
for (var key in this._pendingFiles) {
var kind = this._pendingFiles[key].kind;
var resource = this._pendingFiles[key].resource;
if (this._pendingFiles[key].kind === typescript.ChangeKind.Removed) {
changes.push({ kind, resource, content: undefined });
} else {
// changed or added
toFetch.push(resource);
$perf.files += 1;
}
delete this._pendingFiles[key];
}
if (toFetch.length) {
return this._fileService.resolveContents(toFetch).then(contents => {
contents.forEach(fileContent => {
changes.push({
resource: fileContent.resource,
content: fileContent.value,
kind: pendingFiles[fileContent.resource.toString()].kind
});
delete pendingFiles[fileContent.resource.toString()];
});
// if (toFetch.length !== contents.length) {
// console.warn('files that are MISSING: ', Object.keys(pendingFiles));
// }
// [send] all project source files
return this._consumer.acceptFileChanges(changes)
.then(undefined, err => this._messageService.show(Severity.Warning, err));
});
} else if (changes.length) {
// [send] all project source files
return this._consumer.acceptFileChanges(changes)
.then(undefined, err => this._messageService.show(Severity.Warning, err));
}
}).then(_ => {
// perf numbers
$perf.d = Date.now() - $perf.start;
// console.log('[ts] resolve done', $perf);
});
return p;
}
private projectDiscovery() {
if (!this._projectDiscovery) {
this._projectDiscovery = this._searchResources(this._configuration.projects).then(result => {
this._resolveProject(typescript.virtualProjectResource, typescript.ChangeKind.Added);
for (let resource of result.resources) {
this._resolveProject(resource, typescript.ChangeKind.Added);
}
});
// TODO@Joh count how often this fails and stop trying
this._projectDiscovery.done(undefined, err => {
this._projectDiscovery = null;
console.error(err);
});
}
return this._projectDiscovery;
}
private _searchResources(globPattern: string, maxResults: number = 1500, root: URI = this._workspace, excludes?: string[]): winjs.TPromise<{ resources: URI[]; limitReached: boolean; }> {
let includePattern:glob.IExpression = {};
includePattern[globPattern] = true;
let excludePattern: glob.IExpression = Object.create(null);
excludePattern[ProjectResolver._defaultExcludePattern] = true;
// add custom exclude patterns
if(Array.isArray(excludes)) {
for (let exclude of excludes) {
exclude = exclude.replace(/^[\\\/]/, '').replace(/[\\\/]$/, '');
excludePattern[`${exclude}/**`] = true;
}
}
return this._searchService.search({
folderResources: [root],
type: QueryType.File,
maxResults,
includePattern,
excludePattern,
}).then(complete => {
return {
resources: complete.results.map(r => r.resource),
limitReached: complete.limitHit
};
});
}
private _resolveProject(resource: URI, kind: typescript.ChangeKind): void {
var dirname = paths.dirname(resource.fsPath);
var p = this._doResolveProject(resource, kind);
this._projectPromises[dirname] = this._projectPromises[dirname] && this._projectPromises[dirname].then(_ => p, _ => p) || p;
p.done(undefined, err => {
if (!errors.isPromiseCanceledError(err)) {
console.error(resource.toString(), kind, err);
}
});
}
private _doResolveProject(resource: URI, kind: typescript.ChangeKind): winjs.TPromise<typescript.IProjectChange> {
return resource.toString() === typescript.virtualProjectResource.toString()
? this._doResolveVirtualProject(kind)
: this._doResolveProjectFile(resource, kind);
}
private _doResolveProjectFile(resource: URI, kind: typescript.ChangeKind): winjs.TPromise<typescript.IProjectChange> {
// remove markers
this._markerService.remove('ts.projectResolver', [resource]);
// removed project
if (kind === typescript.ChangeKind.Removed) {
delete this._projectFileEventListener[resource.toString()];
return winjs.TPromise.as({ kind, resource, files: undefined, options: undefined });
}
// added or changed project
let data: typescript.IProjectChange = {
kind,
resource,
files: <URI[]>[],
options: ts.getDefaultCompilerOptions()
};
let fileLimitReached = false;
return this._fileService.resolveContent(resource).then(content => {
let parsed = ts.parseConfigFileText(resource.fsPath, content.value),
basePath = paths.dirname(resource.fsPath);
if (parsed.error) {
this._markerService.changeOne('ts.projectResolver', resource, [{
message: parsed.error.messageText.toString(),
code: parsed.error.code.toString(),
severity: Severity.Error,
startLineNumber: 1,
startColumn: 1,
endLineNumber: 1,
endColumn: 1
}]);
return winjs.TPromise.wrapError(errors.canceled());
}
// compiler options
data.options = ts.parseConfigFile(parsed.config, { readDirectory: () => [] }, basePath).options;
// add/replace project event listener
this._projectFileEventListener[resource.toString()] = new ProjectFileEventListener(
basePath, parsed.config['files'], parsed.config['exclude']);
// files
if (Array.isArray(parsed.config['files'])) {
var files = (<string[]> parsed.config['files'])
.map(path => paths.join(basePath, path))
.map(path => URI.file(path));
data.files = files;
if (data.files.length > this._configuration.maxFilesPerProject) {
data.files.length = this._configuration.maxFilesPerProject;
fileLimitReached = true;
}
} else {
// glob
// we also get into this when the files property isn't formulated
// properly. This isn't über-correct but nice to the user
return this._searchResources(this._configuration.files, this._configuration.maxFilesPerProject,
URI.file(basePath), parsed.config['exclude']).then(result => {
fileLimitReached = result.limitReached;
data.files = result.resources;
});
}
}).then(_ => {
if (kind === typescript.ChangeKind.Added) {
// add all files of this project to the fetch list
data.files.forEach(resource => this._pendingFiles[resource.toString()] = { resource, kind });
// send telemetry info about compiler options and number of files
this._telemetryService.publicLog('js.project', {
compilerOptions: data.options,
fileCount: data.files.length
});
}
if (fileLimitReached) {
// send another telemetry event when there a too many files
this._telemetryService.publicLog('js.project.fileLimitReached', { maxFilesPerProject: this._configuration.maxFilesPerProject });
}
return data;
});
}
private _doResolveVirtualProject(kind: typescript.ChangeKind): winjs.TPromise<typescript.IProjectChange> {
// when starting we optimistically configure the virtual
// project with the first 50 d.ts files we find in the
// workspace
this._projectFileEventListener[typescript.virtualProjectResource.toString()] =
new VirtualProjectFileEventListener(undefined, undefined, undefined);
let excludePattern: glob.IExpression = Object.create(null);
excludePattern[ProjectResolver._defaultExcludePatternForVirtualProject] = true;
return this._searchService.search({
folderResources: [this._workspace],
type: QueryType.File,
maxResults: 50,
includePattern: { '**/*.d.ts': true },
excludePattern
}).then(result => {
let files: URI[] = [];
for (let match of result.results) {
files.push(match.resource);
this._pendingFiles[match.resource.toString()] = { resource: match.resource, kind };
}
return <typescript.IProjectChange> {
files,
resource: typescript.virtualProjectResource,
kind: typescript.ChangeKind.Changed,
options: undefined
};
});
}
private _onFileChangesEvent(e: Files.FileChangesEvent): void {
this._fileChangeEvents.push(...e.changes);
this._fileChangesHandler.schedule();
}
private _processFileChangesEvents() {
let projectEvents: { [r: string]: number[] } = Object.create(null);
let changes = this._fileChangeEvents.slice(0);
this._fileChangeEvents.length = 0;
let isAffectedByChanges = false;
changes.forEach(change => {
var kind: typescript.ChangeKind;
if (glob2.match(this._configuration.projects, change.resource.fsPath)) {
// update projects
kind = ProjectResolver._asChangeKind(change.type);
collections.lookupOrInsert(projectEvents, change.resource.toString(), []).push(kind);
isAffectedByChanges = true;
} else if (glob2.match(this._configuration.files, change.resource.fsPath)) {
kind = ProjectResolver._asChangeKind(change.type);
if (kind === typescript.ChangeKind.Changed && this._modelService.getModel(<any>change.resource)) {
// we have already seen this change
return;
}
collections.forEach(this._projectFileEventListener, entry => {
if (!entry.value.handleChange(change.resource)) {
// this listener is not interested in this change
// so we can return early
return;
}
this._pendingFiles[change.resource.toString()] = { kind, resource: change.resource };
isAffectedByChanges = true;
// in case this file as added or removed we need to tell
// project it has changed
if (kind === typescript.ChangeKind.Added || kind === typescript.ChangeKind.Removed) {
collections.lookupOrInsert(projectEvents, entry.key, []).push(typescript.ChangeKind.Changed);
}
});
}
});
// trigger project resolution for those that were collected earlier
for(let project in projectEvents) {
let value = projectEvents[project];
let lastKind: typescript.ChangeKind;
for(let kind of value) {
if (kind !== lastKind) {
lastKind = kind;
this._resolveProject(URI.parse(project), kind);
}
}
}
if(isAffectedByChanges) {
this.resolveProjects();
}
}
private static _asChangeKind(fileChangeType: Files.FileChangeType): typescript.ChangeKind {
switch (fileChangeType) {
case Files.FileChangeType.UPDATED: return typescript.ChangeKind.Changed;
case Files.FileChangeType.ADDED: return typescript.ChangeKind.Added;
case Files.FileChangeType.DELETED: return typescript.ChangeKind.Removed;
}
throw new Error('unknown change type');
}
}
namespace glob2 {
const prefix1 = '**/*.';
export function match(pattern: string, path: string): boolean {
if (pattern[0] === '{' && pattern[pattern.length - 1] === '}') {
var parts = pattern.substr(1, pattern.length - 2).split(',');
return parts.some(part => matchOne(part, path));
} else {
return matchOne(pattern, path);
}
}
function matchOne(pattern: string, path: string): boolean {
let offset = -1;
if (pattern.indexOf(prefix1) === 0) {
offset = prefix1.length;
}
if (offset === -1) {
return glob.match(pattern, path);
}
let suffix = pattern.substring(offset);
if (suffix.match(/[.\\\/*]/)) {
return glob.match(pattern, path);
}
// endWith check
offset = path.lastIndexOf(suffix);
if (offset === -1) {
return false;
} else {
return offset + suffix.length === path.length;
}
}
}
export = ProjectResolver;
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import assert = require('assert');
import URI from 'vs/base/common/uri';
import glob = require('vs/base/common/glob');
import winjs = require('vs/base/common/winjs.base');
import typescript = require('vs/languages/typescript/common/typescript');
import instantiation = require('vs/platform/instantiation/common/instantiationService');
import project = require('vs/languages/typescript/common/project/projectService');
import ts = require('vs/languages/typescript/common/lib/typescriptServices');
import ProjectResolver = require('vs/languages/typescript.workbench/common/projectResolver');
import {NULL_THREAD_SERVICE} from 'vs/platform/test/common/nullThreadService';
import markerService = require('vs/platform/markers/common/markerService');
import eventEmitter = require('vs/base/common/eventEmitter');
import EditorCommon = require('vs/editor/common/editorCommon');
import Files = require('vs/platform/files/common/files');
import {IModelService} from 'vs/editor/common/services/modelService';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IMessageService} from 'vs/platform/message/common/message';
import * as Search from 'vs/platform/search/common/search';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IWorkspaceContextService, IWorkspace} from 'vs/platform/workspace/common/workspace';
function createContextService(resource: URI = URI.file('/foo/bar')): IWorkspaceContextService {
function getWorkspace(): IWorkspace {
return {
resource,
id: undefined,
mtime: undefined,
name: undefined,
uid: undefined
}
};
return {
serviceId : IWorkspaceContextService,
getWorkspace,
getConfiguration: undefined,
getOptions: undefined,
toResource: undefined,
toWorkspaceRelativePath: undefined,
isInsideWorkspace: undefined
}
}
function createModelService(): IModelService {
function getModel(r: URI): EditorCommon.IModel {
return null;
}
return {
serviceId : IModelService,
getModel,
createModel: undefined,
getModels: undefined,
onModelAdded: undefined,
onModelRemoved: undefined,
onModelModeChanged: undefined,
destroyModel: undefined,
getCreationOptions: undefined
}
}
function createMessageService(): IMessageService {
return {
serviceId : IMessageService,
setStatusMessage: () => { return { dispose: () => { } } },
confirm: undefined,
hideAll: undefined,
show: undefined
};
}
function createSearchService(index:{ [n: string]: string } = Object.create(null)): Search.ISearchService {
function search(query: Search.ISearchQuery): winjs.PPromise<Search.ISearchComplete, Search.ISearchProgressItem> {
var results: Search.IFileMatch[] = [];
for (var key in index) {
var resource = URI.file(key);
if (glob.match(query.includePattern, resource.path)) {
results.push({
resource
});
}
}
return winjs.PPromise.as({
results
});
}
return {
serviceId : Search.ISearchService,
search
};
}
function createFileService(index: { [n: string]: string } = Object.create(null)): Files.IFileService {
function resolveContent(resource: URI): winjs.TPromise<Files.IContent> {
if (!index[resource.path]) {
return winjs.TPromise.as(null);
}
var result: Files.IContent = {
resource,
value: index[resource.path],
encoding: undefined,
etag: undefined,
mime: undefined,
mtime: undefined,
name: undefined
}
return winjs.TPromise.as(result);
}
function resolveContents(resources: URI[]): any {
var result: Files.IContent[] = [];
resources.forEach(resource => {
if (index[resource.path]) {
result.push({
resource,
value: index[resource.path],
encoding: undefined,
etag: undefined,
mime: undefined,
mtime: undefined,
name: undefined
});
}
});
return winjs.TPromise.as(result);
}
return {
serviceId : Files.IFileService,
resolveContent,
resolveContents,
copyFile: undefined,
createFile: undefined,
createFolder: undefined,
del: undefined,
dispose: undefined,
moveFile: undefined,
rename: undefined,
resolveFile: undefined,
updateContent: undefined,
updateOptions: undefined,
importFile: undefined,
watchFileChanges: undefined,
unwatchFileChanges: undefined
}
}
function createTelemetryService(): ITelemetryService {
function publicLog() {
}
return {
serviceId : ITelemetryService,
addTelemetryAppender: undefined,
dispose: undefined,
getAppenders: undefined,
getAppendersCount: undefined,
publicLog,
removeTelemetryAppender: undefined,
start: undefined,
getSessionId: undefined,
getInstanceId: undefined,
getMachineId: undefined,
getTelemetryInfo: undefined,
setInstantiationService: undefined
}
}
var instantiationService: IInstantiationService;
function setup() {
instantiationService = instantiation.createInstantiationService({
eventService: new eventEmitter.EventEmitter(),
markerService: new markerService.MainProcessMarkerService(NULL_THREAD_SERVICE),
fileService: createFileService(),
searchService: createSearchService(),
messageService: createMessageService(),
modelService: createModelService(),
contextService: createContextService(),
telemetryService: createTelemetryService()
});
}
suite('TS - Project Resolver', () => {
setup();
test('no workspace, no resolve', function () {
var resolver = instantiationService
.createChild({ contextService: createContextService(null) })
.createInstance(ProjectResolver, null, null);
var promise = resolver.resolveProjects();
assert.ok(promise === undefined);
});
test('project -> expand files', function (done) {
var fileChangesCount = 0,
projectChangesCount = 0;
var consumer: typescript.IProjectConsumer = {
acceptFileChanges: (changes):any => {
fileChangesCount += changes.length;
return winjs.TPromise.as([]);
},
acceptProjectChanges: (changes):any => {
projectChangesCount += changes.length;
return winjs.TPromise.as([]);
}
};
var files: { [n: string]: string } = Object.create(null);
files['/jsconfig.json'] = '{}';
files['/a.js'] = 'a';
files['/b.js'] = 'b';
files['/c.d.ts'] = 'c';
files['/d.ts'] = 'd';
var resolver = instantiationService.createChild({
searchService: createSearchService(files),
fileService: createFileService(files),
}).createInstance(
ProjectResolver, { files: '{**/*.js,**/*.d.ts}', projects: '**/jsconfig.json' }, consumer);
resolver.resolveProjects().then(_ => {
assert.equal(fileChangesCount, 3);
assert.equal(projectChangesCount, 2);
done();
}, err => {
assert.ok(false, JSON.stringify(err, null, 4));
done();
});
});
});
......@@ -6,7 +6,6 @@
import 'vs/css!./typescript';
import nls = require('vs/nls');
import env = require('vs/base/common/flags');
import platform = require('vs/platform/platform');
import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry';
import ConfigurationRegistry = require('vs/platform/configuration/common/configurationRegistry');
......@@ -15,122 +14,120 @@ let defaults = options.typeScriptOptions;
// ----- Registration and Configuration --------------------------------------------------------
if (!env.enableTypeScriptServiceMode) {
ModesRegistry.registerCompatMode({
id: 'typescript',
extensions: ['.ts'],
aliases: ['TypeScript', 'ts', 'typescript'],
mimetypes: ['text/typescript'],
moduleId: 'vs/languages/typescript/common/typescriptMode',
ctorName: 'TypeScriptMode'
});
ModesRegistry.registerCompatMode({
id: 'typescript',
extensions: ['.ts'],
aliases: ['TypeScript', 'ts', 'typescript'],
mimetypes: ['text/typescript'],
moduleId: 'vs/languages/typescript/common/typescriptMode',
ctorName: 'TypeScriptMode'
});
var configurationRegistry = <ConfigurationRegistry.IConfigurationRegistry>platform.Registry.as(ConfigurationRegistry.Extensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'typescript',
'order': 20,
'title': nls.localize('tsConfigurationTitle', "TypeScript configuration"),
'allOf': [
{
'type': 'object',
'title': nls.localize('suggestSettings', "Controls how TypeScript IntelliSense works."),
'properties': {
'typescript.suggest.alwaysAllWords': {
'type': 'boolean',
'default': defaults.suggest.alwaysAllWords,
'description': nls.localize('allwaysAllWords', "Always include all words from the current document."),
},
'typescript.suggest.useCodeSnippetsOnMethodSuggest': {
'type': 'boolean',
'default': defaults.suggest.useCodeSnippetsOnMethodSuggest,
'description': nls.localize('useCodeSnippetsOnMethodSuggest', "Complete functions with their parameter signature."),
}
var configurationRegistry = <ConfigurationRegistry.IConfigurationRegistry>platform.Registry.as(ConfigurationRegistry.Extensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'typescript',
'order': 20,
'title': nls.localize('tsConfigurationTitle', "TypeScript configuration"),
'allOf': [
{
'type': 'object',
'title': nls.localize('suggestSettings', "Controls how TypeScript IntelliSense works."),
'properties': {
'typescript.suggest.alwaysAllWords': {
'type': 'boolean',
'default': defaults.suggest.alwaysAllWords,
'description': nls.localize('allwaysAllWords', "Always include all words from the current document."),
},
'typescript.suggest.useCodeSnippetsOnMethodSuggest': {
'type': 'boolean',
'default': defaults.suggest.useCodeSnippetsOnMethodSuggest,
'description': nls.localize('useCodeSnippetsOnMethodSuggest', "Complete functions with their parameter signature."),
}
},
}
},
/* Note: we cannot enable this feature because in VS this is an ultimate feature and not available for free
{
'type': 'object',
'properties': {
'typescript.referenceInfos': {
'type': 'boolean',
'description': nls.localize('referenceInfos', "Enables reference infos for types, methods and functions."),
'default': false
}
/* Note: we cannot enable this feature because in VS this is an ultimate feature and not available for free
{
'type': 'object',
'properties': {
'typescript.referenceInfos': {
'type': 'boolean',
'description': nls.localize('referenceInfos', "Enables reference infos for types, methods and functions."),
'default': false
}
},*/
{
'type': 'object',
'title': nls.localize('lint', "Controls various aspects of validation."),
'properties': {
'typescript.validate.lint.curlyBracketsMustNotBeOmitted': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.curlyBracketsMustNotBeOmitted,
'description': nls.localize('lint.curlyBracketsMustNotBeOmitted', "Don't spare curly brackets."),
},
'typescript.validate.lint.emptyBlocksWithoutComment': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.emptyBlocksWithoutComment,
'description': nls.localize('lint.emptyBlocksWithoutComment', "Empty block should have a comment."),
},
'typescript.validate.lint.comparisonOperatorsNotStrict': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.comparisonOperatorsNotStrict,
'description': nls.localize('lint.comparisonOperatorsNotStrict', "Use '!==' and '===' instead of '!=' and '=='."),
},
'typescript.validate.lint.missingSemicolon': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.missingSemicolon,
'description': nls.localize('lint.missingSemicolon', "Missing semicolon."),
},
'typescript.validate.lint.unknownTypeOfResults': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unknownTypeOfResults,
'description': nls.localize('lint.unknownTypeOfResults', "Unexpected output of the 'typeof'-operator."),
},
'typescript.validate.lint.semicolonsInsteadOfBlocks': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.semicolonsInsteadOfBlocks,
'description': nls.localize('lint.semicolonsInsteadOfBlocks', "Semicolon instead of block."),
},
'typescript.validate.lint.functionsInsideLoops': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.functionsInsideLoops,
'description': nls.localize('lint.functionsInsideLoops', "Function inside loop."),
},
'typescript.validate.lint.newOnLowercaseFunctions': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.newOnLowercaseFunctions,
'description': nls.localize('lint.newOnLowercaseFunctions', "Function with lowercase name used as constructor."),
},
'typescript.validate.lint.tripleSlashReferenceAlike': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.tripleSlashReferenceAlike,
'description': nls.localize('lint.tripleSlashReferenceAlike', "Looks for mistyped triple-slash references."),
},
'typescript.validate.lint.unusedVariables': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unusedVariables,
'description': nls.localize('lint.unusedVariables', "Unused local variable."),
},
'typescript.validate.lint.unusedFunctions': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unusedFunctions,
'description': nls.localize('lint.unusedFunctions', "Unused local function."),
},
'typescript.validate.lint.unusedMembers': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unusedMembers,
'description': nls.localize('lint.unusedMembers', "Unused private member."),
},
'typescript.validate.lint.functionsWithoutReturnType': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.functionsWithoutReturnType,
'description': nls.localize('lint.functionsWithoutReturnType', "Don't spare the return-type annotation for functions."),
}
}
},*/
{
'type': 'object',
'title': nls.localize('lint', "Controls various aspects of validation."),
'properties': {
'typescript.validate.lint.curlyBracketsMustNotBeOmitted': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.curlyBracketsMustNotBeOmitted,
'description': nls.localize('lint.curlyBracketsMustNotBeOmitted', "Don't spare curly brackets."),
},
'typescript.validate.lint.emptyBlocksWithoutComment': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.emptyBlocksWithoutComment,
'description': nls.localize('lint.emptyBlocksWithoutComment', "Empty block should have a comment."),
},
'typescript.validate.lint.comparisonOperatorsNotStrict': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.comparisonOperatorsNotStrict,
'description': nls.localize('lint.comparisonOperatorsNotStrict', "Use '!==' and '===' instead of '!=' and '=='."),
},
'typescript.validate.lint.missingSemicolon': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.missingSemicolon,
'description': nls.localize('lint.missingSemicolon', "Missing semicolon."),
},
'typescript.validate.lint.unknownTypeOfResults': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unknownTypeOfResults,
'description': nls.localize('lint.unknownTypeOfResults', "Unexpected output of the 'typeof'-operator."),
},
'typescript.validate.lint.semicolonsInsteadOfBlocks': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.semicolonsInsteadOfBlocks,
'description': nls.localize('lint.semicolonsInsteadOfBlocks', "Semicolon instead of block."),
},
'typescript.validate.lint.functionsInsideLoops': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.functionsInsideLoops,
'description': nls.localize('lint.functionsInsideLoops', "Function inside loop."),
},
'typescript.validate.lint.newOnLowercaseFunctions': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.newOnLowercaseFunctions,
'description': nls.localize('lint.newOnLowercaseFunctions', "Function with lowercase name used as constructor."),
},
'typescript.validate.lint.tripleSlashReferenceAlike': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.tripleSlashReferenceAlike,
'description': nls.localize('lint.tripleSlashReferenceAlike', "Looks for mistyped triple-slash references."),
},
'typescript.validate.lint.unusedVariables': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unusedVariables,
'description': nls.localize('lint.unusedVariables', "Unused local variable."),
},
'typescript.validate.lint.unusedFunctions': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unusedFunctions,
'description': nls.localize('lint.unusedFunctions', "Unused local function."),
},
'typescript.validate.lint.unusedMembers': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.unusedMembers,
'description': nls.localize('lint.unusedMembers', "Unused private member."),
},
'typescript.validate.lint.functionsWithoutReturnType': {
'enum': ['ignore', 'warning', 'error'],
'default': defaults.validate.lint.functionsWithoutReturnType,
'description': nls.localize('lint.functionsWithoutReturnType', "Don't spare the return-type annotation for functions."),
}
}
]
});
}
}
]
});
......@@ -5,10 +5,8 @@
'use strict';
import winjs = require('vs/base/common/winjs.base');
import platform = require('vs/platform/platform');
import URI from 'vs/base/common/uri';
import ts = require('vs/languages/typescript/common/lib/typescriptServices');
import {AsyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
export enum ChangeKind {
Changed,
......@@ -115,22 +113,3 @@ export namespace Defaults {
ProjectResolver.setCompilerOptions(options);
}
}
// ----- TypeScript extension ---------------------------------------------------------------
export namespace Extensions {
export var Identifier = 'typescript';
platform.Registry.add(Identifier, Extensions);
var projectResolver: AsyncDescriptor<IProjectResolver2>;
export function setProjectResolver(desc: AsyncDescriptor<IProjectResolver2>): void {
projectResolver = desc;
}
export function getProjectResolver(): AsyncDescriptor<IProjectResolver2> {
return projectResolver;
}
}
......@@ -307,7 +307,7 @@ export class TypeScriptMode<W extends typescriptWorker.TypeScriptWorker2> extend
// ---- project sync
protected _getProjectResolver(): AsyncDescriptor<typescript.IProjectResolver2>|typescript.IProjectResolver2 {
return typescript.Extensions.getProjectResolver() || typescript.Defaults.ProjectResolver;
return typescript.Defaults.ProjectResolver;
}
acceptProjectChanges(changes: { kind: typescript.ChangeKind; resource: URI; files: URI[]; options: ts.CompilerOptions }[]): WinJS.TPromise<{[dirname:string]:URI}> {
......
......@@ -7,7 +7,6 @@
import winjs = require('vs/base/common/winjs.base');
import errors = require('vs/base/common/errors');
import env = require('vs/base/common/flags');
import {IFileService} from 'vs/platform/files/common/files';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
......@@ -95,7 +94,6 @@ export class WorkspaceStats {
tags['workspace.reactNative'] = this.searchArray(names, /^android$/i) && this.searchArray(names, /^ios$/i) &&
this.searchArray(names, /^index\.android\.js$/i) && this.searchArray(names, /^index\.ios\.js$/i);
tags['workspace.enableTypeScriptServiceModeForJS'] = !!env.enableTypeScriptServiceModeForJS;
return tags;
}, error => { errors.onUnexpectedError(error); return null; });
} else {
......
......@@ -86,7 +86,8 @@ class ExtHostApiCommands {
description: 'Execute signature help provider.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'position', description: 'Position in a text document', constraint: types.Position }
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
{ name: 'triggerCharacter', description: '(optional) Trigger signature help when the user types the character, like `,` or `(`' }
],
returns: 'A promise that resolves to SignatureHelp.'
});
......@@ -101,7 +102,8 @@ class ExtHostApiCommands {
description: 'Execute completion item provider.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'position', description: 'Position in a text document', constraint: types.Position }
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
{ name: 'triggerCharacter', description: '(optional) Trigger completion when the user types the character, like `,` or `(`' }
],
returns: 'A promise that resolves to a CompletionList-instance.'
});
......@@ -111,14 +113,14 @@ class ExtHostApiCommands {
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'range', description: 'Range in a text document', constraint: types.Range }
],
returns: 'A promise that resolves to an array of CompletionItem-instances.'
returns: 'A promise that resolves to an array of Command-instances.'
});
this._register('vscode.executeCodeLensProvider', this._executeCodeLensProvider, {
description: 'Execute completion item provider.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI }
],
returns: 'A promise that resolves to an array of Commands.'
returns: 'A promise that resolves to an array of CodeLens-instances.'
});
this._register('vscode.executeFormatDocumentProvider', this._executeFormatDocumentProvider, {
description: 'Execute document format provider.',
......
......@@ -494,13 +494,19 @@ export class MainThreadDocuments {
modelService.onModelModeChanged(this._onModelModeChanged, this, this._toDispose);
this._toDispose.push(eventService.addListener2(FileEventType.FILE_SAVED, (e: LocalFileChangeEvent) => {
this._proxy._acceptModelSaved(e.getAfter().resource.toString());
if (this._shouldHandleFileEvent(e)) {
this._proxy._acceptModelSaved(e.getAfter().resource.toString());
}
}));
this._toDispose.push(eventService.addListener2(FileEventType.FILE_REVERTED, (e: LocalFileChangeEvent) => {
this._proxy._acceptModelReverted(e.getAfter().resource.toString());
if (this._shouldHandleFileEvent(e)) {
this._proxy._acceptModelReverted(e.getAfter().resource.toString());
}
}));
this._toDispose.push(eventService.addListener2(FileEventType.FILE_DIRTY, (e: LocalFileChangeEvent) => {
this._proxy._acceptModelDirty(e.getAfter().resource.toString());
if (this._shouldHandleFileEvent(e)) {
this._proxy._acceptModelDirty(e.getAfter().resource.toString());
}
}));
const handle = setInterval(() => this._runDocumentCleanup(), 30 * 1000);
......@@ -519,6 +525,12 @@ export class MainThreadDocuments {
this._toDispose = disposeAll(this._toDispose);
}
private _shouldHandleFileEvent(e: LocalFileChangeEvent): boolean {
const after = e.getAfter();
const model = this._modelService.getModel(after.resource);
return model && !model.isTooLargeForHavingARichMode();
}
private _onModelAdded(model: EditorCommon.IModel): void {
// Same filter as in mainThreadEditors
if (model.isTooLargeForHavingARichMode()) {
......
......@@ -24,6 +24,7 @@ import {IMessageService, Severity} from 'vs/platform/message/common/message';
import {ICommonCodeEditor} from 'vs/editor/common/editorCommon';
import {OpenGlobalSettingsAction} from 'vs/workbench/browser/actions/openSettings';
import {ICodeEditor, IDiffEditor} from 'vs/editor/browser/editorBrowser';
import {TrimTrailingWhitespaceAction} from 'vs/editor/contrib/linesOperations/common/linesOperations';
import {EndOfLineSequence, ITokenizedModel, EditorType, IEditorSelection, ITextModel, IDiffEditorModel, IEditor} from 'vs/editor/common/editorCommon';
import {IndentUsingSpaces, IndentUsingTabs, DetectIndentation, IndentationToSpacesAction, IndentationToTabsAction} from 'vs/editor/contrib/indentation/common/indentation';
import {EventType, ResourceEvent, EditorEvent, TextEditorSelectionEvent} from 'vs/workbench/common/events';
......@@ -726,7 +727,8 @@ class ChangeIndentationAction extends Action {
}
const control = <ICommonCodeEditor>activeEditor.getControl();
const picks = [control.getAction(IndentUsingSpaces.ID), control.getAction(IndentUsingTabs.ID), control.getAction(DetectIndentation.ID), control.getAction(IndentationToSpacesAction.ID), control.getAction(IndentationToTabsAction.ID)];
const picks = [control.getAction(IndentUsingSpaces.ID), control.getAction(IndentUsingTabs.ID), control.getAction(DetectIndentation.ID),
control.getAction(IndentationToSpacesAction.ID), control.getAction(IndentationToTabsAction.ID), control.getAction(TrimTrailingWhitespaceAction.ID)];
(<IPickOpenEntry>picks[0]).separator = { label: nls.localize('indentView', "change view") };
(<IPickOpenEntry>picks[3]).separator = { label: nls.localize('indentConvert', "convert file"), border: true };
......
......@@ -167,10 +167,7 @@
window.MonacoEnvironment = {
'enableTasks': hasWorkspaceContext,
'enableJavaScriptRewriting': true,
'enableSendASmile' : !!configuration.sendASmile,
'enableTypeScriptServiceMode': true || !process.env['VSCODE_TSWORKER'],
'enableTypeScriptServiceModeForJS': !!process.env['CODE_TSJS'] || !!process.env['VSCODE_TSJS']
'enableSendASmile' : !!configuration.sendASmile
};
var timers = window.MonacoEnvironment.timers = {
......
......@@ -432,17 +432,6 @@ export class VSCodeMenu {
});
}
private createRoleMenuItem(label: string, actionId: string, role: string): Electron.MenuItem {
let options: Electron.MenuItemOptions = {
label: mnemonicLabel(label),
accelerator: this.getAccelerator(actionId),
role: role,
enabled: true
};
return new MenuItem(options);
}
private setEditMenu(winLinuxEditMenu: Electron.Menu): void {
let undo: Electron.MenuItem;
let redo: Electron.MenuItem;
......@@ -452,12 +441,12 @@ export class VSCodeMenu {
let selectAll: Electron.MenuItem;
if (platform.isMacintosh) {
undo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', (devTools) => devTools.undo());
redo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', (devTools) => devTools.redo());
cut = this.createRoleMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "&&Cut"), 'editor.action.clipboardCutAction', 'cut');
copy = this.createRoleMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "C&&opy"), 'editor.action.clipboardCopyAction', 'copy');
paste = this.createRoleMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction', 'paste');
selectAll = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll', (devTools) => devTools.selectAll());
undo = this.createMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', true, 'undo');
redo = this.createMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', true, 'redo');
cut = this.createMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "&&Cut"), 'editor.action.clipboardCutAction', true, 'cut');
copy = this.createMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "C&&opy"), 'editor.action.clipboardCopyAction', true, 'copy');
paste = this.createMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction', true, 'paste');
selectAll = this.createMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll', true, 'selectall');
} else {
undo = this.createMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo');
redo = this.createMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo');
......@@ -659,9 +648,9 @@ export class VSCodeMenu {
}
}
private createMenuItem(label: string, actionId: string, enabled?: boolean): Electron.MenuItem;
private createMenuItem(label: string, click: () => void, enabled?: boolean): Electron.MenuItem;
private createMenuItem(arg1: string, arg2: any, arg3?: boolean): Electron.MenuItem {
private createMenuItem(label: string, actionId: string, enabled?: boolean, role?:string): Electron.MenuItem;
private createMenuItem(label: string, click: () => void, enabled?: boolean, role?:string): Electron.MenuItem;
private createMenuItem(arg1: string, arg2: any, arg3?: boolean, role?:string): Electron.MenuItem {
let label = mnemonicLabel(arg1);
let click: () => void = (typeof arg2 === 'function') ? arg2 : () => windows.manager.sendToFocused('vscode:runAction', arg2);
let enabled = typeof arg3 === 'boolean' ? arg3 : windows.manager.getWindowCount() > 0;
......@@ -675,32 +664,13 @@ export class VSCodeMenu {
label: label,
accelerator: this.getAccelerator(actionId),
click: click,
role: role,
enabled: enabled
};
return new MenuItem(options);
}
private createDevToolsAwareMenuItem(label: string, actionId: string, devToolsFocusedFn: (contents: Electron.WebContents) => void): Electron.MenuItem {
return new MenuItem({
label: mnemonicLabel(label),
accelerator: this.getAccelerator(actionId),
enabled: windows.manager.getWindowCount() > 0,
click: () => {
let windowInFocus = windows.manager.getFocusedWindow();
if (!windowInFocus) {
return;
}
if (windowInFocus.win.isDevToolsFocused()) {
devToolsFocusedFn(windowInFocus.win.devToolsWebContents);
} else {
windows.manager.sendToFocused('vscode:runAction', actionId);
}
}
});
}
private getAccelerator(actionId: string): string {
if (actionId) {
let resolvedKeybinding = this.mapResolvedKeybindingToActionId[actionId];
......
......@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import nls = require('vs/nls');
import lifecycle = require('vs/base/common/lifecycle');
import errors = require('vs/base/common/errors');
import { TPromise } from 'vs/base/common/winjs.base';
......@@ -67,7 +68,7 @@ export class SelectConfigActionItem extends BaseActionItem {
return this.debugService.loadLaunchConfig().then(config => {
if (!config || !config.configurations) {
this.select.add(this.createOption('<none>'));
this.select.add(this.createOption(`<${ nls.localize('none', "none") }>`));
this.select.disabled = true;
return;
}
......
......@@ -889,7 +889,7 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
return TPromise.as(null);
}
const breakpointsToSend = this.model.getFunctionBreakpoints().filter(fbp => fbp.enabled);
const breakpointsToSend = this.model.getFunctionBreakpoints().filter(fbp => fbp.enabled && this.model.areBreakpointsActivated());
return this.session.setFunctionBreakpoints({ breakpoints: breakpointsToSend }).then(response => {
const data: {[id: string]: { name?: string, verified?: boolean } } = { };
for (let i = 0; i < breakpointsToSend.length; i++) {
......
......@@ -27,6 +27,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
private cachedInitServer: TPromise<void>;
private startTime: number;
private stopServerPending: boolean;
private sentPromises: TPromise<DebugProtocol.Response>[];
public isAttach: boolean;
public restarted: boolean;
public capabilities: DebugProtocol.Capabilites;
......@@ -40,6 +41,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
) {
super();
this.capabilities = {};
this.sentPromises = [];
}
private initServer(): TPromise<void> {
......@@ -60,24 +62,29 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
}
protected send(command: string, args: any): TPromise<DebugProtocol.Response> {
return this.initServer().then(() => super.send(command, args).then(response => response, (errorResponse: DebugProtocol.ErrorResponse) => {
const error = errorResponse.body ? errorResponse.body.error : null;
const message = error ? debug.formatPII(error.format, false, error.variables) : errorResponse.message;
if (error && error.sendTelemetry) {
this.telemetryService.publicLog('debugProtocolErrorResponse', { error: message });
this.telemtryAdapter.log('debugProtocolErrorResponse', { error: message });
}
return this.initServer().then(() => {
const promise = super.send(command, args).then(response => response, (errorResponse: DebugProtocol.ErrorResponse) => {
const error = errorResponse.body ? errorResponse.body.error : null;
const message = error ? debug.formatPII(error.format, false, error.variables) : errorResponse.message;
if (error && error.sendTelemetry) {
this.telemetryService.publicLog('debugProtocolErrorResponse', { error: message });
this.telemtryAdapter.log('debugProtocolErrorResponse', { error: message });
}
if (error && error.url) {
const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info");
return TPromise.wrapError(errors.create(message, { actions: [CloseAction, new Action('debug.moreInfo', label, null, true, () => {
shell.openExternal(error.url);
return TPromise.as(null);
})]}));
}
if (error && error.url) {
const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info");
return TPromise.wrapError(errors.create(message, { actions: [CloseAction, new Action('debug.moreInfo', label, null, true, () => {
shell.openExternal(error.url);
return TPromise.as(null);
})]}));
}
return TPromise.wrapError(new Error(message));
}));
return TPromise.wrapError(new Error(message));
});
this.sentPromises.push(promise);
return promise;
});
}
public initialize(args: DebugProtocol.InitializeRequestArguments): TPromise<DebugProtocol.InitializeResponse> {
......@@ -137,6 +144,9 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
if (this.stopServerPending && force) {
return this.stopServer();
}
// Cancel all sent promises on disconnect so debug trees are not left in a broken state #3666.
this.sentPromises.forEach(p => p.cancel());
this.sentPromises = [];
if ((this.serverProcess || this.socket) && !this.stopServerPending) {
// point of no return: from now on don't report any errors
......
......@@ -4,21 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
export interface IOptions {
cwd: string;
env?: any;
}
export var IExecutionService = createDecorator<IExecutionService>('executionService');
export interface IExecutionService {
serviceId: ServiceIdentifier<any>;
exec(file: string, args: string[], cwd: string | IOptions): TPromise<any>;
}
export var ITerminalService = createDecorator<ITerminalService>('nativeTerminalService');
export interface ITerminalService {
......
......@@ -4,19 +4,15 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import env = require('vs/base/common/platform');
import {WinExecutionService, MacExecutionService, LinuxExecutionService} from 'vs/workbench/parts/execution/electron-browser/executionService';
import * as env from 'vs/base/common/platform';
import {WinTerminalService, MacTerminalService, LinuxTerminalService} from 'vs/workbench/parts/execution/electron-browser/terminalService';
import {registerSingleton} from 'vs/platform/instantiation/common/extensions';
import {ITerminalService, IExecutionService} from 'vs/workbench/parts/execution/common/execution';
import {ITerminalService} from 'vs/workbench/parts/execution/common/execution';
if (env.isWindows) {
registerSingleton(IExecutionService, WinExecutionService);
registerSingleton(ITerminalService, WinTerminalService);
} else if (env.isMacintosh) {
registerSingleton(IExecutionService, MacExecutionService);
registerSingleton(ITerminalService, MacTerminalService);
} else if (env.isLinux) {
registerSingleton(IExecutionService, LinuxExecutionService);
registerSingleton(ITerminalService, LinuxTerminalService);
}
\ No newline at end of file
}
/*---------------------------------------------------------------------------------------------
* 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 nls = require('vs/nls');
import errors = require('vs/base/common/errors');
import hash = require('vs/base/common/hash');
import collections = require('vs/base/common/collections');
import {TPromise} from 'vs/base/common/winjs.base';
import objects = require('vs/base/common/objects');
import strings = require('vs/base/common/strings');
import exec = require('vs/workbench/parts/execution/common/execution');
import uri from 'vs/base/common/uri';
import cp = require('child_process');
import processes = require('vs/base/node/processes');
export class AbstractExecutionService implements exec.IExecutionService {
public serviceId = exec.IExecutionService;
private _executions: collections.INumberDictionary<TPromise<any>> = Object.create(null);
public exec(file: string, args: string[], cwdOrOptions: string | exec.IOptions): TPromise<any> {
let options: exec.IOptions,
allEnv = objects.clone(process.env);
if (typeof cwdOrOptions === 'string') {
options = {
cwd: cwdOrOptions,
env: allEnv
};
} else {
objects.mixin(allEnv, cwdOrOptions.env);
cwdOrOptions.env = allEnv;
options = cwdOrOptions;
}
let key = args.concat([file, options.cwd]).reduce((p, c) => hash.combine(hash.computeMurmur2StringHashCode(c), p), 17);
if (this._executions[key]) {
this._executions[key].cancel();
delete this._executions[key];
}
let ret = this.doExec(file, args, options);
this._executions[key] = ret;
return ret.then(val => val, err => {
if (!errors.isPromiseCanceledError(err)) {
throw err;
}
});
}
protected doExec(file: string, args: string[], options: exec.IOptions): TPromise<any> {
throw errors.notImplemented();
}
}
export class WinExecutionService extends AbstractExecutionService {
protected doExec(file: string, args: string[], options: exec.IOptions): TPromise<any> {
let childProcess: cp.ChildProcess;
return new TPromise<any>((c, e, p) => {
const shell = processes.getWindowsShell();
// we use `start` to get another shell where `& pause` can be handled
args = [
'/c',
'start',
'/wait',
shell,
'/c',
strings.format('"{0} {1} & pause"', file, args.join(' '))
];
options = options || <any>{};
(<any>options).windowsVerbatimArguments = true;
childProcess = cp.spawn(shell, args, options);
childProcess.on('exit', c);
childProcess.on('error', e);
// send out the process once
p(childProcess);
}, function() {
if (!childProcess) {
return;
}
cp.exec(`taskkill /F /T /PID ${childProcess.pid}`, function(err, stdout, stderr) {
if (err) {
console.error(err);
}
});
});
}
}
export class MacExecutionService extends AbstractExecutionService {
protected doExec(file: string, args: string[], options: exec.IOptions): TPromise<any> {
let childProcess: cp.ChildProcess;
return new TPromise<any>((c, e, p) => {
args = [
uri.parse(require.toUrl('vs/workbench/parts/execution/electron-browser/macHelper.scpt')).fsPath,
'cd', `'${options.cwd}'`, ';',
file
].concat(args);
childProcess = cp.spawn('/usr/bin/osascript', args, options);
childProcess.on('exit', c);
childProcess.on('error', e);
// send out the process once
p(childProcess);
}, function() {
if (childProcess) {
childProcess.kill('SIGTERM');
}
});
}
}
export class LinuxExecutionService extends AbstractExecutionService {
private static LINUX_TERM = '/usr/bin/gnome-terminal'; // '/usr/bin/x-terminal-emulator'
private static WAIT_MESSAGE = nls.localize('linux.wait', "Press any key to continue...");
protected doExec(file: string, args: string[], options: exec.IOptions): TPromise<any> {
let childProcess: cp.ChildProcess;
return new TPromise<any>((c, e, p) => {
let flattenedArgs = '';
if (args.length > 0) {
flattenedArgs = '"' + args.join('" "') + '"';
}
let cdCommand = '';
if (options.cwd) {
cdCommand = strings.format('cd "{0}"', options.cwd);
}
let bashCommand = strings.format(
'{0}; "{1}" {2} ; echo; read -p "{3}" -n1;',
cdCommand, file, flattenedArgs, LinuxExecutionService.WAIT_MESSAGE
);
args = [
'-x',
'bash',
'-c',
// wrapping argument in two sets of ' because node is so "friendly" that it removes one set...
strings.format('\'\'{0}\'\'', bashCommand)
];
childProcess = cp.spawn(LinuxExecutionService.LINUX_TERM, args, options);
childProcess.on('exit', c);
childProcess.on('error', e);
// send out the process once
p(childProcess);
}, function() {
console.log('SENDING KILL');
if (childProcess) {
childProcess.kill('SIGTERM');
}
});
}
}
\ No newline at end of file
-------------------------------------------------------------------
-- Copyright (c) Microsoft Corporation. All rights reserved.
-- Licensed under the MIT License.
-- See License.txt in the project root for license information.
-------------------------------------------------------------------
on run argv
set prevDelimiter to AppleScript's text item delimiters
set AppleScript's text item delimiters to " "
set command to argv as string
set AppleScript's text item delimiters to prevDelimiter
tell application "Terminal"
activate
set targetWindow to null
repeat with currentWindow in windows
if currentWindow is not busy then
set targetWindow to currentWindow
end if
end repeat
if targetWindow null then
do script command in targetWindow
else
do script command
end if
end tell
end run
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册