Merge branch 'master' into joh/progress-api

This commit is contained in:
Johannes Rieken
2017-01-13 13:55:31 +01:00
83 changed files with 1801 additions and 927 deletions
+10 -4
View File
@@ -189,11 +189,12 @@ const hygiene = exports.hygiene = (some, options) => {
}); });
const tsl = es.through(function (file) { const tsl = es.through(function (file) {
const configuration = tslint.findConfiguration(null, '.'); const configuration = tslint.Configuration.findConfiguration(null, '.');
const options = { configuration, formatter: 'json', rulesDirectory: 'build/lib/tslint' }; const options = { formatter: 'json', rulesDirectory: 'build/lib/tslint' };
const contents = file.contents.toString('utf8'); const contents = file.contents.toString('utf8');
const linter = new tslint(file.relative, contents, options); const linter = new tslint.Linter(options);
const result = linter.lint(); linter.lint(file.relative, contents, configuration.results);
const result = linter.getResult();
if (result.failureCount > 0) { if (result.failureCount > 0) {
reportFailures(result.failures); reportFailures(result.failures);
@@ -229,6 +230,11 @@ gulp.task('hygiene', () => hygiene());
if (require.main === module) { if (require.main === module) {
const cp = require('child_process'); const cp = require('child_process');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
process.exit(1);
});
cp.exec('git config core.autocrlf', (err, out) => { cp.exec('git config core.autocrlf', (err, out) => {
const skipEOL = out.trim() === 'true'; const skipEOL = out.trim() === 'true';
+12 -2
View File
@@ -51,8 +51,18 @@ gulp.task('mixin', function () {
const build = all.pipe(filter('build/**')); const build = all.pipe(filter('build/**'));
const productJsonFilter = filter('product.json', { restore: true }); const productJsonFilter = filter('product.json', { restore: true });
const vsdaFilter = (function() {
const filter = [];
if (process.platform !== 'win32') { filter.push('!**/vsda_win32.node'); }
if (process.platform !== 'darwin') { filter.push('!**/vsda_darwin.node'); }
if (process.platform !== 'linux' || process.arch !== 'x64') { filter.push('!**/vsda_linux64.node'); }
if (process.platform !== 'linux' || process.arch === 'x64') { filter.push('!**/vsda_linux32.node'); }
return filter;
})();
const mixin = all const mixin = all
.pipe(filter('quality/' + quality + '/**')) .pipe(filter(['quality/' + quality + '/**'].concat(vsdaFilter)))
.pipe(util.rebase(2)) .pipe(util.rebase(2))
.pipe(productJsonFilter) .pipe(productJsonFilter)
.pipe(buffer()) .pipe(buffer())
@@ -71,4 +81,4 @@ gulp.task('mixin', function () {
return f; return f;
})) }))
.pipe(gulp.dest('.')); .pipe(gulp.dest('.'));
}); });
+6 -5
View File
@@ -30,7 +30,8 @@ const product = require('../product.json');
const shrinkwrap = require('../npm-shrinkwrap.json'); const shrinkwrap = require('../npm-shrinkwrap.json');
const crypto = require('crypto'); const crypto = require('crypto');
const dependencies = Object.keys(shrinkwrap.dependencies); const dependencies = Object.keys(shrinkwrap.dependencies)
.concat(Array.isArray(product.extraNodeModules) ? product.extraNodeModules : []); // additional dependencies from our product configuration
const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n)); const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n));
const nodeModules = ['electron', 'original-fs'] const nodeModules = ['electron', 'original-fs']
.concat(dependencies) .concat(dependencies)
@@ -39,8 +40,8 @@ const nodeModules = ['electron', 'original-fs']
// Build // Build
const builtInExtensions = [ const builtInExtensions = [
{ name: 'ms-vscode.node-debug', version: '1.9.5' }, { name: 'ms-vscode.node-debug', version: '1.9.6' },
{ name: 'ms-vscode.node-debug2', version: '1.9.2' } { name: 'ms-vscode.node-debug2', version: '1.9.4' }
]; ];
const vscodeEntryPoints = _.flatten([ const vscodeEntryPoints = _.flatten([
@@ -93,11 +94,11 @@ gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compil
gulp.task('optimize-index-js', ['optimize-vscode'], () => { gulp.task('optimize-index-js', ['optimize-vscode'], () => {
const fullpath = path.join(process.cwd(), 'out-vscode/vs/workbench/electron-browser/bootstrap/index.js') const fullpath = path.join(process.cwd(), 'out-vscode/vs/workbench/electron-browser/bootstrap/index.js');
const contents = fs.readFileSync(fullpath).toString(); const contents = fs.readFileSync(fullpath).toString();
const newContents = contents.replace('[/*BUILD->INSERT_NODE_MODULES*/]', JSON.stringify(nodeModules)); const newContents = contents.replace('[/*BUILD->INSERT_NODE_MODULES*/]', JSON.stringify(nodeModules));
fs.writeFileSync(fullpath, newContents); fs.writeFileSync(fullpath, newContents);
}) });
const baseUrl = `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`; const baseUrl = `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`;
gulp.task('clean-minified-vscode', util.rimraf('out-vscode-min')); gulp.task('clean-minified-vscode', util.rimraf('out-vscode-min'));
+1 -3
View File
@@ -23,8 +23,6 @@ options.verbose = false;
options.sourceMap = true; options.sourceMap = true;
options.rootDir = rootDir; options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir); options.sourceRoot = util.toFileUri(rootDir);
var smSourceRootPath = path.resolve(path.dirname(rootDir));
var smSourceRoot = util.toFileUri(smSourceRootPath);
function createCompile(build, emitError) { function createCompile(build, emitError) {
var opts = _.clone(options); var opts = _.clone(options);
opts.inlineSources = !!build; opts.inlineSources = !!build;
@@ -48,7 +46,7 @@ function createCompile(build, emitError) {
.pipe(sourcemaps.write('.', { .pipe(sourcemaps.write('.', {
addComment: false, addComment: false,
includeContent: !!build, includeContent: !!build,
sourceRoot: smSourceRoot sourceRoot: options.sourceRoot
})) }))
.pipe(tsFilter.restore) .pipe(tsFilter.restore)
.pipe(reporter.end(emitError)); .pipe(reporter.end(emitError));
+1 -4
View File
@@ -28,9 +28,6 @@ options.sourceMap = true;
options.rootDir = rootDir; options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir); options.sourceRoot = util.toFileUri(rootDir);
const smSourceRootPath = path.resolve(path.dirname(rootDir));
const smSourceRoot = util.toFileUri(smSourceRootPath);
function createCompile(build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream { function createCompile(build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream {
const opts = _.clone(options); const opts = _.clone(options);
opts.inlineSources = !!build; opts.inlineSources = !!build;
@@ -57,7 +54,7 @@ function createCompile(build: boolean, emitError?: boolean): (token?: util.ICanc
.pipe(sourcemaps.write('.', { .pipe(sourcemaps.write('.', {
addComment: false, addComment: false,
includeContent: !!build, includeContent: !!build,
sourceRoot: smSourceRoot sourceRoot: options.sourceRoot
})) }))
.pipe(tsFilter.restore) .pipe(tsFilter.restore)
.pipe(reporter.end(emitError)); .pipe(reporter.end(emitError));
@@ -90,8 +90,8 @@ var NoUnexternalizedStringsRuleWalker = (function (_super) {
return; return;
} }
if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) { if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) {
var s = node.getText(); var s_1 = node.getText();
var replacement = new Lint.Replacement(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")"); var replacement = new Lint.Replacement(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s_1.substring(1, s_1.length - 1) + "', " + s_1 + ")");
var fix = new Lint.Fix("Unexternalitzed string", [replacement]); var fix = new Lint.Fix("Unexternalitzed string", [replacement]);
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), "Unexternalized string found: " + node.getText(), fix)); this.addFailure(this.createFailure(node.getStart(), node.getWidth(), "Unexternalized string found: " + node.getText(), fix));
return; return;
+2 -2
View File
@@ -195,7 +195,7 @@ function format(text:string): string {
// Apply the edits on the input code // Apply the edits on the input code
return applyEdits(text, edits); return applyEdits(text, edits);
function getRuleProvider(options: ts.FormatCodeOptions) { function getRuleProvider(options: ts.FormatCodeSettings) {
// Share this between multiple formatters using the same options. // Share this between multiple formatters using the same options.
// This represents the bulk of the space the formatter uses. // This represents the bulk of the space the formatter uses.
let ruleProvider = new (<any>ts).formatting.RulesProvider(); let ruleProvider = new (<any>ts).formatting.RulesProvider();
@@ -215,7 +215,7 @@ function format(text:string): string {
return result; return result;
} }
function getDefaultOptions(): ts.FormatCodeOptions { function getDefaultOptions(): ts.FormatCodeSettings {
return { return {
indentSize: 4, indentSize: 4,
tabSize: 4, tabSize: 4,
+1 -1
View File
@@ -43,7 +43,7 @@
"sinon": "^1.17.2", "sinon": "^1.17.2",
"source-map": "^0.4.4", "source-map": "^0.4.4",
"tslint": "^3.3.0", "tslint": "^3.3.0",
"typescript": "^2.0.3", "typescript": "^2.1.4",
"typescript-formatter": "3.1.0", "typescript-formatter": "3.1.0",
"underscore": "^1.8.2", "underscore": "^1.8.2",
"vinyl": "^0.4.5", "vinyl": "^0.4.5",
+6 -1
View File
@@ -6,8 +6,9 @@
body { body {
font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback"; font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
font-size: 14px; font-size: 14px;
padding-left: 12px; padding: 0 12px;
line-height: 22px; line-height: 22px;
word-wrap: break-word;
} }
body.scrollBeyondLastLine { body.scrollBeyondLastLine {
@@ -96,6 +97,10 @@ code {
line-height: 19px; line-height: 19px;
} }
body.wordWrap pre {
white-space: pre-wrap;
}
.mac code { .mac code {
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
+3 -1
View File
@@ -256,6 +256,8 @@ class MDDocumentContentProvider implements vscode.TextDocumentContentProvider {
public provideTextDocumentContent(uri: vscode.Uri): Thenable<string> { public provideTextDocumentContent(uri: vscode.Uri): Thenable<string> {
return vscode.workspace.openTextDocument(vscode.Uri.parse(uri.query)).then(document => { return vscode.workspace.openTextDocument(vscode.Uri.parse(uri.query)).then(document => {
const scrollBeyondLastLine = vscode.workspace.getConfiguration('editor')['scrollBeyondLastLine']; const scrollBeyondLastLine = vscode.workspace.getConfiguration('editor')['scrollBeyondLastLine'];
const wordWrap = vscode.workspace.getConfiguration('editor')['wordWrap'];
const head = ([] as Array<string>).concat( const head = ([] as Array<string>).concat(
'<!DOCTYPE html>', '<!DOCTYPE html>',
'<html>', '<html>',
@@ -267,7 +269,7 @@ class MDDocumentContentProvider implements vscode.TextDocumentContentProvider {
this.computeCustomStyleSheetIncludes(uri), this.computeCustomStyleSheetIncludes(uri),
`<base href="${document.uri.toString(true)}">`, `<base href="${document.uri.toString(true)}">`,
'</head>', '</head>',
`<body class="${scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''}">` `<body class="${scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${wordWrap ? 'wordWrap' : ''}">`
).join('\n'); ).join('\n');
const body = this._renderer.render(this.getDocumentContentForPreview(document)); const body = this._renderer.render(this.getDocumentContentForPreview(document));
-5
View File
@@ -256,11 +256,6 @@
} }
} }
}, },
"keybindings": {
"key": ".",
"command": "^acceptSelectedSuggestion",
"when": "editorTextFocus && suggestWidgetVisible && editorLangId == 'typescript' && suggestionSupportsAcceptOnKey"
},
"commands": [ "commands": [
{ {
"command": "typescript.reloadProjects", "command": "typescript.reloadProjects",
@@ -18,16 +18,17 @@ import * as nls from 'vscode-nls';
let localize = nls.loadMessageBundle(); let localize = nls.loadMessageBundle();
class MyCompletionItem extends CompletionItem { class MyCompletionItem extends CompletionItem {
constructor(
document: TextDocument; public position: Position,
position: Position; public document: TextDocument,
entry: CompletionEntry,
constructor(position: Position, document: TextDocument, entry: CompletionEntry) { enableDotCompletions: boolean
) {
super(entry.name); super(entry.name);
this.sortText = entry.sortText; this.sortText = entry.sortText;
this.kind = MyCompletionItem.convertKind(entry.kind); this.kind = MyCompletionItem.convertKind(entry.kind);
this.position = position; this.position = position;
this.document = document; this.commitCharacters = MyCompletionItem.getCommitCharacters(enableDotCompletions, entry.kind);
if (entry.replacementSpan) { if (entry.replacementSpan) {
let span: protocol.TextSpan = entry.replacementSpan; let span: protocol.TextSpan = entry.replacementSpan;
// The indexing for the range returned by the server uses 1-based indexing. // The indexing for the range returned by the server uses 1-based indexing.
@@ -85,6 +86,38 @@ class MyCompletionItem extends CompletionItem {
return CompletionItemKind.Property; return CompletionItemKind.Property;
} }
private static getCommitCharacters(enableDotCompletions: boolean, kind: string): string[] | undefined {
switch (kind) {
case PConst.Kind.externalModuleName:
return ['"', '\''];
case PConst.Kind.file:
case PConst.Kind.directory:
return ['/', '"', '\''];
case PConst.Kind.memberGetAccessor:
case PConst.Kind.memberSetAccessor:
case PConst.Kind.constructSignature:
case PConst.Kind.callSignature:
case PConst.Kind.indexSignature:
case PConst.Kind.enum:
case PConst.Kind.interface:
return enableDotCompletions ? ['.'] : undefined;
case PConst.Kind.module:
case PConst.Kind.alias:
case PConst.Kind.variable:
case PConst.Kind.localVariable:
case PConst.Kind.memberVariable:
case PConst.Kind.class:
case PConst.Kind.function:
case PConst.Kind.memberFunction:
return enableDotCompletions ? ['.', '('] : undefined;
}
return undefined;
}
} }
interface Configuration { interface Configuration {
@@ -97,15 +130,12 @@ namespace Configuration {
export default class TypeScriptCompletionItemProvider implements CompletionItemProvider { export default class TypeScriptCompletionItemProvider implements CompletionItemProvider {
public triggerCharacters = ['.'];
public excludeTokens = ['string', 'comment', 'numeric'];
public sortBy = [{ type: 'reference', partSeparator: '/' }];
private client: ITypescriptServiceClient;
private typingsStatus: TypingsStatus;
private config: Configuration; private config: Configuration;
constructor(client: ITypescriptServiceClient, typingsStatus: TypingsStatus) { constructor(
private client: ITypescriptServiceClient,
private typingsStatus: TypingsStatus
) {
this.client = client; this.client = client;
this.typingsStatus = typingsStatus; this.typingsStatus = typingsStatus;
this.config = { useCodeSnippetsOnMethodSuggest: false }; this.config = { useCodeSnippetsOnMethodSuggest: false };
@@ -158,9 +188,22 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
let completionItems: CompletionItem[] = []; let completionItems: CompletionItem[] = [];
let body = msg.body; let body = msg.body;
if (body) { if (body) {
// Only enable dot completions in TS files for now
let enableDotCompletions = document && (document.languageId === 'typescript' || document.languageId === 'typescriptreact');
// TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/13456
// Only enable dot completions when previous character is an identifier.
// Prevents incorrectly completing while typing spread operators.
if (position.character > 0) {
const preText = document.getText(new Range(
new Position(position.line, 0),
new Position(position.line, position.character - 1)));
enableDotCompletions = preText.match(/[a-z_$]\s*$/ig) !== null;
}
for (let i = 0; i < body.length; i++) { for (let i = 0; i < body.length; i++) {
let element = body[i]; let element = body[i];
let item = new MyCompletionItem(position, document, element); let item = new MyCompletionItem(position, document, element, enableDotCompletions);
completionItems.push(item); completionItems.push(item);
} }
} }
@@ -5,50 +5,18 @@
'use strict'; 'use strict';
import { DefinitionProvider, TextDocument, Position, Range, CancellationToken, Definition, Location } from 'vscode'; import { DefinitionProvider, TextDocument, Position, CancellationToken, Definition } from 'vscode';
import * as Proto from '../protocol';
import { ITypescriptServiceClient } from '../typescriptService'; import { ITypescriptServiceClient } from '../typescriptService';
import DefinitionProviderBase from './definitionProviderBase';
export default class TypeScriptDefinitionProvider implements DefinitionProvider { export default class TypeScriptDefinitionProvider extends DefinitionProviderBase implements DefinitionProvider {
private client: ITypescriptServiceClient;
public tokens: string[] = [];
constructor(client: ITypescriptServiceClient) { constructor(client: ITypescriptServiceClient) {
this.client = client; super(client);
} }
public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise<Definition | null> { public provideDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise<Definition | null> {
const filepath = this.client.asAbsolutePath(document.uri); return this.getSymbolLocations('definition', document, position, token);
if (!filepath) {
return Promise.resolve(null);
}
let args: Proto.FileLocationRequestArgs = {
file: filepath,
line: position.line + 1,
offset: position.character + 1
};
if (!args.file) {
return Promise.resolve(null);
}
return this.client.execute('definition', args, token).then(response => {
let locations: Proto.FileSpan[] = response.body || [];
if (!locations || locations.length === 0) {
return [] as Definition;
}
return locations.map(location => {
let resource = this.client.asUrl(location.file);
if (resource === null) {
return null;
} else {
return new Location(resource, new Range(location.start.line - 1, location.start.offset - 1, location.end.line - 1, location.end.offset - 1));
}
}).filter(x => x !== null) as Location[];
}, (error) => {
this.client.error(`'definition' request failed with error.`, error);
return [] as Definition;
});
} }
} }
@@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* 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 { TextDocument, Position, Range, CancellationToken, Location } from 'vscode';
import * as Proto from '../protocol';
import { ITypescriptServiceClient } from '../typescriptService';
export default class TypeScriptDefinitionProviderBase {
private client: ITypescriptServiceClient;
public tokens: string[] = [];
constructor(client: ITypescriptServiceClient) {
this.client = client;
}
protected getSymbolLocations(definitionType: 'definition' | 'implementation', document: TextDocument, position: Position, token: CancellationToken | boolean): Promise<Location[] | null> {
const filepath = this.client.asAbsolutePath(document.uri);
if (!filepath) {
return Promise.resolve(null);
}
let args: Proto.FileLocationRequestArgs = {
file: filepath,
line: position.line + 1,
offset: position.character + 1
};
if (!args.file) {
return Promise.resolve(null);
}
return this.client.execute(definitionType, args, token).then(response => {
let locations: Proto.FileSpan[] = (response && response.body) || [];
if (!locations || locations.length === 0) {
return [];
}
return locations.map(location => {
let resource = this.client.asUrl(location.file);
if (resource === null) {
return null;
} else {
return new Location(resource, new Range(location.start.line - 1, location.start.offset - 1, location.end.line - 1, location.end.offset - 1));
}
}).filter(x => x !== null) as Location[];
}, (error) => {
this.client.error(`'${definitionType}' request failed with error.`, error);
return [];
});
}
}
@@ -73,14 +73,13 @@ export default class TypeScriptReferencesCodeLensProvider implements CodeLensPro
// Exclude original definition from references // Exclude original definition from references
const locations = response.body.refs const locations = response.body.refs
.filter(reference => .filter(reference =>
reference.start.line !== codeLens.range.start.line + 1 !(reference.start.line === codeLens.range.start.line + 1
&& reference.start.offset !== codeLens.range.start.character + 1) && reference.start.offset === codeLens.range.start.character + 1))
.map(reference => .map(reference =>
new Location(Uri.file(reference.file), new Location(Uri.file(reference.file),
new Range( new Range(
new Position(reference.start.line - 1, reference.start.offset - 1), new Position(reference.start.line - 1, reference.start.offset - 1),
new Position(reference.end.line - 1, reference.end.offset - 1)))); new Position(reference.end.line - 1, reference.end.offset - 1))));
codeLens.command = { codeLens.command = {
title: locations.length + ' ' + (locations.length === 1 ? localize('oneReferenceLabel', 'reference') : localize('manyReferenceLabel', 'references')), title: locations.length + ' ' + (locations.length === 1 ? localize('oneReferenceLabel', 'reference') : localize('manyReferenceLabel', 'references')),
command: 'editor.action.showReferences', command: 'editor.action.showReferences',
@@ -124,12 +123,17 @@ export default class TypeScriptReferencesCodeLensProvider implements CodeLensPro
} }
// fallthrough // fallthrough
case PConst.Kind.class:
if (item.text === '<class>') {
break;
}
// fallthrough
case PConst.Kind.memberFunction: case PConst.Kind.memberFunction:
case PConst.Kind.memberVariable: case PConst.Kind.memberVariable:
case PConst.Kind.memberGetAccessor: case PConst.Kind.memberGetAccessor:
case PConst.Kind.memberSetAccessor: case PConst.Kind.memberSetAccessor:
case PConst.Kind.constructorImplementation: case PConst.Kind.constructorImplementation:
case PConst.Kind.class:
case PConst.Kind.interface: case PConst.Kind.interface:
case PConst.Kind.type: case PConst.Kind.type:
case PConst.Kind.enum: case PConst.Kind.enum:
@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* 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 { TypeDefinitionProvider, TextDocument, Position, CancellationToken, Definition } from 'vscode';
import { ITypescriptServiceClient } from '../typescriptService';
import DefinitionProviderBase from './definitionProviderBase';
export default class TypeScriptTypeDefinitionProvider extends DefinitionProviderBase implements TypeDefinitionProvider {
constructor(client: ITypescriptServiceClient) {
super(client);
}
public provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise<Definition | null> {
return this.getSymbolLocations('implementation', document, position, token);
}
}
@@ -25,6 +25,7 @@ import { ITypescriptServiceClientHost } from './typescriptService';
import HoverProvider from './features/hoverProvider'; import HoverProvider from './features/hoverProvider';
import DefinitionProvider from './features/definitionProvider'; import DefinitionProvider from './features/definitionProvider';
import TypeDefinitionProvider from './features/TypeDefinitionProvider';
import DocumentHighlightProvider from './features/documentHighlightProvider'; import DocumentHighlightProvider from './features/documentHighlightProvider';
import ReferenceProvider from './features/referenceProvider'; import ReferenceProvider from './features/referenceProvider';
import DocumentSymbolProvider from './features/documentSymbolProvider'; import DocumentSymbolProvider from './features/documentSymbolProvider';
@@ -147,6 +148,7 @@ class LanguageProvider {
let hoverProvider = new HoverProvider(client); let hoverProvider = new HoverProvider(client);
let definitionProvider = new DefinitionProvider(client); let definitionProvider = new DefinitionProvider(client);
let typeDefinitionProvider = new TypeDefinitionProvider(client);
let documentHighlightProvider = new DocumentHighlightProvider(client); let documentHighlightProvider = new DocumentHighlightProvider(client);
let referenceProvider = new ReferenceProvider(client); let referenceProvider = new ReferenceProvider(client);
let documentSymbolProvider = new DocumentSymbolProvider(client); let documentSymbolProvider = new DocumentSymbolProvider(client);
@@ -169,6 +171,7 @@ class LanguageProvider {
languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.'); languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.');
languages.registerHoverProvider(selector, hoverProvider); languages.registerHoverProvider(selector, hoverProvider);
languages.registerDefinitionProvider(selector, definitionProvider); languages.registerDefinitionProvider(selector, definitionProvider);
languages.registerTypeDefinitionProvider(selector, typeDefinitionProvider);
languages.registerDocumentHighlightProvider(selector, documentHighlightProvider); languages.registerDocumentHighlightProvider(selector, documentHighlightProvider);
languages.registerReferenceProvider(selector, referenceProvider); languages.registerReferenceProvider(selector, referenceProvider);
languages.registerDocumentSymbolProvider(selector, documentSymbolProvider); languages.registerDocumentSymbolProvider(selector, documentSymbolProvider);
@@ -87,6 +87,7 @@ export interface ITypescriptServiceClient {
execute(commant: 'completionEntryDetails', args: Proto.CompletionDetailsRequestArgs, token?: CancellationToken): Promise<Proto.CompletionDetailsResponse>; execute(commant: 'completionEntryDetails', args: Proto.CompletionDetailsRequestArgs, token?: CancellationToken): Promise<Proto.CompletionDetailsResponse>;
execute(commant: 'signatureHelp', args: Proto.SignatureHelpRequestArgs, token?: CancellationToken): Promise<Proto.SignatureHelpResponse>; execute(commant: 'signatureHelp', args: Proto.SignatureHelpRequestArgs, token?: CancellationToken): Promise<Proto.SignatureHelpResponse>;
execute(command: 'definition', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.DefinitionResponse>; execute(command: 'definition', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.DefinitionResponse>;
execute(command: 'implementation', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.ImplementationResponse>;
execute(command: 'references', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.ReferencesResponse>; execute(command: 'references', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.ReferencesResponse>;
execute(command: 'navto', args: Proto.NavtoRequestArgs, token?: CancellationToken): Promise<Proto.NavtoResponse>; execute(command: 'navto', args: Proto.NavtoRequestArgs, token?: CancellationToken): Promise<Proto.NavtoResponse>;
execute(command: 'navbar', args: Proto.FileRequestArgs, token?: CancellationToken): Promise<Proto.NavBarResponse>; execute(command: 'navbar', args: Proto.FileRequestArgs, token?: CancellationToken): Promise<Proto.NavBarResponse>;
+6
View File
@@ -58,8 +58,14 @@ var ALL_EDITOR_TASKS = [
'tslint', 'tslint',
'hygiene', 'hygiene',
]; ];
var runningEditorTasks = process.argv.length > 2 && process.argv.slice(2).every(function (arg) { return (ALL_EDITOR_TASKS.indexOf(arg) !== -1); }); var runningEditorTasks = process.argv.length > 2 && process.argv.slice(2).every(function (arg) { return (ALL_EDITOR_TASKS.indexOf(arg) !== -1); });
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
process.exit(1);
});
if (runningEditorTasks) { if (runningEditorTasks) {
require(`./build/gulpfile.editor`); require(`./build/gulpfile.editor`);
require(`./build/gulpfile.hygiene`); require(`./build/gulpfile.hygiene`);
+1 -1
View File
@@ -432,7 +432,7 @@
"xterm": { "xterm": {
"version": "2.2.3", "version": "2.2.3",
"from": "git+https://github.com/Tyriar/xterm.js.git#vscode-release/1.9", "from": "git+https://github.com/Tyriar/xterm.js.git#vscode-release/1.9",
"resolved": "git+https://github.com/Tyriar/xterm.js.git#8fb0947bf7d2e506b16b5425c71726c25a64475b" "resolved": "git+https://github.com/Tyriar/xterm.js.git#36c63323c3f940636e799ae6e0168b2dfd7a3d21"
}, },
"yauzl": { "yauzl": {
"version": "2.3.1", "version": "2.3.1",
+2 -2
View File
@@ -2,7 +2,7 @@
"name": "code-oss-dev", "name": "code-oss-dev",
"version": "1.9.0", "version": "1.9.0",
"electronVersion": "1.4.6", "electronVersion": "1.4.6",
"distro": "ef07477c3bbf2aa2f274b13093cbe0d96fa59fdd", "distro": "07e460da0e2854e12c183abaa5acbcd7b8c48d7f",
"author": { "author": {
"name": "Microsoft Corporation" "name": "Microsoft Corporation"
}, },
@@ -67,7 +67,7 @@
"gulp-rename": "^1.2.0", "gulp-rename": "^1.2.0",
"gulp-replace": "^0.5.4", "gulp-replace": "^0.5.4",
"gulp-shell": "^0.5.2", "gulp-shell": "^0.5.2",
"gulp-sourcemaps": "^1.6.0", "gulp-sourcemaps": "^1.11.0",
"gulp-tsb": "^2.0.3", "gulp-tsb": "^2.0.3",
"gulp-tslint": "^7.0.1", "gulp-tslint": "^7.0.1",
"gulp-uglify": "^2.0.0", "gulp-uglify": "^2.0.0",
@@ -40,13 +40,14 @@ export class SelectBox extends Widget {
return this._onDidSelect.event; return this._onDidSelect.event;
} }
public setOptions(options: string[], selected?: number): void { public setOptions(options: string[], selected?: number, disabled?: number): void {
if (!this.options || !arrays.equals(this.options, options)) { if (!this.options || !arrays.equals(this.options, options)) {
this.options = options; this.options = options;
this.selectElement.options.length = 0; this.selectElement.options.length = 0;
let i = 0;
this.options.forEach((option) => { this.options.forEach((option) => {
this.selectElement.add(this.createOption(option)); this.selectElement.add(this.createOption(option, disabled === i++));
}); });
} }
this.select(selected); this.select(selected);
@@ -91,10 +92,11 @@ export class SelectBox extends Widget {
this.setOptions(this.options, this.selected); this.setOptions(this.options, this.selected);
} }
private createOption(value: string): HTMLOptionElement { private createOption(value: string, disabled?: boolean): HTMLOptionElement {
let option = document.createElement('option'); let option = document.createElement('option');
option.value = value; option.value = value;
option.text = value; option.text = value;
option.disabled = disabled;
return option; return option;
} }
@@ -157,7 +157,7 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
} }
public focusTextArea(): void { public focusTextArea(): void {
this.textAreaHandler.writePlaceholderAndSelectTextAreaSync(); this.textAreaHandler.focusTextArea();
} }
public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean { public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
@@ -17,7 +17,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { TimeoutTimer, RunOnceScheduler } from 'vs/base/common/async'; import { TimeoutTimer, RunOnceScheduler } from 'vs/base/common/async';
import { ViewContext } from 'vs/editor/common/view/viewContext'; import { ViewContext } from 'vs/editor/common/view/viewContext';
import { VisibleRange } from 'vs/editor/common/view/renderingContext'; import { VisibleRange } from 'vs/editor/common/view/renderingContext';
import { EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, EditorMouseEvent } from 'vs/editor/browser/editorDom'; import { EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, EditorMouseEvent, createEditorPagePosition, ClientCoordinates } from 'vs/editor/browser/editorDom';
import { StandardMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { StandardMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { EditorZoom } from 'vs/editor/common/config/editorZoom';
import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor'; import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
@@ -204,9 +204,7 @@ export class MouseHandler extends ViewEventHandler implements IDisposable {
} }
// --- begin event handlers // --- begin event handlers
_layoutInfo: editorCommon.EditorLayoutInfo;
public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean { public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
this._layoutInfo = layoutInfo;
return false; return false;
} }
public onScrollChanged(e: editorCommon.IScrollEvent): boolean { public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
@@ -224,13 +222,26 @@ export class MouseHandler extends ViewEventHandler implements IDisposable {
} }
// --- end event handlers // --- end event handlers
public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
let clientPos = new ClientCoordinates(clientX, clientY);
let pos = clientPos.toPageCoordinates();
let editorPos = createEditorPagePosition(this.viewHelper.viewDomNode);
if (pos.y < editorPos.y || pos.y > editorPos.y + editorPos.height || pos.x < editorPos.x || pos.x > editorPos.x + editorPos.width) {
return null;
}
let lastViewCursorsRenderData = this.viewHelper.getLastViewCursorsRenderData();
return this.mouseTargetFactory.createMouseTarget(lastViewCursorsRenderData, editorPos, pos, null);
}
protected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): editorBrowser.IMouseTarget { protected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): editorBrowser.IMouseTarget {
let lastViewCursorsRenderData = this.viewHelper.getLastViewCursorsRenderData(); let lastViewCursorsRenderData = this.viewHelper.getLastViewCursorsRenderData();
return this.mouseTargetFactory.createMouseTarget(this._layoutInfo, lastViewCursorsRenderData, e, testEventTarget); return this.mouseTargetFactory.createMouseTarget(lastViewCursorsRenderData, e.editorPos, e.pos, testEventTarget ? e.target : null);
} }
private _getMouseColumn(e: EditorMouseEvent): number { private _getMouseColumn(e: EditorMouseEvent): number {
return this.mouseTargetFactory.getMouseColumn(this._layoutInfo, e); return this.mouseTargetFactory.getMouseColumn(e.editorPos, e.pos);
} }
protected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void { protected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void {
@@ -453,23 +464,23 @@ class MouseDownOperation extends Disposable {
let mouseColumn = this._getMouseColumn(e); let mouseColumn = this._getMouseColumn(e);
if (e.posy < editorContent.top) { if (e.posy < editorContent.y) {
let aboveLineNumber = this._viewHelper.getLineNumberAtVerticalOffset(Math.max(this._viewHelper.getScrollTop() - (editorContent.top - e.posy), 0)); let aboveLineNumber = this._viewHelper.getLineNumberAtVerticalOffset(Math.max(this._viewHelper.getScrollTop() - (editorContent.y - e.posy), 0));
return new MousePosition(new Position(aboveLineNumber, 1), mouseColumn); return new MousePosition(new Position(aboveLineNumber, 1), mouseColumn);
} }
if (e.posy > editorContent.top + editorContent.height) { if (e.posy > editorContent.y + editorContent.height) {
let belowLineNumber = this._viewHelper.getLineNumberAtVerticalOffset(this._viewHelper.getScrollTop() + (e.posy - editorContent.top)); let belowLineNumber = this._viewHelper.getLineNumberAtVerticalOffset(this._viewHelper.getScrollTop() + (e.posy - editorContent.y));
return new MousePosition(new Position(belowLineNumber, this._context.model.getLineMaxColumn(belowLineNumber)), mouseColumn); return new MousePosition(new Position(belowLineNumber, this._context.model.getLineMaxColumn(belowLineNumber)), mouseColumn);
} }
let possibleLineNumber = this._viewHelper.getLineNumberAtVerticalOffset(this._viewHelper.getScrollTop() + (e.posy - editorContent.top)); let possibleLineNumber = this._viewHelper.getLineNumberAtVerticalOffset(this._viewHelper.getScrollTop() + (e.posy - editorContent.y));
if (e.posx < editorContent.left) { if (e.posx < editorContent.x) {
return new MousePosition(new Position(possibleLineNumber, 1), mouseColumn); return new MousePosition(new Position(possibleLineNumber, 1), mouseColumn);
} }
if (e.posx > editorContent.left + editorContent.width) { if (e.posx > editorContent.x + editorContent.width) {
return new MousePosition(new Position(possibleLineNumber, this._context.model.getLineMaxColumn(possibleLineNumber)), mouseColumn); return new MousePosition(new Position(possibleLineNumber, this._context.model.getLineMaxColumn(possibleLineNumber)), mouseColumn);
} }
File diff suppressed because it is too large Load Diff
@@ -7,9 +7,8 @@
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
import { IScrollEvent } from 'vs/editor/common/editorCommon';
import { MouseHandler, IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler'; import { MouseHandler, IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler';
import { IViewController } from 'vs/editor/browser/editorBrowser'; import { IViewController, IMouseTarget } from 'vs/editor/browser/editorBrowser';
import { ViewContext } from 'vs/editor/common/view/viewContext'; import { ViewContext } from 'vs/editor/common/view/viewContext';
import { EditorMouseEvent } from 'vs/editor/browser/editorDom'; import { EditorMouseEvent } from 'vs/editor/browser/editorDom';
@@ -247,8 +246,8 @@ export class PointerHandler implements IDisposable {
} }
} }
public onScrollChanged(e: IScrollEvent): void { public getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget {
this.handler.onScrollChanged(e); return this.handler.getTargetAtClientPoint(clientX, clientY);
} }
public dispose(): void { public dispose(): void {
+9
View File
@@ -44,6 +44,7 @@ export interface ICodeEditorHelper {
getVerticalOffsetForPosition(lineNumber: number, column: number): number; getVerticalOffsetForPosition(lineNumber: number, column: number): number;
delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void; delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void;
getOffsetForColumn(lineNumber: number, column: number): number; getOffsetForColumn(lineNumber: number, column: number): number;
getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget;
} }
/** /**
@@ -522,6 +523,14 @@ export interface ICodeEditor extends editorCommon.ICommonCodeEditor {
*/ */
getTopForPosition(lineNumber: number, column: number): number; getTopForPosition(lineNumber: number, column: number): number;
/**
* Get the hit test target at coordinates `clientX` and `clientY`.
* The coordinates are relative to the top-left of the viewport.
*
* @returns Hit test target or null if the coordinates fall outside the editor or the editor has no model.
*/
getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget;
/** /**
* Get the visible position for `position`. * Get the visible position for `position`.
* The result position takes scrolling into account and is relative to the top left corner of the editor. * The result position takes scrolling into account and is relative to the top left corner of the editor.
+73 -12
View File
@@ -9,27 +9,88 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import { GlobalMouseMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; import { GlobalMouseMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor';
/**
* Coordinates relative to the whole document (e.g. mouse event's pageX and pageY)
*/
export class PageCoordinates {
_pageCoordinatesBrand: void;
public readonly x: number;
public readonly y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public toClientCoordinates(): ClientCoordinates {
return new ClientCoordinates(this.x - dom.StandardWindow.scrollX, this.y - dom.StandardWindow.scrollY);
}
}
/**
* Coordinates within the application's client area (i.e. origin is document's scroll position).
*
* For example, clicking in the top-left corner of the client area will
* always result in a mouse event with a client.x value of 0, regardless
* of whether the page is scrolled horizontally.
*/
export class ClientCoordinates {
_clientCoordinatesBrand: void;
public readonly clientX: number;
public readonly clientY: number;
constructor(clientX: number, clientY: number) {
this.clientX = clientX;
this.clientY = clientY;
}
public toPageCoordinates(): PageCoordinates {
return new PageCoordinates(this.clientX + dom.StandardWindow.scrollX, this.clientY + dom.StandardWindow.scrollY);
}
}
/**
* The position of the editor in the page.
*/
export class EditorPagePosition {
_editorPagePositionBrand: void;
public readonly x: number;
public readonly y: number;
public readonly width: number;
public readonly height: number;
constructor(x: number, y: number, width: number, height: number) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
export function createEditorPagePosition(editorViewDomNode: HTMLElement): EditorPagePosition {
let editorPos = dom.getDomNodePagePosition(editorViewDomNode);
return new EditorPagePosition(editorPos.left, editorPos.top, editorPos.width, editorPos.height);
}
export class EditorMouseEvent extends StandardMouseEvent { export class EditorMouseEvent extends StandardMouseEvent {
_editorMouseEventBrand: void; _editorMouseEventBrand: void;
editorPos: dom.IDomNodePagePosition; /**
* Coordinates relative to the whole document.
*/
public readonly pos: PageCoordinates;
/** /**
* The horizontal position of the cursor relative to the viewport (i.e. scrolled). * Editor's coordinates relative to the whole document.
*/ */
viewportx: number; public readonly editorPos: EditorPagePosition;
/**
* The vertical position of the cursor relative to the viewport (i.e. scrolled).
*/
viewporty: number;
constructor(e: MouseEvent, editorViewDomNode: HTMLElement) { constructor(e: MouseEvent, editorViewDomNode: HTMLElement) {
super(e); super(e);
this.editorPos = dom.getDomNodePagePosition(editorViewDomNode); this.pos = new PageCoordinates(this.posx, this.posy);
this.editorPos = createEditorPagePosition(editorViewDomNode);
this.viewportx = this.posx - dom.StandardWindow.scrollX;
this.viewporty = this.posy - dom.StandardWindow.scrollY;
} }
} }
@@ -276,6 +276,13 @@ export function registerDefinitionProvider(languageId: string, provider: modes.D
return modes.DefinitionProviderRegistry.register(languageId, provider); return modes.DefinitionProviderRegistry.register(languageId, provider);
} }
/**
* Register a type definition provider (used by e.g. go to implementation).
*/
export function registerTypeDefinitionProvider(languageId: string, provider: modes.TypeDefinitionProvider): IDisposable {
return modes.TypeDefinitionProviderRegistry.register(languageId, provider);
}
/** /**
* Register a code lens provider (used by e.g. inline code lenses). * Register a code lens provider (used by e.g. inline code lenses).
*/ */
@@ -633,6 +640,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
registerDocumentSymbolProvider: registerDocumentSymbolProvider, registerDocumentSymbolProvider: registerDocumentSymbolProvider,
registerDocumentHighlightProvider: registerDocumentHighlightProvider, registerDocumentHighlightProvider: registerDocumentHighlightProvider,
registerDefinitionProvider: registerDefinitionProvider, registerDefinitionProvider: registerDefinitionProvider,
registerTypeDefinitionProvider: registerTypeDefinitionProvider,
registerCodeLensProvider: registerCodeLensProvider, registerCodeLensProvider: registerCodeLensProvider,
registerCodeActionProvider: registerCodeActionProvider, registerCodeActionProvider: registerCodeActionProvider,
registerDocumentFormattingEditProvider: registerDocumentFormattingEditProvider, registerDocumentFormattingEditProvider: registerDocumentFormattingEditProvider,
+11 -2
View File
@@ -197,7 +197,6 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
// (there have been reports of tiny blinking cursors) // (there have been reports of tiny blinking cursors)
// (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea) // (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea)
this.textAreaCover = document.createElement('div'); this.textAreaCover = document.createElement('div');
PartFingerprints.write(this.textAreaCover, PartFingerprint.TextAreaCover);
if (this._context.configuration.editor.viewInfo.glyphMargin) { if (this._context.configuration.editor.viewInfo.glyphMargin) {
this.textAreaCover.className = 'monaco-editor-background ' + editorBrowser.ClassNames.GLYPH_MARGIN + ' ' + editorBrowser.ClassNames.TEXTAREA_COVER; this.textAreaCover.className = 'monaco-editor-background ' + editorBrowser.ClassNames.GLYPH_MARGIN + ' ' + editorBrowser.ClassNames.TEXTAREA_COVER;
} else { } else {
@@ -609,7 +608,15 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
return -1; return -1;
} }
return visibleRanges[0].left; return visibleRanges[0].left;
},
getTargetAtClientPoint: (clientX: number, clientY: number): editorBrowser.IMouseTarget => {
if (this._isDisposed) {
throw new Error('ViewImpl.codeEditorHelper.getTargetAtClientPoint: View is disposed');
}
return this.pointerHandler.getTargetAtClientPoint(clientX, clientY);
} }
}; };
} }
return this.codeEditorHelper; return this.codeEditorHelper;
@@ -666,7 +673,9 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.keyboardHandler.focusTextArea(); this.keyboardHandler.focusTextArea();
// IE does not trigger the focus event immediately, so we must help it a little bit // IE does not trigger the focus event immediately, so we must help it a little bit
this._setHasFocus(true); if (document.activeElement === this.textArea) {
this._setHasFocus(true);
}
} }
public isFocused(): boolean { public isFocused(): boolean {
-5
View File
@@ -30,17 +30,12 @@ export abstract class ViewPart extends ViewEventHandler {
export const enum PartFingerprint { export const enum PartFingerprint {
None, None,
ContentWidgets, ContentWidgets,
Margin,
OverflowingContentWidgets, OverflowingContentWidgets,
OverflowGuard, OverflowGuard,
OverlayWidgets, OverlayWidgets,
OverviewRuler,
ScrollableElement, ScrollableElement,
TextArea, TextArea,
TextAreaCover,
ViewCursorsLayer,
ViewLines, ViewLines,
ViewZones
} }
export class PartFingerprints { export class PartFingerprints {
@@ -8,7 +8,7 @@
import { StyleMutator, FastDomNode, createFastDomNode } from 'vs/base/browser/styleMutator'; import { StyleMutator, FastDomNode, createFastDomNode } from 'vs/base/browser/styleMutator';
import * as editorCommon from 'vs/editor/common/editorCommon'; import * as editorCommon from 'vs/editor/common/editorCommon';
import { ClassNames } from 'vs/editor/browser/editorBrowser'; import { ClassNames } from 'vs/editor/browser/editorBrowser';
import { ViewPart, PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart'; import { ViewPart } from 'vs/editor/browser/view/viewPart';
import { ViewContext } from 'vs/editor/common/view/viewContext'; import { ViewContext } from 'vs/editor/common/view/viewContext';
import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
import { ILayoutProvider } from 'vs/editor/browser/viewLayout/layoutProvider'; import { ILayoutProvider } from 'vs/editor/browser/viewLayout/layoutProvider';
@@ -39,7 +39,6 @@ export class Margin extends ViewPart {
public _createDomNode(): HTMLElement { public _createDomNode(): HTMLElement {
let domNode = document.createElement('div'); let domNode = document.createElement('div');
PartFingerprints.write(domNode, PartFingerprint.Margin);
domNode.className = ClassNames.MARGIN + ' monaco-editor-background'; domNode.className = ClassNames.MARGIN + ' monaco-editor-background';
domNode.style.position = 'absolute'; domNode.style.position = 'absolute';
domNode.setAttribute('role', 'presentation'); domNode.setAttribute('role', 'presentation');
@@ -9,7 +9,6 @@ import { OverviewRulerPosition, OverviewRulerLane, OverviewRulerZone, ColorZone
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import * as browser from 'vs/base/browser/browser'; import * as browser from 'vs/base/browser/browser';
import { OverviewZoneManager } from 'vs/editor/common/view/overviewZoneManager'; import { OverviewZoneManager } from 'vs/editor/common/view/overviewZoneManager';
import { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart';
export class OverviewRulerImpl { export class OverviewRulerImpl {
@@ -25,7 +24,6 @@ export class OverviewRulerImpl {
this._canvasLeftOffset = canvasLeftOffset; this._canvasLeftOffset = canvasLeftOffset;
this._domNode = <HTMLCanvasElement>document.createElement('canvas'); this._domNode = <HTMLCanvasElement>document.createElement('canvas');
PartFingerprints.write(this._domNode, PartFingerprint.OverviewRuler);
this._domNode.className = cssClassName; this._domNode.className = cssClassName;
this._domNode.style.position = 'absolute'; this._domNode.style.position = 'absolute';
@@ -8,7 +8,7 @@
import 'vs/css!./viewCursors'; import 'vs/css!./viewCursors';
import * as editorCommon from 'vs/editor/common/editorCommon'; import * as editorCommon from 'vs/editor/common/editorCommon';
import { ClassNames } from 'vs/editor/browser/editorBrowser'; import { ClassNames } from 'vs/editor/browser/editorBrowser';
import { ViewPart, PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart'; import { ViewPart } from 'vs/editor/browser/view/viewPart';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
import { IViewCursorRenderData, ViewCursor } from 'vs/editor/browser/viewParts/viewCursors/viewCursor'; import { IViewCursorRenderData, ViewCursor } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
import { ViewContext } from 'vs/editor/common/view/viewContext'; import { ViewContext } from 'vs/editor/common/view/viewContext';
@@ -49,7 +49,6 @@ export class ViewCursors extends ViewPart {
this._renderData = []; this._renderData = [];
this._domNode = createFastDomNode(document.createElement('div')); this._domNode = createFastDomNode(document.createElement('div'));
PartFingerprints.write(this._domNode.domNode, PartFingerprint.ViewCursorsLayer);
this._updateDomClassName(); this._updateDomClassName();
this._domNode.domNode.appendChild(this._primaryCursor.getDomNode()); this._domNode.domNode.appendChild(this._primaryCursor.getDomNode());
@@ -8,7 +8,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { StyleMutator } from 'vs/base/browser/styleMutator'; import { StyleMutator } from 'vs/base/browser/styleMutator';
import * as editorCommon from 'vs/editor/common/editorCommon'; import * as editorCommon from 'vs/editor/common/editorCommon';
import { ClassNames, IViewZone } from 'vs/editor/browser/editorBrowser'; import { ClassNames, IViewZone } from 'vs/editor/browser/editorBrowser';
import { ViewPart, PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart'; import { ViewPart } from 'vs/editor/browser/view/viewPart';
import { ViewContext } from 'vs/editor/common/view/viewContext'; import { ViewContext } from 'vs/editor/common/view/viewContext';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
@@ -49,7 +49,6 @@ export class ViewZones extends ViewPart {
this._whitespaceManager = whitespaceManager; this._whitespaceManager = whitespaceManager;
this.domNode = document.createElement('div'); this.domNode = document.createElement('div');
PartFingerprints.write(this.domNode, PartFingerprint.ViewZones);
this.domNode.className = ClassNames.VIEW_ZONES; this.domNode.className = ClassNames.VIEW_ZONES;
this.domNode.style.position = 'absolute'; this.domNode.style.position = 'absolute';
this.domNode.setAttribute('role', 'presentation'); this.domNode.setAttribute('role', 'presentation');
@@ -404,6 +404,13 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
return this._view.getCodeEditorHelper().getVerticalOffsetForPosition(lineNumber, column); return this._view.getCodeEditorHelper().getVerticalOffsetForPosition(lineNumber, column);
} }
public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
if (!this.hasView) {
return null;
}
return this._view.getCodeEditorHelper().getTargetAtClientPoint(clientX, clientY);
}
public getScrolledVisiblePosition(rawPosition: editorCommon.IPosition): { top: number; left: number; height: number; } { public getScrolledVisiblePosition(rawPosition: editorCommon.IPosition): { top: number; left: number; height: number; } {
if (!this.hasView) { if (!this.hasView) {
return null; return null;
@@ -5,6 +5,7 @@
.monaco-editor .vs-whitespace { .monaco-editor .vs-whitespace {
display:inline-block; display:inline-block;
font-weight: normal !important;
} }
.monaco-editor.hc-black .view-line { .monaco-editor.hc-black .view-line {
mix-blend-mode: difference; mix-blend-mode: difference;
@@ -118,7 +118,7 @@ export class TextAreaHandler extends Disposable {
// In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled. // In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled.
if (!this.Browser.isEdgeOrIE) { if (!this.Browser.isEdgeOrIE) {
this.setTextAreaState('compositionstart', this.textAreaState.toEmpty()); this.setTextAreaState('compositionstart', this.textAreaState.toEmpty(), false);
} }
this._onCompositionStart.fire({ this._onCompositionStart.fire({
@@ -200,13 +200,13 @@ export class TextAreaHandler extends Disposable {
} else { } else {
if (this.textArea.getSelectionStart() !== this.textArea.getSelectionEnd()) { if (this.textArea.getSelectionStart() !== this.textArea.getSelectionEnd()) {
// Clean up the textarea, to get a clean paste // Clean up the textarea, to get a clean paste
this.setTextAreaState('paste', this.textAreaState.toEmpty()); this.setTextAreaState('paste', this.textAreaState.toEmpty(), false);
} }
this._nextCommand = ReadFromTextArea.Paste; this._nextCommand = ReadFromTextArea.Paste;
} }
})); }));
this._writePlaceholderAndSelectTextArea('ctor'); this._writePlaceholderAndSelectTextArea('ctor', false);
} }
public dispose(): void { public dispose(): void {
@@ -227,24 +227,24 @@ export class TextAreaHandler extends Disposable {
} }
this.hasFocus = isFocused; this.hasFocus = isFocused;
if (this.hasFocus) { if (this.hasFocus) {
this._writePlaceholderAndSelectTextArea('focusgain'); this._writePlaceholderAndSelectTextArea('focusgain', false);
} }
} }
public setCursorSelections(primary: Range, secondary: Range[]): void { public setCursorSelections(primary: Range, secondary: Range[]): void {
this.selection = primary; this.selection = primary;
this.selections = [primary].concat(secondary); this.selections = [primary].concat(secondary);
this._writePlaceholderAndSelectTextArea('selection changed'); this._writePlaceholderAndSelectTextArea('selection changed', false);
} }
// --- end event handlers // --- end event handlers
private setTextAreaState(reason: string, textAreaState: TextAreaState): void { private setTextAreaState(reason: string, textAreaState: TextAreaState, forceFocus: boolean): void {
if (!this.hasFocus) { if (!this.hasFocus) {
textAreaState = textAreaState.resetSelection(); textAreaState = textAreaState.resetSelection();
} }
textAreaState.applyToTextArea(reason, this.textArea, this.hasFocus); textAreaState.applyToTextArea(reason, this.textArea, this.hasFocus || forceFocus);
this.textAreaState = textAreaState; this.textAreaState = textAreaState;
} }
@@ -281,18 +281,18 @@ export class TextAreaHandler extends Disposable {
}); });
} }
public writePlaceholderAndSelectTextAreaSync(): void { public focusTextArea(): void {
this._writePlaceholderAndSelectTextArea('focusTextArea'); this._writePlaceholderAndSelectTextArea('focusTextArea', true);
} }
private _writePlaceholderAndSelectTextArea(reason: string): void { private _writePlaceholderAndSelectTextArea(reason: string, forceFocus: boolean): void {
if (!this.textareaIsShownAtCursor) { if (!this.textareaIsShownAtCursor) {
// Do not write to the textarea if it is visible. // Do not write to the textarea if it is visible.
if (this.Browser.isIPad) { if (this.Browser.isIPad) {
// Do not place anything in the textarea for the iPad // Do not place anything in the textarea for the iPad
this.setTextAreaState(reason, this.textAreaState.toEmpty()); this.setTextAreaState(reason, this.textAreaState.toEmpty(), forceFocus);
} else { } else {
this.setTextAreaState(reason, this.textAreaState.fromEditorSelection(this.model, this.selection)); this.setTextAreaState(reason, this.textAreaState.fromEditorSelection(this.model, this.selection), forceFocus);
} }
} }
} }
@@ -304,7 +304,7 @@ export class TextAreaHandler extends Disposable {
if (e.canUseTextData()) { if (e.canUseTextData()) {
e.setTextData(whatToCopy); e.setTextData(whatToCopy);
} else { } else {
this.setTextAreaState('copy or cut', this.textAreaState.fromText(whatToCopy)); this.setTextAreaState('copy or cut', this.textAreaState.fromText(whatToCopy), false);
} }
if (this.Browser.enableEmptySelectionClipboard) { if (this.Browser.enableEmptySelectionClipboard) {
+7 -4
View File
@@ -243,10 +243,9 @@ export interface IEditorOptions {
*/ */
roundedSelection?: boolean; roundedSelection?: boolean;
/** /**
* Theme to be used for rendering. Consists of two parts, the UI theme and the syntax theme, * Theme to be used for rendering.
* separated by a space. * The current out-of-the-box available themes are: 'vs' (default), 'vs-dark', 'hc-black'.
* The current available UI themes are: 'vs' (default), 'vs-dark', 'hc-black' * You can create custom themes via `monaco.editor.defineTheme`.
* The syntax themes are contributed. The default is 'default-theme'
*/ */
theme?: string; theme?: string;
/** /**
@@ -3064,6 +3063,10 @@ export namespace ModeContextKeys {
* @internal * @internal
*/ */
export const hasDefinitionProvider = new RawContextKey<boolean>('editorHasDefinitionProvider', undefined); export const hasDefinitionProvider = new RawContextKey<boolean>('editorHasDefinitionProvider', undefined);
/**
* @internal
*/
export const hasTypeDefinitionProvider = new RawContextKey<boolean>('editorHasTypeDefinitionProvider', undefined);
/** /**
* @internal * @internal
*/ */
+16
View File
@@ -418,6 +418,7 @@ export interface Location {
* defined. * defined.
*/ */
export type Definition = Location | Location[]; export type Definition = Location | Location[];
/** /**
* The definition provider interface defines the contract between extensions and * The definition provider interface defines the contract between extensions and
* the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)
@@ -430,6 +431,16 @@ export interface DefinitionProvider {
provideDefinition(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>; provideDefinition(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>;
} }
/**
* The type definition provider interface defines the contract between extensions and
* the go to implementation feature.
*/
export interface TypeDefinitionProvider {
/**
* Provide the implementation of the symbol at the given position and document.
*/
provideTypeDefinition(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>;
}
/** /**
* A symbol kind. * A symbol kind.
@@ -738,6 +749,11 @@ export const DocumentHighlightProviderRegistry = new LanguageFeatureRegistry<Doc
*/ */
export const DefinitionProviderRegistry = new LanguageFeatureRegistry<DefinitionProvider>(); export const DefinitionProviderRegistry = new LanguageFeatureRegistry<DefinitionProvider>();
/**
* @internal
*/
export const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry<TypeDefinitionProvider>();
/** /**
* @internal * @internal
*/ */
@@ -19,6 +19,7 @@ export class EditorModeContext {
private _hasCodeActionsProvider: IContextKey<boolean>; private _hasCodeActionsProvider: IContextKey<boolean>;
private _hasCodeLensProvider: IContextKey<boolean>; private _hasCodeLensProvider: IContextKey<boolean>;
private _hasDefinitionProvider: IContextKey<boolean>; private _hasDefinitionProvider: IContextKey<boolean>;
private _hasTypeDefinitionProvider: IContextKey<boolean>;
private _hasHoverProvider: IContextKey<boolean>; private _hasHoverProvider: IContextKey<boolean>;
private _hasDocumentHighlightProvider: IContextKey<boolean>; private _hasDocumentHighlightProvider: IContextKey<boolean>;
private _hasDocumentSymbolProvider: IContextKey<boolean>; private _hasDocumentSymbolProvider: IContextKey<boolean>;
@@ -39,6 +40,7 @@ export class EditorModeContext {
this._hasCodeActionsProvider = ModeContextKeys.hasCodeActionsProvider.bindTo(contextKeyService); this._hasCodeActionsProvider = ModeContextKeys.hasCodeActionsProvider.bindTo(contextKeyService);
this._hasCodeLensProvider = ModeContextKeys.hasCodeLensProvider.bindTo(contextKeyService); this._hasCodeLensProvider = ModeContextKeys.hasCodeLensProvider.bindTo(contextKeyService);
this._hasDefinitionProvider = ModeContextKeys.hasDefinitionProvider.bindTo(contextKeyService); this._hasDefinitionProvider = ModeContextKeys.hasDefinitionProvider.bindTo(contextKeyService);
this._hasTypeDefinitionProvider = ModeContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService);
this._hasHoverProvider = ModeContextKeys.hasHoverProvider.bindTo(contextKeyService); this._hasHoverProvider = ModeContextKeys.hasHoverProvider.bindTo(contextKeyService);
this._hasDocumentHighlightProvider = ModeContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService); this._hasDocumentHighlightProvider = ModeContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService);
this._hasDocumentSymbolProvider = ModeContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService); this._hasDocumentSymbolProvider = ModeContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService);
@@ -57,6 +59,7 @@ export class EditorModeContext {
modes.CodeActionProviderRegistry.onDidChange(this._update, this, this._disposables); modes.CodeActionProviderRegistry.onDidChange(this._update, this, this._disposables);
modes.CodeLensProviderRegistry.onDidChange(this._update, this, this._disposables); modes.CodeLensProviderRegistry.onDidChange(this._update, this, this._disposables);
modes.DefinitionProviderRegistry.onDidChange(this._update, this, this._disposables); modes.DefinitionProviderRegistry.onDidChange(this._update, this, this._disposables);
modes.TypeDefinitionProviderRegistry.onDidChange(this._update, this, this._disposables);
modes.HoverProviderRegistry.onDidChange(this._update, this, this._disposables); modes.HoverProviderRegistry.onDidChange(this._update, this, this._disposables);
modes.DocumentHighlightProviderRegistry.onDidChange(this._update, this, this._disposables); modes.DocumentHighlightProviderRegistry.onDidChange(this._update, this, this._disposables);
modes.DocumentSymbolProviderRegistry.onDidChange(this._update, this, this._disposables); modes.DocumentSymbolProviderRegistry.onDidChange(this._update, this, this._disposables);
@@ -79,6 +82,7 @@ export class EditorModeContext {
this._hasCodeActionsProvider.reset(); this._hasCodeActionsProvider.reset();
this._hasCodeLensProvider.reset(); this._hasCodeLensProvider.reset();
this._hasDefinitionProvider.reset(); this._hasDefinitionProvider.reset();
this._hasTypeDefinitionProvider.reset();
this._hasHoverProvider.reset(); this._hasHoverProvider.reset();
this._hasDocumentHighlightProvider.reset(); this._hasDocumentHighlightProvider.reset();
this._hasDocumentSymbolProvider.reset(); this._hasDocumentSymbolProvider.reset();
@@ -100,6 +104,7 @@ export class EditorModeContext {
this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model)); this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model));
this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model));
this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model)); this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model));
this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model));
this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model)); this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model));
this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model)); this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model));
this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model)); this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model));
@@ -17,7 +17,6 @@ import { ReplaceAllCommand } from './replaceAllCommand';
import { Selection } from 'vs/editor/common/core/selection'; import { Selection } from 'vs/editor/common/core/selection';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { IKeybindings } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindings } from 'vs/platform/keybinding/common/keybinding';
import { SearchParams } from 'vs/editor/common/model/textModelSearch';
export const ToggleCaseSensitiveKeybinding: IKeybindings = { export const ToggleCaseSensitiveKeybinding: IKeybindings = {
primary: KeyMod.Alt | KeyCode.KEY_C, primary: KeyMod.Alt | KeyCode.KEY_C,
@@ -3,8 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as strings from 'vs/base/common/strings';
import { IPatternInfo } from 'vs/platform/search/common/search';
import { CharCode } from 'vs/base/common/charCode'; import { CharCode } from 'vs/base/common/charCode';
export class ReplacePattern { export class ReplacePattern {
@@ -40,7 +38,7 @@ export class ReplacePattern {
} }
} }
public buildReplaceString(matches:string[]): string { public buildReplaceString(matches: string[]): string {
if (this._staticValue) { if (this._staticValue) {
return this._staticValue; return this._staticValue;
} }
@@ -61,7 +59,7 @@ export class ReplacePattern {
return result; return result;
} }
private static _substitute(matchIndex: number, matches:string[]): string { private static _substitute(matchIndex: number, matches: string[]): string {
if (matchIndex === 0) { if (matchIndex === 0) {
return matches[0]; return matches[0];
} }
@@ -83,11 +81,11 @@ export class ReplacePattern {
*/ */
export class ReplacePiece { export class ReplacePiece {
public static staticValue(value:string): ReplacePiece { public static staticValue(value: string): ReplacePiece {
return new ReplacePiece(value, -1); return new ReplacePiece(value, -1);
} }
public static matchIndex(index:number): ReplacePiece { public static matchIndex(index: number): ReplacePiece {
return new ReplacePiece(null, index); return new ReplacePiece(null, index);
} }
@@ -99,7 +99,7 @@ suite('Replace Pattern test', () => {
}); });
test('get replace string if given text is a complete match', () => { test('get replace string if given text is a complete match', () => {
function assertReplace(target:string, search: RegExp, replaceString: string, expected: string): void { function assertReplace(target: string, search: RegExp, replaceString: string, expected: string): void {
let replacePattern = parseReplaceString(replaceString); let replacePattern = parseReplaceString(replaceString);
let m = search.exec(target); let m = search.exec(target);
let actual = replacePattern.buildReplaceString(m); let actual = replacePattern.buildReplaceString(m);
@@ -125,7 +125,7 @@ suite('Replace Pattern test', () => {
}); });
test('get replace string if match is sub-string of the text', () => { test('get replace string if match is sub-string of the text', () => {
function assertReplace(target:string, search: RegExp, replaceString: string, expected: string): void { function assertReplace(target: string, search: RegExp, replaceString: string, expected: string): void {
let replacePattern = parseReplaceString(replaceString); let replacePattern = parseReplaceString(replaceString);
let m = search.exec(target); let m = search.exec(target);
let actual = replacePattern.buildReplaceString(m); let actual = replacePattern.buildReplaceString(m);
@@ -26,13 +26,14 @@ import { editorAction, IActionOptions, ServicesAccessor, EditorAction } from 'vs
import { Location, DefinitionProviderRegistry } from 'vs/editor/common/modes'; import { Location, DefinitionProviderRegistry } from 'vs/editor/common/modes';
import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser';
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
import { getDeclarationsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; import { getDeclarationsAtPosition, getTypeDefinitionAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/referencesController'; import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/referencesController';
import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/referencesModel'; import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/referencesModel';
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { PeekContext } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget'; import { PeekContext } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService'; import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
import * as corePosition from 'vs/editor/common/core/position';
import ModeContextKeys = editorCommon.ModeContextKeys; import ModeContextKeys = editorCommon.ModeContextKeys;
import EditorContextKeys = editorCommon.EditorContextKeys; import EditorContextKeys = editorCommon.EditorContextKeys;
@@ -64,7 +65,7 @@ export class DefinitionAction extends EditorAction {
let model = editor.getModel(); let model = editor.getModel();
let pos = editor.getPosition(); let pos = editor.getPosition();
return getDeclarationsAtPosition(model, pos).then(references => { return this.getDeclarationsAtPosition(model, pos).then(references => {
if (!references) { if (!references) {
return; return;
@@ -104,6 +105,10 @@ export class DefinitionAction extends EditorAction {
}); });
} }
protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise<Location[]> {
return getDeclarationsAtPosition(model, position);
}
private _onResult(editorService: IEditorService, editor: editorCommon.ICommonCodeEditor, model: ReferencesModel) { private _onResult(editorService: IEditorService, editor: editorCommon.ICommonCodeEditor, model: ReferencesModel) {
if (this._configuration.openInPeek) { if (this._configuration.openInPeek) {
this._openInPeek(editorService, editor, model); this._openInPeek(editorService, editor, model);
@@ -217,6 +222,61 @@ export class PeekDefinitionAction extends DefinitionAction {
} }
} }
@editorAction
export class GoToImplementationAction extends DefinitionAction {
public static ID = 'editor.action.goToImplementation';
constructor() {
super(new DefinitionActionConfig(), {
id: GoToImplementationAction.ID,
label: nls.localize('actions.goToImplementation.label', "Go to Implementation"),
alias: 'Go to Implementation',
precondition: ModeContextKeys.hasTypeDefinitionProvider,
kbOpts: {
kbExpr: EditorContextKeys.TextFocus,
primary: KeyMod.CtrlCmd | KeyCode.F12
},
menuOpts: {
group: 'navigation',
order: 1.3
}
});
}
protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise<Location[]> {
return getTypeDefinitionAtPosition(model, position);
}
}
@editorAction
export class PeekImplementationAction extends DefinitionAction {
public static ID = 'editor.action.peekImplementation';
constructor() {
super(new DefinitionActionConfig(false, true, false), {
id: PeekImplementationAction.ID,
label: nls.localize('actions.peekImplementation.label', "Peek Implementation"),
alias: 'Peek Implementation',
precondition: ModeContextKeys.hasTypeDefinitionProvider,
kbOpts: {
kbExpr: EditorContextKeys.TextFocus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F12
},
menuOpts: {
group: 'navigation',
order: 1.3
}
});
}
protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise<Location[]> {
return getTypeDefinitionAtPosition(model, position);
}
}
// --- Editor Contribution to goto definition using the mouse and a modifier key // --- Editor Contribution to goto definition using the mouse and a modifier key
@editorContribution @editorContribution
@@ -9,10 +9,24 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { IReadOnlyModel } from 'vs/editor/common/editorCommon'; import { IReadOnlyModel } from 'vs/editor/common/editorCommon';
import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions';
import { DefinitionProviderRegistry, Location } from 'vs/editor/common/modes'; import { DefinitionProviderRegistry, TypeDefinitionProviderRegistry, Location } from 'vs/editor/common/modes';
import { asWinJsPromise } from 'vs/base/common/async'; import { asWinJsPromise } from 'vs/base/common/async';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
function outputResults(promises: TPromise<Location[]>[]) {
return TPromise.join(promises).then(allReferences => {
let result: Location[] = [];
for (let references of allReferences) {
if (Array.isArray(references)) {
result.push(...references);
} else if (references) {
result.push(references);
}
}
return result;
});
}
export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> { export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> {
const provider = DefinitionProviderRegistry.ordered(model); const provider = DefinitionProviderRegistry.ordered(model);
@@ -27,18 +41,25 @@ export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Posit
onUnexpectedExternalError(err); onUnexpectedExternalError(err);
}); });
}); });
return outputResults(promises);
return TPromise.join(promises).then(allReferences => {
let result: Location[] = [];
for (let references of allReferences) {
if (Array.isArray(references)) {
result.push(...references);
} else if (references) {
result.push(references);
}
}
return result;
});
} }
CommonEditorRegistry.registerDefaultLanguageCommand('_executeDefinitionProvider', getDeclarationsAtPosition); export function getTypeDefinitionAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> {
const provider = TypeDefinitionProviderRegistry.ordered(model);
// get results
const promises = provider.map((provider, idx) => {
return asWinJsPromise((token) => {
return provider.provideTypeDefinition(model, position, token);
}).then(result => {
return result;
}, err => {
onUnexpectedExternalError(err);
});
});
return outputResults(promises);
}
CommonEditorRegistry.registerDefaultLanguageCommand('_executeDefinitionProvider', getDeclarationsAtPosition);
CommonEditorRegistry.registerDefaultLanguageCommand('_executeTypeDefinitionProvider', getTypeDefinitionAtPosition);
@@ -105,9 +105,14 @@ export class SuggestController implements IEditorContribution {
// Wire up logic to accept a suggestion on certain characters // Wire up logic to accept a suggestion on certain characters
const autoAcceptOracle = new AcceptOnCharacterOracle(editor, this.widget, item => this.onDidSelectItem(item)); const autoAcceptOracle = new AcceptOnCharacterOracle(editor, this.widget, item => this.onDidSelectItem(item));
this.toDispose.push( this.toDispose.push(
autoAcceptOracle,
this.model.onDidCancel(autoAcceptOracle.reset, autoAcceptOracle), this.model.onDidCancel(autoAcceptOracle.reset, autoAcceptOracle),
this.model.onDidTrigger(autoAcceptOracle.reset, autoAcceptOracle), this.model.onDidTrigger(autoAcceptOracle.reset, autoAcceptOracle),
autoAcceptOracle this.model.onDidSuggest(e => {
if (e.completionModel.items.length === 0) {
autoAcceptOracle.reset();
}
})
); );
} }
@@ -124,7 +124,7 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr:
cursorOffset = off; cursorOffset = off;
cursorLength = len; cursorLength = len;
handler.setCursorSelections(new Range(1, 1 + cursorOffset, 1, 1 + cursorOffset + cursorLength), []); handler.setCursorSelections(new Range(1, 1 + cursorOffset, 1, 1 + cursorOffset + cursorLength), []);
handler.writePlaceholderAndSelectTextAreaSync(); handler.focusTextArea();
}; };
let updateModelAndPosition = (text: string, off: number, len: number) => { let updateModelAndPosition = (text: string, off: number, len: number) => {
+26 -4
View File
@@ -1154,10 +1154,9 @@ declare module monaco.editor {
*/ */
roundedSelection?: boolean; roundedSelection?: boolean;
/** /**
* Theme to be used for rendering. Consists of two parts, the UI theme and the syntax theme, * Theme to be used for rendering.
* separated by a space. * The current out-of-the-box available themes are: 'vs' (default), 'vs-dark', 'hc-black'.
* The current available UI themes are: 'vs' (default), 'vs-dark', 'hc-black' * You can create custom themes via `monaco.editor.defineTheme`.
* The syntax themes are contributed. The default is 'default-theme'
*/ */
theme?: string; theme?: string;
/** /**
@@ -3803,6 +3802,13 @@ declare module monaco.editor {
* Get the vertical position (top offset) for the position w.r.t. to the first line. * Get the vertical position (top offset) for the position w.r.t. to the first line.
*/ */
getTopForPosition(lineNumber: number, column: number): number; getTopForPosition(lineNumber: number, column: number): number;
/**
* Get the hit test target at coordinates `clientX` and `clientY`.
* The coordinates are relative to the top-left of the viewport.
*
* @returns Hit test target or null if the coordinates fall outside the editor or the editor has no model.
*/
getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget;
/** /**
* Get the visible position for `position`. * Get the visible position for `position`.
* The result position takes scrolling into account and is relative to the top left corner of the editor. * The result position takes scrolling into account and is relative to the top left corner of the editor.
@@ -3953,6 +3959,11 @@ declare module monaco.languages {
*/ */
export function registerDefinitionProvider(languageId: string, provider: DefinitionProvider): IDisposable; export function registerDefinitionProvider(languageId: string, provider: DefinitionProvider): IDisposable;
/**
* Register a type definition provider (used by e.g. go to implementation).
*/
export function registerTypeDefinitionProvider(languageId: string, provider: TypeDefinitionProvider): IDisposable;
/** /**
* Register a code lens provider (used by e.g. inline code lenses). * Register a code lens provider (used by e.g. inline code lenses).
*/ */
@@ -4532,6 +4543,17 @@ declare module monaco.languages {
provideDefinition(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>; provideDefinition(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>;
} }
/**
* The type definition provider interface defines the contract between extensions and
* the go to implementation feature.
*/
export interface TypeDefinitionProvider {
/**
* Provide the implementation of the symbol at the given position and document.
*/
provideTypeDefinition(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>;
}
/** /**
* A symbol kind. * A symbol kind.
*/ */
+1
View File
@@ -52,6 +52,7 @@ export interface IProductConfiguration {
npsSurveyUrl: string; npsSurveyUrl: string;
checksums: { [path: string]: string; }; checksums: { [path: string]: string; };
checksumFailMoreInfoUrl: string; checksumFailMoreInfoUrl: string;
extraNodeModules: string[];
} }
const rootPath = path.dirname(uri.parse(require.toUrl('')).fsPath); const rootPath = path.dirname(uri.parse(require.toUrl('')).fsPath);
+42 -9
View File
@@ -1632,6 +1632,24 @@ declare module 'vscode' {
provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Definition>; provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Definition>;
} }
/**
* The type definition provider interface defines the contract between extensions and
* the go to implementation feature.
*/
export interface TypeDefinitionProvider {
/**
* Provide the implementations of the symbol at the given position and document.
*
* @param document The document in which the command was invoked.
* @param position The position at which the command was invoked.
* @param token A cancellation token.
* @return A definition or a thenable that resolves to such. The lack of a result can be
* signaled by returning `undefined` or `null`.
*/
provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Definition>;
}
/** /**
* MarkedString can be used to render human readable text. It is either a markdown string * MarkedString can be used to render human readable text. It is either a markdown string
* or a code-block that provides a language and a code snippet. Note that * or a code-block that provides a language and a code snippet. Note that
@@ -3628,15 +3646,6 @@ declare module 'vscode' {
*/ */
export function createOutputChannel(name: string): OutputChannel; export function createOutputChannel(name: string): OutputChannel;
/**
* Set a message to the status bar. This is a short hand for the more powerful
* status bar [items](#window.createStatusBarItem).
*
* @param text The message to show, support icon subtitution as in status bar [items](#StatusBarItem.text).
* @return A disposable which hides the status bar message.
*/
export function setStatusBarMessage(text: string): Disposable;
/** /**
* Set a message to the status bar. This is a short hand for the more powerful * Set a message to the status bar. This is a short hand for the more powerful
* status bar [items](#window.createStatusBarItem). * status bar [items](#window.createStatusBarItem).
@@ -3657,6 +3666,18 @@ declare module 'vscode' {
*/ */
export function setStatusBarMessage(text: string, hideWhenDone: Thenable<any>): Disposable; export function setStatusBarMessage(text: string, hideWhenDone: Thenable<any>): Disposable;
/**
* Set a message to the status bar. This is a short hand for the more powerful
* status bar [items](#window.createStatusBarItem).
*
* *Note* that status bar messages stack and that they must be disposed when no
* longer used.
*
* @param text The message to show, support icon subtitution as in status bar [items](#StatusBarItem.text).
* @return A disposable which hides the status bar message.
*/
export function setStatusBarMessage(text: string): Disposable;
/** /**
* Creates a status bar [item](#StatusBarItem). * Creates a status bar [item](#StatusBarItem).
* *
@@ -4117,6 +4138,18 @@ declare module 'vscode' {
*/ */
export function registerDefinitionProvider(selector: DocumentSelector, provider: DefinitionProvider): Disposable; export function registerDefinitionProvider(selector: DocumentSelector, provider: DefinitionProvider): Disposable;
/**
* Register an type definition provider.
*
* Multiple providers can be registered for a language. In that case providers are sorted
* by their [score](#languages.match) and the best-matching provider is used.
*
* @param selector A selector that defines the documents this provider is applicable to.
* @param provider An implementation provider.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerTypeDefinitionProvider(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable;
/** /**
* Register a hover provider. * Register a hover provider.
* *
@@ -182,6 +182,9 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable { registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
return languageFeatures.registerDefinitionProvider(selector, provider); return languageFeatures.registerDefinitionProvider(selector, provider);
}, },
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
return languageFeatures.registerTypeDefinitionProvider(selector, provider);
},
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
return languageFeatures.registerHoverProvider(selector, provider); return languageFeatures.registerHoverProvider(selector, provider);
}, },
@@ -153,6 +153,7 @@ export abstract class MainThreadLanguageFeaturesShape {
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): TPromise<any> { throw ni(); } $registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): TPromise<any> { throw ni(); }
$emitCodeLensEvent(eventHandle: number, event?: any): TPromise<any> { throw ni(); } $emitCodeLensEvent(eventHandle: number, event?: any): TPromise<any> { throw ni(); }
$registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); } $registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); }
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); }
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); } $registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); }
$registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); } $registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); }
$registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); } $registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> { throw ni(); }
@@ -335,6 +336,7 @@ export abstract class ExtHostLanguageFeaturesShape {
$provideCodeLenses(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]> { throw ni(); } $provideCodeLenses(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]> { throw ni(); }
$resolveCodeLens(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> { throw ni(); } $resolveCodeLens(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> { throw ni(); }
$provideDefinition(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.Definition> { throw ni(); } $provideDefinition(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.Definition> { throw ni(); }
$provideTypeDefinition(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.Definition> { throw ni(); }
$provideHover(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.Hover> { throw ni(); } $provideHover(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.Hover> { throw ni(); }
$provideDocumentHighlights(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.DocumentHighlight[]> { throw ni(); } $provideDocumentHighlights(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.DocumentHighlight[]> { throw ni(); }
$provideReferences(handle: number, resource: URI, position: editorCommon.IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> { throw ni(); } $provideReferences(handle: number, resource: URI, position: editorCommon.IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> { throw ni(); }
@@ -46,6 +46,14 @@ export class ExtHostApiCommands {
], ],
returns: 'A promise that resolves to an array of Location-instances.' returns: 'A promise that resolves to an array of Location-instances.'
}); });
this._register('vscode.executeTypeDefinitionProvider', this._executeTypeDefinitionProvider, {
description: 'Execute all implementation providers.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'position', description: 'Position of a symbol', constraint: types.Position }
],
returns: 'A promise that resolves to an array of Location-instance.'
});
this._register('vscode.executeHoverProvider', this._executeHoverProvider, { this._register('vscode.executeHoverProvider', this._executeHoverProvider, {
description: 'Execute all hover provider.', description: 'Execute all hover provider.',
args: [ args: [
@@ -265,6 +273,18 @@ export class ExtHostApiCommands {
}); });
} }
private _executeTypeDefinitionProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
const args = {
resource,
position: position && typeConverters.fromPosition(position)
};
return this._commands.executeCommand<modes.Location[]>('_executeTypeDefinitionProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.location.to);
}
});
}
private _executeHoverProvider(resource: URI, position: types.Position): Thenable<types.Hover[]> { private _executeHoverProvider(resource: URI, position: types.Position): Thenable<types.Hover[]> {
const args = { const args = {
resource, resource,
@@ -122,6 +122,29 @@ class DefinitionAdapter {
} }
} }
class ImplementationAdapter {
private _documents: ExtHostDocuments;
private _provider: vscode.TypeDefinitionProvider;
constructor(documents: ExtHostDocuments, provider: vscode.TypeDefinitionProvider) {
this._documents = documents;
this._provider = provider;
}
provideTypeDefinition(resource: URI, position: IPosition): TPromise<modes.Definition> {
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideTypeDefinition(doc, pos, token)).then(value => {
if (Array.isArray(value)) {
return value.map(TypeConverters.location.from);
} else if (value) {
return TypeConverters.location.from(value);
}
});
}
}
class HoverAdapter { class HoverAdapter {
private _documents: ExtHostDocuments; private _documents: ExtHostDocuments;
@@ -614,7 +637,7 @@ class LinkProviderAdapter {
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | QuickFixAdapter | DocumentFormattingAdapter | DocumentHighlightAdapter | ReferenceAdapter | QuickFixAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter; | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter;
export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape { export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
@@ -713,6 +736,17 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(resource, position)); return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(resource, position));
} }
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new ImplementationAdapter(this._documents, provider));
this._proxy.$registerImplementationSupport(handle, selector);
return this._createDisposable(handle);
}
$provideTypeDefinition(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideTypeDefinition(resource, position));
}
// --- extra info // --- extra info
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
@@ -102,6 +102,15 @@ export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape
return undefined; return undefined;
} }
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, <modes.TypeDefinitionProvider>{
provideTypeDefinition: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position));
}
});
return undefined;
}
// --- extra info // --- extra info
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> { $registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
@@ -95,7 +95,8 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
); );
interface ISerializedUntitledEditorInput { interface ISerializedUntitledEditorInput {
resource: any | string; // TODO@Ben migration resource: string;
resourceJSON: any;
modeId: string; modeId: string;
} }
@@ -120,7 +121,11 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
resource = URI.file(resource.fsPath); // untitled with associated file path use the file schema resource = URI.file(resource.fsPath); // untitled with associated file path use the file schema
} }
const serialized: ISerializedUntitledEditorInput = { resource: resource.toJSON(), modeId: untitledEditorInput.getModeId() }; const serialized: ISerializedUntitledEditorInput = {
resource: resource.toString(), // Keep for backwards compatibility
resourceJSON: resource.toJSON(),
modeId: untitledEditorInput.getModeId()
};
return JSON.stringify(serialized); return JSON.stringify(serialized);
} }
@@ -128,7 +133,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput); const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput);
return this.untitledEditorService.createOrGet(typeof deserialized.resource === 'string' ? URI.parse(deserialized.resource) : URI.revive(deserialized.resource), deserialized.modeId); return this.untitledEditorService.createOrGet(!!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource), deserialized.modeId);
} }
} }
@@ -22,6 +22,7 @@ const $ = dom.$;
export class StartDebugActionItem extends EventEmitter implements IActionItem { export class StartDebugActionItem extends EventEmitter implements IActionItem {
private static ADD_CONFIGURATION = nls.localize('addConfiguration', "Add Configuration..."); private static ADD_CONFIGURATION = nls.localize('addConfiguration', "Add Configuration...");
private static SEPARATOR = '─────────';
public actionRunner: IActionRunner; public actionRunner: IActionRunner;
private container: HTMLElement; private container: HTMLElement;
@@ -132,8 +133,9 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem {
} else { } else {
this.setEnabled(true); this.setEnabled(true);
const selected = options.indexOf(this.debugService.getViewModel().selectedConfigurationName); const selected = options.indexOf(this.debugService.getViewModel().selectedConfigurationName);
options.push(StartDebugActionItem.SEPARATOR);
options.push(StartDebugActionItem.ADD_CONFIGURATION); options.push(StartDebugActionItem.ADD_CONFIGURATION);
this.selectBox.setOptions(options, selected); this.selectBox.setOptions(options, selected, options.length - 2);
} }
} }
} }
@@ -6,14 +6,13 @@
import * as lifecycle from 'vs/base/common/lifecycle'; import * as lifecycle from 'vs/base/common/lifecycle';
import uri from 'vs/base/common/uri'; import uri from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { guessMimeTypes } from 'vs/base/common/mime'; import { guessMimeTypes, MIME_TEXT } from 'vs/base/common/mime';
import { IModel } from 'vs/editor/common/editorCommon'; import { IModel } from 'vs/editor/common/editorCommon';
import { IModelService } from 'vs/editor/common/services/modelService'; import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService'; import { IModeService } from 'vs/editor/common/services/modeService';
import { ITextModelResolverService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; import { ITextModelResolverService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { DEBUG_SCHEME, IDebugService, State } from 'vs/workbench/parts/debug/common/debug'; import { DEBUG_SCHEME, IDebugService, State } from 'vs/workbench/parts/debug/common/debug';
import { Model } from 'vs/workbench/parts/debug/common/debugModel';
import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { Source } from 'vs/workbench/parts/debug/common/debugSource';
export class DebugContentProvider implements IWorkbenchContribution, ITextModelContentProvider { export class DebugContentProvider implements IWorkbenchContribution, ITextModelContentProvider {
@@ -52,9 +51,12 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC
this.modelsToDispose.push(model); this.modelsToDispose.push(model);
return model; return model;
}, err => { }, (err: DebugProtocol.ErrorResponse) => {
(<Model>this.debugService.getModel()).sourceIsUnavailable(resource); this.debugService.deemphasizeSource(resource);
return err; const modePromise = this.modeService.getOrCreateMode(MIME_TEXT);
const model = this.modelService.createModel(err.message, modePromise, resource);
return model;
}); });
} }
} }
@@ -476,6 +476,11 @@ export interface IDebugService {
*/ */
restartProcess(process: IProcess): TPromise<any>; restartProcess(process: IProcess): TPromise<any>;
/**
* Deemphasizes all sources with the passed uri. Source will appear as grayed out in callstack view.
*/
deemphasizeSource(uri: uri): void;
/** /**
* Gets the current debug model. * Gets the current debug model.
*/ */
@@ -381,7 +381,7 @@ export class Thread implements debug.IThread {
} }
public getId(): string { public getId(): string {
return `thread:${this.process.getId()}:${this.name}:${this.threadId}`; return `thread:${this.process.getId()}:${this.threadId}`;
} }
public clearCallStack(): void { public clearCallStack(): void {
@@ -506,6 +506,9 @@ export class Process implements debug.IProcess {
if (data.thread && !this.threads.has(data.threadId)) { if (data.thread && !this.threads.has(data.threadId)) {
// A new thread came in, initialize it. // A new thread came in, initialize it.
this.threads.set(data.threadId, new Thread(this, data.thread.name, data.thread.id)); this.threads.set(data.threadId, new Thread(this, data.thread.name, data.thread.id));
} else if (data.thread && data.thread.name) {
// Just the thread name got updated #18244
this.threads.get(data.threadId).name = data.thread.name;
} }
if (data.stoppedDetails) { if (data.stoppedDetails) {
@@ -556,7 +559,7 @@ export class Process implements debug.IProcess {
} }
} }
public sourceIsUnavailable(uri: uri): void { public deemphasizeSource(uri: uri): void {
this.threads.forEach(thread => { this.threads.forEach(thread => {
thread.getCallStack().forEach(stackFrame => { thread.getCallStack().forEach(stackFrame => {
if (stackFrame.source.uri.toString() === uri.toString()) { if (stackFrame.source.uri.toString() === uri.toString()) {
@@ -926,8 +929,8 @@ export class Model implements debug.IModel {
this._onDidChangeWatchExpressions.fire(); this._onDidChangeWatchExpressions.fire();
} }
public sourceIsUnavailable(uri: uri): void { public deemphasizeSource(uri: uri): void {
this.processes.forEach(p => p.sourceIsUnavailable(uri)); this.processes.forEach(p => p.deemphasizeSource(uri));
this._onDidChangeCallStack.fire(); this._onDidChangeCallStack.fire();
} }
@@ -213,7 +213,7 @@ export class DebugHoverWidget implements IContentWidget {
} }
// Find the most specific scope containing the range #16632 // Find the most specific scope containing the range #16632
return [scopes.filter(scope => Range.containsRange(scope.range, expressionRange)) return [scopes.filter(scope => scope.range && Range.containsRange(scope.range, expressionRange))
.sort((first, second) => (first.range.endLineNumber - first.range.startLineNumber) - (second.range.endLineNumber - second.range.startLineNumber)).shift()]; .sort((first, second) => (first.range.endLineNumber - first.range.startLineNumber) - (second.range.endLineNumber - second.range.startLineNumber)).shift()];
}) })
.then(scopes => TPromise.join(scopes.map(scope => this.doFindExpression(scope, namesToFind)))) .then(scopes => TPromise.join(scopes.map(scope => this.doFindExpression(scope, namesToFind))))
@@ -310,7 +310,7 @@ export class DebugService implements debug.IDebugService {
})); }));
this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidContinued(event => { this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidContinued(event => {
const threadId = event.body.allThreadsContinued ? undefined : event.body.threadId; const threadId = event.body.allThreadsContinued !== false ? undefined : event.body.threadId;
this.model.clearThreads(session.getId(), false, threadId); this.model.clearThreads(session.getId(), false, threadId);
if (this.viewModel.focusedProcess.getId() === session.getId()) { if (this.viewModel.focusedProcess.getId() === session.getId()) {
this.focusStackFrameAndEvaluate(null, this.viewModel.focusedProcess).done(null, errors.onUnexpectedError); this.focusStackFrameAndEvaluate(null, this.viewModel.focusedProcess).done(null, errors.onUnexpectedError);
@@ -779,7 +779,7 @@ export class DebugService implements debug.IDebugService {
this.lastTaskEvent = null; this.lastTaskEvent = null;
}); });
if (filteredTasks[0].isWatching) { if (filteredTasks[0].isBackground) {
return new TPromise((c, e) => this.taskService.addOneTimeDisposableListener(TaskServiceEvents.Inactive, () => c(null))); return new TPromise((c, e) => this.taskService.addOneTimeDisposableListener(TaskServiceEvents.Inactive, () => c(null)));
} }
@@ -801,6 +801,10 @@ export class DebugService implements debug.IDebugService {
}); });
} }
public deemphasizeSource(uri: uri): void {
this.model.deemphasizeSource(uri);
}
public restartProcess(process: debug.IProcess): TPromise<any> { public restartProcess(process: debug.IProcess): TPromise<any> {
if (!process) { if (!process) {
return this.createProcess(this.viewModel.selectedConfigurationName); return this.createProcess(this.viewModel.selectedConfigurationName);
@@ -49,6 +49,11 @@ export interface IRenderValueOptions {
showHover?: boolean; showHover?: boolean;
} }
function replaceWhitespace(value: string): string {
const map = { '\n': '\\n', '\r': '\\r', '\t': '\\t' };
return value.replace(/[\n\r\t]/g, char => map[char]);
}
export function renderExpressionValue(expressionOrValue: debug.IExpression | string, container: HTMLElement, options: IRenderValueOptions): void { export function renderExpressionValue(expressionOrValue: debug.IExpression | string, container: HTMLElement, options: IRenderValueOptions): void {
let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value; let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value;
@@ -77,8 +82,7 @@ export function renderExpressionValue(expressionOrValue: debug.IExpression | str
value = value.substr(0, options.maxValueLength) + '...'; value = value.substr(0, options.maxValueLength) + '...';
} }
if (value && !options.preserveWhitespace) { if (value && !options.preserveWhitespace) {
const map = { '\n': '\\n', '\r': '\\r', '\t': '\\t' }; container.textContent = replaceWhitespace(value);
container.textContent = value.replace(/[\n\r\t]/g, char => map[char]);
} else { } else {
container.textContent = value; container.textContent = value;
} }
@@ -89,7 +93,7 @@ export function renderExpressionValue(expressionOrValue: debug.IExpression | str
export function renderVariable(tree: ITree, variable: Variable, data: IVariableTemplateData, showChanged: boolean): void { export function renderVariable(tree: ITree, variable: Variable, data: IVariableTemplateData, showChanged: boolean): void {
if (variable.available) { if (variable.available) {
data.name.textContent = variable.name; data.name.textContent = replaceWhitespace(variable.name);
data.name.title = variable.type ? variable.type : ''; data.name.title = variable.type ? variable.type : '';
} }
@@ -556,6 +560,9 @@ export class CallStackRenderer implements IRenderer {
private renderStackFrame(stackFrame: debug.IStackFrame, data: IStackFrameTemplateData): void { private renderStackFrame(stackFrame: debug.IStackFrame, data: IStackFrameTemplateData): void {
stackFrame.source.deemphasize ? dom.addClass(data.stackFrame, 'disabled') : dom.removeClass(data.stackFrame, 'disabled'); stackFrame.source.deemphasize ? dom.addClass(data.stackFrame, 'disabled') : dom.removeClass(data.stackFrame, 'disabled');
data.file.title = stackFrame.source.raw.path || stackFrame.source.name; data.file.title = stackFrame.source.raw.path || stackFrame.source.name;
if (stackFrame.source.raw.origin) {
data.file.title += `\n${stackFrame.source.raw.origin}`;
}
data.label.textContent = stackFrame.name; data.label.textContent = stackFrame.name;
data.label.title = stackFrame.name; data.label.title = stackFrame.name;
data.fileName.textContent = getSourceName(stackFrame.source, this.contextService); data.fileName.textContent = getSourceName(stackFrame.source, this.contextService);
@@ -54,6 +54,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession {
public disconnected: boolean; public disconnected: boolean;
private sentPromises: TPromise<DebugProtocol.Response>[]; private sentPromises: TPromise<DebugProtocol.Response>[];
private capabilities: DebugProtocol.Capabilities; private capabilities: DebugProtocol.Capabilities;
private allThreadsContinued: boolean;
private _onDidInitialize: Emitter<DebugProtocol.InitializedEvent>; private _onDidInitialize: Emitter<DebugProtocol.InitializedEvent>;
private _onDidStop: Emitter<DebugProtocol.StoppedEvent>; private _onDidStop: Emitter<DebugProtocol.StoppedEvent>;
@@ -80,6 +81,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession {
super(id); super(id);
this.emittedStopped = false; this.emittedStopped = false;
this.readyForBreakpoints = false; this.readyForBreakpoints = false;
this.allThreadsContinued = false;
this.sentPromises = []; this.sentPromises = [];
this._onDidInitialize = new Emitter<DebugProtocol.InitializedEvent>(); this._onDidInitialize = new Emitter<DebugProtocol.InitializedEvent>();
@@ -202,6 +204,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession {
this.emittedStopped = true; this.emittedStopped = true;
this._onDidStop.fire(<DebugProtocol.StoppedEvent>event); this._onDidStop.fire(<DebugProtocol.StoppedEvent>event);
} else if (event.event === 'continued') { } else if (event.event === 'continued') {
this.allThreadsContinued = (<DebugProtocol.ContinuedEvent>event).body.allThreadsContinued = false ? false : true;
this._onDidContinued.fire(<DebugProtocol.ContinuedEvent>event); this._onDidContinued.fire(<DebugProtocol.ContinuedEvent>event);
} else if (event.event === 'thread') { } else if (event.event === 'thread') {
this._onDidThread.fire(<DebugProtocol.ThreadEvent>event); this._onDidThread.fire(<DebugProtocol.ThreadEvent>event);
@@ -270,7 +273,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession {
public continue(args: DebugProtocol.ContinueArguments): TPromise<DebugProtocol.ContinueResponse> { public continue(args: DebugProtocol.ContinueArguments): TPromise<DebugProtocol.ContinueResponse> {
return this.send('continue', args).then(response => { return this.send('continue', args).then(response => {
this.fireFakeContinued(args.threadId); this.fireFakeContinued(args.threadId, this.allThreadsContinued);
return response; return response;
}); });
} }
@@ -402,12 +405,13 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession {
} }
} }
private fireFakeContinued(threadId: number): void { private fireFakeContinued(threadId: number, allThreadsContinued = false): void {
this._onDidContinued.fire({ this._onDidContinued.fire({
type: 'event', type: 'event',
event: 'continued', event: 'continued',
body: { body: {
threadId threadId,
allThreadsContinued
}, },
seq: undefined seq: undefined
}); });
@@ -86,6 +86,8 @@ export class MockDebugService implements debug.IDebugService {
public getViewModel(): debug.IViewModel { public getViewModel(): debug.IViewModel {
return null; return null;
} }
public deemphasizeSource(uri: uri): void { }
} }
export class MockSession implements debug.ISession { export class MockSession implements debug.ISession {
@@ -105,7 +105,8 @@ const descriptor = new AsyncDescriptor<IFileEditorInput>('vs/workbench/parts/fil
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerDefaultFileInput(descriptor); Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerDefaultFileInput(descriptor);
interface ISerializedFileInput { interface ISerializedFileInput {
resource: any | string; // TODO@Ben migration resource: string;
resourceJSON: any;
encoding?: string; encoding?: string;
} }
@@ -131,9 +132,10 @@ class FileEditorInputFactory implements IEditorInputFactory {
public serialize(editorInput: EditorInput): string { public serialize(editorInput: EditorInput): string {
const fileEditorInput = <FileEditorInput>editorInput; const fileEditorInput = <FileEditorInput>editorInput;
const resource = fileEditorInput.getResource();
const fileInput: ISerializedFileInput = { const fileInput: ISerializedFileInput = {
resource: fileEditorInput.getResource().toJSON() resource: resource.toString(), // Keep for backwards compatibility
resourceJSON: resource.toJSON()
}; };
const encoding = fileEditorInput.getPreferredEncoding(); const encoding = fileEditorInput.getPreferredEncoding();
@@ -147,7 +149,7 @@ class FileEditorInputFactory implements IEditorInputFactory {
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput); const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput);
return instantiationService.createInstance(FileEditorInput, typeof fileInput.resource === 'string' ? URI.parse(fileInput.resource) : URI.revive(fileInput.resource), fileInput.encoding); return instantiationService.createInstance(FileEditorInput, !!fileInput.resourceJSON ? URI.revive(fileInput.resourceJSON) : URI.parse(fileInput.resource), fileInput.encoding);
} }
} }
@@ -105,7 +105,7 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
}, { }, {
indentPixels: 0, indentPixels: 0,
twistiePixels: 20, twistiePixels: 20,
ariaLabel: nls.localize({ key: 'treeAriaLabel', comment: ['Open is an adjective'] }, "Open Editors") ariaLabel: nls.localize({ key: 'treeAriaLabel', comment: ['Open is an adjective'] }, "Open Editors: List of Active Files")
}); });
this.fullRefreshNeeded = true; this.fullRefreshNeeded = true;
@@ -71,10 +71,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
} }
public setResource(resource: URI): void { public setResource(resource: URI): void {
if (resource.scheme !== 'file') {
throw new Error('FileEditorInput can only handle file:// resources.');
}
this.resource = resource; this.resource = resource;
// Reset resource dependent properties // Reset resource dependent properties
@@ -243,6 +243,7 @@ class OutputContentProvider implements ITextModelContentProvider {
} }
const bufferedOutput = this.bufferedOutput[channel]; const bufferedOutput = this.bufferedOutput[channel];
this.bufferedOutput[channel] = '';
if (!bufferedOutput) { if (!bufferedOutput) {
return; // return if nothing to append return; // return if nothing to append
} }
@@ -999,7 +999,7 @@ export class SearchViewlet extends Viewlet {
// Fake progress up to 90%, or when actual progress beats it // Fake progress up to 90%, or when actual progress beats it
const fakeMax = 900; const fakeMax = 900;
const fakeMultiplier = 15; const fakeMultiplier = 12;
if (fakeProgress && progressWorked < fakeMax) { if (fakeProgress && progressWorked < fakeMax) {
// Linearly decrease the rate of fake progress. // Linearly decrease the rate of fake progress.
// 1 is the smallest allowed amount of progress. // 1 is the smallest allowed amount of progress.
@@ -1,115 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise, Promise } from 'vs/base/common/winjs.base';
import { TerminateResponse } from 'vs/base/common/processes';
import { IMode } from 'vs/editor/common/modes';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { ITaskSystem, ITaskSummary, TaskDescription, TelemetryEvent, Triggers, TaskConfiguration, ITaskExecuteResult, TaskExecuteKind } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IModeService } from 'vs/editor/common/services/modeService';
export interface LanguageServiceTaskConfiguration extends TaskConfiguration {
modes: string[];
}
export class LanguageServiceTaskSystem extends EventEmitter implements ITaskSystem {
public static TelemetryEventName: string = 'taskService';
private configuration: LanguageServiceTaskConfiguration;
private telemetryService: ITelemetryService;
private modeService: IModeService;
constructor(configuration: LanguageServiceTaskConfiguration, telemetryService: ITelemetryService, modeService: IModeService) {
super();
this.configuration = configuration;
this.telemetryService = telemetryService;
this.modeService = modeService;
}
public build(): ITaskExecuteResult {
return this.processMode((mode) => {
return null;
}, 'build', Triggers.shortcut);
}
public rebuild(): ITaskExecuteResult {
return this.processMode((mode) => {
return null;
}, 'rebuild', Triggers.shortcut);
}
public clean(): ITaskExecuteResult {
return this.processMode((mode) => {
return null;
}, 'clean', Triggers.shortcut);
}
public runTest(): ITaskExecuteResult {
return { kind: TaskExecuteKind.Started, promise: TPromise.wrapError<ITaskSummary>('Not implemented yet.') };
}
public run(taskIdentifier: string): ITaskExecuteResult {
return { kind: TaskExecuteKind.Started, promise: TPromise.wrapError<ITaskSummary>('Not implemented yet.') };
}
public isActive(): TPromise<boolean> {
return TPromise.as(false);
}
public isActiveSync(): boolean {
return false;
}
public canAutoTerminate(): boolean {
return false;
}
public terminate(): TPromise<TerminateResponse> {
return TPromise.as({ success: true });
}
public terminateSync(): TerminateResponse {
return { success: true };
}
public tasks(): TPromise<TaskDescription[]> {
let result: TaskDescription[] = [];
return TPromise.as(result);
}
private processMode(fn: (mode: IMode) => Promise, taskName: string, trigger: string): ITaskExecuteResult {
let telemetryEvent: TelemetryEvent = {
trigger: trigger,
command: 'languageService',
success: true
};
return {
kind: TaskExecuteKind.Started, started: {}, promise: Promise.join(this.configuration.modes.map((mode) => {
return this.modeService.getOrCreateMode(mode);
})).then((modes: IMode[]) => {
let promises: Promise[] = [];
modes.forEach((mode) => {
let promise = fn(mode);
if (promise) {
promises.push(promise);
}
});
return Promise.join(promises);
}).then((value) => {
this.telemetryService.publicLog(LanguageServiceTaskSystem.TelemetryEventName, telemetryEvent);
return value;
}, (err) => {
telemetryEvent.success = false;
this.telemetryService.publicLog(LanguageServiceTaskSystem.TelemetryEventName, telemetryEvent);
return Promise.wrapError(err);
})
};
}
}
@@ -98,9 +98,9 @@ export interface TaskDescription {
args?: string[]; args?: string[];
/** /**
* Whether the task is running in watching mode or not. * Whether the task is a background task or not.
*/ */
isWatching?: boolean; isBackground?: boolean;
/** /**
* Whether the task should prompt on close for confirmation if running. * Whether the task should prompt on close for confirmation if running.
@@ -201,7 +201,7 @@ export interface ITaskExecuteResult {
}; };
active?: { active?: {
same: boolean; same: boolean;
watching: boolean; background: boolean;
}; };
} }
@@ -242,5 +242,5 @@ export interface TaskConfiguration {
/** /**
* The build system to use. If omitted program is used. * The build system to use. If omitted program is used.
*/ */
buildSystem?: string; _runner?: string;
} }
@@ -59,13 +59,15 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output'; import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output';
import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal';
import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskConfiguration, TaskDescription, TaskSystemEvents } from 'vs/workbench/parts/tasks/common/taskSystem'; import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskConfiguration, TaskDescription, TaskSystemEvents } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITaskService, TaskServiceEvents } from 'vs/workbench/parts/tasks/common/taskService'; import { ITaskService, TaskServiceEvents } from 'vs/workbench/parts/tasks/common/taskService';
import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates'; import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates';
import { LanguageServiceTaskSystem, LanguageServiceTaskConfiguration } from 'vs/workbench/parts/tasks/common/languageServiceTaskSystem';
import * as FileConfig from 'vs/workbench/parts/tasks/node/processRunnerConfiguration'; import * as FileConfig from 'vs/workbench/parts/tasks/node/processRunnerConfiguration';
import { ProcessRunnerSystem } from 'vs/workbench/parts/tasks/node/processRunnerSystem'; import { ProcessRunnerSystem } from 'vs/workbench/parts/tasks/node/processRunnerSystem';
import { TerminalTaskSystem } from './terminalTaskSystem';
import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunnerDetector'; import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunnerDetector';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -631,7 +633,9 @@ class TaskService extends EventEmitter implements ITaskService {
@IModelService modelService: IModelService, @IExtensionService extensionService: IExtensionService, @IModelService modelService: IModelService, @IExtensionService extensionService: IExtensionService,
@IQuickOpenService quickOpenService: IQuickOpenService, @IQuickOpenService quickOpenService: IQuickOpenService,
@IEnvironmentService private environmentService: IEnvironmentService, @IEnvironmentService private environmentService: IEnvironmentService,
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService) { @IConfigurationResolverService private configurationResolverService: IConfigurationResolverService,
@ITerminalService private terminalService: ITerminalService
) {
super(); super();
this.modeService = modeService; this.modeService = modeService;
@@ -740,10 +744,15 @@ class TaskService extends EventEmitter implements ITaskService {
throw new TaskError(Severity.Info, nls.localize('TaskSystem.noConfiguration', 'No task runner configured.'), TaskErrors.NotConfigured); throw new TaskError(Severity.Info, nls.localize('TaskSystem.noConfiguration', 'No task runner configured.'), TaskErrors.NotConfigured);
} }
let result: ITaskSystem = null; let result: ITaskSystem = null;
if (config.buildSystem === 'service') { if (this.isRunnerConfig(config)) {
result = new LanguageServiceTaskSystem(<LanguageServiceTaskConfiguration>config, this.telemetryService, this.modeService);
} else if (this.isRunnerConfig(config)) {
result = new ProcessRunnerSystem(<FileConfig.ExternalTaskRunnerConfiguration>config, this.markerService, this.modelService, this.telemetryService, this.outputService, this.configurationResolverService, TaskService.OutputChannelId, clearOutput); result = new ProcessRunnerSystem(<FileConfig.ExternalTaskRunnerConfiguration>config, this.markerService, this.modelService, this.telemetryService, this.outputService, this.configurationResolverService, TaskService.OutputChannelId, clearOutput);
} else if (this.isTerminalConfig(config)) {
result = new TerminalTaskSystem(
<FileConfig.ExternalTaskRunnerConfiguration>config,
this.terminalService, this.outputService, this.markerService,
this.modelService, this.configurationResolverService, this.telemetryService,
TaskService.OutputChannelId
);
} }
if (result === null) { if (result === null) {
this._taskSystemPromise = null; this._taskSystemPromise = null;
@@ -776,7 +785,11 @@ class TaskService extends EventEmitter implements ITaskService {
} }
private isRunnerConfig(config: TaskConfiguration): boolean { private isRunnerConfig(config: TaskConfiguration): boolean {
return !config.buildSystem || config.buildSystem === 'program'; return !config._runner || config._runner === 'program';
}
private isTerminalConfig(config: TaskConfiguration): boolean {
return config._runner === 'terminal';
} }
private hasDetectorSupport(config: FileConfig.ExternalTaskRunnerConfiguration): boolean { private hasDetectorSupport(config: FileConfig.ExternalTaskRunnerConfiguration): boolean {
@@ -819,14 +832,14 @@ class TaskService extends EventEmitter implements ITaskService {
} }
private executeTarget(fn: (taskSystem: ITaskSystem) => ITaskExecuteResult): TPromise<ITaskSummary> { private executeTarget(fn: (taskSystem: ITaskSystem) => ITaskExecuteResult): TPromise<ITaskSummary> {
return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved
return this.configurationService.reloadConfiguration().then(() => { // make sure configuration is up to date return this.configurationService.reloadConfiguration().then(() => { // make sure configuration is up to date
return this.taskSystemPromise. return this.taskSystemPromise.
then((taskSystem) => { then((taskSystem) => {
let executeResult = fn(taskSystem); let executeResult = fn(taskSystem);
if (executeResult.kind === TaskExecuteKind.Active) { if (executeResult.kind === TaskExecuteKind.Active) {
let active = executeResult.active; let active = executeResult.active;
if (active.same && active.watching) { if (active.same && active.background) {
this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame', 'The task is already active and in watch mode. To terminate the task use `F1 > terminate task`')); this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame', 'The task is already active and in watch mode. To terminate the task use `F1 > terminate task`'));
} else { } else {
throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is an active running task right now. Terminate it first before executing another task.'), TaskErrors.RunningTask); throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is an active running task right now. Terminate it first before executing another task.'), TaskErrors.RunningTask);
@@ -0,0 +1,440 @@
/*---------------------------------------------------------------------------------------------
* 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 path = require('path');
import * as nls from 'vs/nls';
import * as Objects from 'vs/base/common/objects';
import { CharCode } from 'vs/base/common/charCode';
import * as Platform from 'vs/base/common/platform';
import * as Async from 'vs/base/common/async';
import { TPromise } from 'vs/base/common/winjs.base';
import { IStringDictionary } from 'vs/base/common/collections';
import Severity from 'vs/base/common/severity';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { TerminateResponse } from 'vs/base/common/processes';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { ValidationStatus } from 'vs/base/common/parsers';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ProblemMatcher } from 'vs/platform/markers/common/problemMatcher';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ITerminalService, ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal';
import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
import { IOutputService, IOutputChannel } from 'vs/workbench/parts/output/common/output';
import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEvents } from 'vs/workbench/parts/tasks/common/problemCollectors';
import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskRunnerConfiguration, TaskDescription, ShowOutput, TelemetryEvent, Triggers, TaskSystemEvents, TaskEvent, TaskType } from 'vs/workbench/parts/tasks/common/taskSystem';
import * as FileConfig from '../node/processRunnerConfiguration';
interface TerminalData {
terminal: ITerminalInstance;
promise: TPromise<ITaskSummary>;
}
class TerminalDecoder {
// See https://en.wikipedia.org/wiki/ANSI_escape_code & http://stackoverflow.com/questions/25189651/how-to-remove-ansi-control-chars-vt100-from-a-java-string &
// https://www.npmjs.com/package/strip-ansi
private static ANSI_CONTROL_SEQUENCE: RegExp = /\x1b[[()#;?]*(?:\d{1,4}(?:;\d{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
private remaining: string;
public write(data: string): string[] {
let result: string[] = [];
let value = this.remaining
? this.remaining + data.replace(TerminalDecoder.ANSI_CONTROL_SEQUENCE, '')
: data.replace(TerminalDecoder.ANSI_CONTROL_SEQUENCE, '');
if (value.length < 1) {
return result;
}
let start = 0;
let ch: number;
while (start < value.length && ((ch = value.charCodeAt(start)) === CharCode.CarriageReturn || ch === CharCode.LineFeed)) {
start++;
}
let idx = start;
while (idx < value.length) {
ch = value.charCodeAt(idx);
if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) {
result.push(value.substring(start, idx));
idx++;
while (idx < value.length && ((ch = value.charCodeAt(idx)) === CharCode.CarriageReturn || ch === CharCode.LineFeed)) {
idx++;
}
start = idx;
} else {
idx++;
}
}
this.remaining = start < value.length ? value.substr(start) : null;
return result;
}
public end(): string {
return this.remaining;
}
}
export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
public static TelemetryEventName: string = 'taskService';
private validationStatus: ValidationStatus;
private buildTaskIdentifier: string;
private testTaskIdentifier: string;
private configuration: TaskRunnerConfiguration;
private outputChannel: IOutputChannel;
private activeTasks: IStringDictionary<TerminalData>;
constructor(private fileConfig: FileConfig.ExternalTaskRunnerConfiguration, private terminalService: ITerminalService, private outputService: IOutputService,
private markerService: IMarkerService, private modelService: IModelService, private configurationResolverService: IConfigurationResolverService,
private telemetryService: ITelemetryService, outputChannelId: string) {
super();
this.outputChannel = this.outputService.getChannel(outputChannelId);
this.clearOutput();
this.activeTasks = Object.create(null);
let parseResult = FileConfig.parse(fileConfig, this);
this.validationStatus = parseResult.validationStatus;
this.configuration = parseResult.configuration;
this.buildTaskIdentifier = parseResult.defaultBuildTaskIdentifier;
this.testTaskIdentifier = parseResult.defaultTestTaskIdentifier;
if (!this.validationStatus.isOK()) {
this.showOutput();
}
}
public log(value: string): void {
this.outputChannel.append(value + '\n');
}
private showOutput(): void {
this.outputChannel.show(true);
}
private clearOutput(): void {
this.outputChannel.clear();
}
public build(): ITaskExecuteResult {
if (!this.buildTaskIdentifier) {
throw new TaskError(Severity.Info, nls.localize('TerminalTaskSystem.noBuildTask', 'No build task defined in tasks.json'), TaskErrors.NoBuildTask);
}
return this.run(this.buildTaskIdentifier, Triggers.shortcut);
}
public rebuild(): ITaskExecuteResult {
return null;
}
public clean(): ITaskExecuteResult {
return null;
}
public runTest(): ITaskExecuteResult {
return null;
}
public run(taskIdentifier: string, trigger: string = Triggers.command): ITaskExecuteResult {
let task = this.configuration.tasks[taskIdentifier];
if (!task) {
throw new TaskError(Severity.Info, nls.localize('TerminalTaskSystem.noTask', 'Task \'{0}\' not found', taskIdentifier), TaskErrors.TaskNotFound);
}
let telemetryEvent: TelemetryEvent = {
trigger: trigger,
command: 'other',
success: true
};
try {
let result = this.executeTask(task, telemetryEvent);
result.promise = result.promise.then((summary) => {
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
return summary;
}, (error) => {
telemetryEvent.success = false;
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
return TPromise.wrapError<ITaskSummary>(error);
});
return result;
} catch (error) {
telemetryEvent.success = false;
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
if (error instanceof TaskError) {
throw error;
} else if (error instanceof Error) {
this.log(error.message);
throw new TaskError(Severity.Error, error.message, TaskErrors.UnknownError);
} else {
this.log(error.toString());
throw new TaskError(Severity.Error, nls.localize('TerminalTaskSystem.unknownError', 'A unknown error has occurred while executing a task. See task output log for details.'), TaskErrors.UnknownError);
}
}
}
public isActive(): TPromise<boolean> {
return TPromise.as(false);
}
public isActiveSync(): boolean {
return false;
}
public canAutoTerminate(): boolean {
return false;
}
public terminate(): TPromise<TerminateResponse> {
return null;
}
public tasks(): TPromise<TaskDescription[]> {
let result: TaskDescription[];
if (!this.configuration || !this.configuration.tasks) {
result = [];
} else {
result = Object.keys(this.configuration.tasks).map(key => this.configuration.tasks[key]);
}
return TPromise.as(result);
}
private executeTask(task: TaskDescription, telemetryEvent: TelemetryEvent): ITaskExecuteResult {
let terminalData = this.activeTasks[task.id];
if (terminalData && terminalData.promise) {
if (task.showOutput === ShowOutput.Always) {
terminalData.terminal.setVisible(true);
}
return { kind: TaskExecuteKind.Active, active: { same: true, background: task.isBackground }, promise: terminalData.promise };
} else {
let terminal: ITerminalInstance = undefined;
let promise: TPromise<ITaskSummary> = undefined;
if (task.isBackground) {
promise = new TPromise<ITaskSummary>((resolve, reject) => {
let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
let toUnbind: IDisposable[] = [];
let event: TaskEvent = { taskId: task.id, taskName: task.name, type: TaskType.Watching };
let eventCounter: number = 0;
toUnbind.push(watchingProblemMatcher.addListener2(ProblemCollectorEvents.WatchingBeginDetected, () => {
eventCounter++;
this.emit(TaskSystemEvents.Active, event);
}));
toUnbind.push(watchingProblemMatcher.addListener2(ProblemCollectorEvents.WatchingEndDetected, () => {
eventCounter--;
this.emit(TaskSystemEvents.Inactive, event);
}));
watchingProblemMatcher.aboutToStart();
let delayer: Async.Delayer<any> = null;
let decoder = new TerminalDecoder();
terminal = this.createTerminal(task);
terminal.onData((data: string) => {
decoder.write(data).forEach(line => {
watchingProblemMatcher.processLine(line);
if (delayer === null) {
delayer = new Async.Delayer(3000);
}
delayer.trigger(() => {
watchingProblemMatcher.forceDelivery();
delayer = null;
});
});
});
terminal.onExit((exitCode) => {
watchingProblemMatcher.dispose();
toUnbind = dispose(toUnbind);
toUnbind = null;
for (let i = 0; i < eventCounter; i++) {
this.emit(TaskSystemEvents.Inactive, event);
}
eventCounter = 0;
if (exitCode && exitCode === 1 && watchingProblemMatcher.numberOfMatches === 0 && task.showOutput !== ShowOutput.Never) {
this.terminalService.setActiveInstance(terminal);
this.terminalService.showPanel(false);
}
resolve({ exitCode });
});
});
} else {
promise = new TPromise<ITaskSummary>((resolve, reject) => {
terminal = this.createTerminal(task);
this.emit(TaskSystemEvents.Active, event);
let decoder = new TerminalDecoder();
let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
terminal.onData((data: string) => {
decoder.write(data).forEach((line) => {
startStopProblemMatcher.processLine(line);
});
});
terminal.onExit((exitCode) => {
startStopProblemMatcher.processLine(decoder.end());
startStopProblemMatcher.done();
startStopProblemMatcher.dispose();
this.emit(TaskSystemEvents.Inactive, event);
delete this.activeTasks[task.id];
resolve({ exitCode });
});
this.terminalService.setActiveInstance(terminal);
if (task.showOutput === ShowOutput.Always) {
this.terminalService.showPanel(false);
}
});
}
this.terminalService.setActiveInstance(terminal);
if (task.showOutput === ShowOutput.Always) {
this.terminalService.showPanel(false);
}
this.activeTasks[task.id] = { terminal, promise };
return { kind: TaskExecuteKind.Started, started: {}, promise: promise };
}
}
private createTerminal(task: TaskDescription): ITerminalInstance {
let { command, args } = this.resolveCommandAndArgs(task);
let terminalName = nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', task.name);
if (this.configuration.isShellCommand) {
let shellConfig = (this.terminalService.configHelper as TerminalConfigHelper).getShell();
let shellArgs = shellConfig.args.slice(0);
let toAdd: string[] = [];
let commandLine: string;
if (Platform.isWindows) {
toAdd.push('/d', '/c');
let quotedCommand: boolean = false;
let quotedArg: boolean = false;
let quoted = this.ensureDoubleQuotes(command);
let commandPieces: string[] = [];
commandPieces.push(quoted.value);
quotedCommand = quoted.quoted;
if (args) {
args.forEach((arg) => {
quoted = this.ensureDoubleQuotes(arg);
commandPieces.push(quoted.value);
quotedArg = quotedArg && quoted.quoted;
});
}
if (quotedCommand) {
if (quotedArg) {
commandLine = '"' + commandPieces.join(' ') + '"';
} else {
if (commandPieces.length > 1) {
commandLine = '"' + commandPieces[0] + '"' + ' ' + commandPieces.slice(1).join(' ');
} else {
commandLine = '"' + commandPieces[0] + '"';
}
}
} else {
commandLine = commandPieces.join(' ');
}
} else {
toAdd.push('-c');
commandLine = `${command} ${args.join(' ')}`;
}
toAdd.forEach(element => {
if (!shellArgs.some(arg => arg.toLowerCase() === element)) {
shellArgs.push(element);
}
});
shellArgs.push(commandLine);
return this.terminalService.createInstance(terminalName, shellConfig.executable, shellArgs, true);
} else {
return this.terminalService.createInstance(terminalName, command, args, true);
}
}
private resolveCommandAndArgs(task: TaskDescription): { command: string, args: string[] } {
let args: string[] = this.configuration.args ? this.configuration.args.slice() : [];
// We need to first pass the task name
if (!task.suppressTaskName) {
if (this.fileConfig.taskSelector) {
args.push(this.fileConfig.taskSelector + task.name);
} else {
args.push(task.name);
}
}
// And then additional arguments
if (task.args) {
args = args.concat(task.args);
}
args = this.resolveVariables(args);
let command: string = this.resolveVariable(this.configuration.command);
return { command, args };
}
private resolveVariables(value: string[]): string[] {
return value.map(s => this.resolveVariable(s));
}
private resolveMatchers<T extends ProblemMatcher>(values: T[]): T[] {
if (values.length === 0) {
return values;
}
let result: T[] = [];
values.forEach((matcher) => {
if (!matcher.filePrefix) {
result.push(matcher);
} else {
let copy = Objects.clone(matcher);
copy.filePrefix = this.resolveVariable(copy.filePrefix);
result.push(copy);
}
});
return result;
}
private resolveVariable(value: string): string {
return this.configurationResolverService.resolve(value);
}
private static doubleQuotes = /^[^"].* .*[^"]$/;
private ensureDoubleQuotes(value: string) {
if (TerminalTaskSystem.doubleQuotes.test(value)) {
return {
value: '"' + value + '"',
quoted: true
};
} else {
return {
value: value,
quoted: value.length > 0 && value[0] === '"' && value[value.length - 1] === '"'
};
}
}
private static WellKnowCommands: IStringDictionary<boolean> = {
'ant': true,
'cmake': true,
'eslint': true,
'gradle': true,
'grunt': true,
'gulp': true,
'jake': true,
'jenkins': true,
'jshint': true,
'make': true,
'maven': true,
'msbuild': true,
'msc': true,
'nmake': true,
'npm': true,
'rake': true,
'tsc': true,
'xbuild': true
};
public getSanitizedCommand(cmd: string): string {
let result = cmd.toLowerCase();
let index = result.lastIndexOf(path.sep);
if (index !== -1) {
result = result.substring(index + 1);
}
if (TerminalTaskSystem.WellKnowCommands[result]) {
return result;
}
return 'other';
}
}
@@ -451,7 +451,7 @@ class ConfigurationParser {
name: globals.command, name: globals.command,
showOutput: globals.showOutput, showOutput: globals.showOutput,
suppressTaskName: true, suppressTaskName: true,
isWatching: isWatching, isBackground: isWatching,
promptOnClose: promptOnClose, promptOnClose: promptOnClose,
echoCommand: globals.echoCommand, echoCommand: globals.echoCommand,
}; };
@@ -539,15 +539,15 @@ class ConfigurationParser {
if (Types.isStringArray(externalTask.args)) { if (Types.isStringArray(externalTask.args)) {
task.args = externalTask.args.slice(); task.args = externalTask.args.slice();
} }
task.isWatching = false; task.isBackground = false;
if (!Types.isUndefined(externalTask.isWatching)) { if (!Types.isUndefined(externalTask.isWatching)) {
task.isWatching = !!externalTask.isWatching; task.isBackground = !!externalTask.isWatching;
} }
task.promptOnClose = true; task.promptOnClose = true;
if (!Types.isUndefined(externalTask.promptOnClose)) { if (!Types.isUndefined(externalTask.promptOnClose)) {
task.promptOnClose = !!externalTask.promptOnClose; task.promptOnClose = !!externalTask.promptOnClose;
} else { } else {
task.promptOnClose = !task.isWatching; task.promptOnClose = !task.isBackground;
} }
if (Types.isString(externalTask.showOutput)) { if (Types.isString(externalTask.showOutput)) {
task.showOutput = TaskSystem.ShowOutput.fromString(externalTask.showOutput); task.showOutput = TaskSystem.ShowOutput.fromString(externalTask.showOutput);
@@ -90,7 +90,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
public build(): ITaskExecuteResult { public build(): ITaskExecuteResult {
if (this.activeTaskIdentifier) { if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier]; let task = this.configuration.tasks[this.activeTaskIdentifier];
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultBuildTaskIdentifier, watching: task.isWatching }, promise: this.activeTaskPromise }; return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultBuildTaskIdentifier, background: task.isBackground }, promise: this.activeTaskPromise };
} }
if (!this.defaultBuildTaskIdentifier) { if (!this.defaultBuildTaskIdentifier) {
throw new TaskError(Severity.Info, nls.localize('TaskRunnerSystem.noBuildTask', 'No task is marked as a build task in the tasks.json. Mark a task with \'isBuildCommand\'.'), TaskErrors.NoBuildTask); throw new TaskError(Severity.Info, nls.localize('TaskRunnerSystem.noBuildTask', 'No task is marked as a build task in the tasks.json. Mark a task with \'isBuildCommand\'.'), TaskErrors.NoBuildTask);
@@ -109,7 +109,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
public runTest(): ITaskExecuteResult { public runTest(): ITaskExecuteResult {
if (this.activeTaskIdentifier) { if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier]; let task = this.configuration.tasks[this.activeTaskIdentifier];
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultTestTaskIdentifier, watching: task.isWatching }, promise: this.activeTaskPromise }; return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultTestTaskIdentifier, background: task.isBackground }, promise: this.activeTaskPromise };
} }
if (!this.defaultTestTaskIdentifier) { if (!this.defaultTestTaskIdentifier) {
throw new TaskError(Severity.Info, nls.localize('TaskRunnerSystem.noTestTask', 'No test task configured.'), TaskErrors.NoTestTask); throw new TaskError(Severity.Info, nls.localize('TaskRunnerSystem.noTestTask', 'No test task configured.'), TaskErrors.NoTestTask);
@@ -120,7 +120,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
public run(taskIdentifier: string): ITaskExecuteResult { public run(taskIdentifier: string): ITaskExecuteResult {
if (this.activeTaskIdentifier) { if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier]; let task = this.configuration.tasks[this.activeTaskIdentifier];
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === taskIdentifier, watching: task.isWatching }, promise: this.activeTaskPromise }; return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === taskIdentifier, background: task.isBackground }, promise: this.activeTaskPromise };
} }
return this.executeTask(taskIdentifier); return this.executeTask(taskIdentifier);
} }
@@ -239,7 +239,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
let prompt: string = Platform.isWindows ? '>' : '$'; let prompt: string = Platform.isWindows ? '>' : '$';
this.log(`running command${prompt} ${command} ${args.join(' ')}`); this.log(`running command${prompt} ${command} ${args.join(' ')}`);
} }
if (task.isWatching) { if (task.isBackground) {
let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService); let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
let toUnbind: IDisposable[] = []; let toUnbind: IDisposable[] = [];
let event: TaskEvent = { taskId: task.id, taskName: task.name, type: TaskType.Watching }; let event: TaskEvent = { taskId: task.id, taskName: task.name, type: TaskType.Watching };
@@ -73,7 +73,7 @@ class TaskBuilder {
showOutput: TaskSystem.ShowOutput.Always, showOutput: TaskSystem.ShowOutput.Always,
suppressTaskName: false, suppressTaskName: false,
echoCommand: false, echoCommand: false,
isWatching: false, isBackground: false,
promptOnClose: true, promptOnClose: true,
problemMatchers: [] problemMatchers: []
}; };
@@ -99,8 +99,8 @@ class TaskBuilder {
return this; return this;
} }
public isWatching(value: boolean): TaskBuilder { public isBackground(value: boolean): TaskBuilder {
this.result.isWatching = value; this.result.isBackground = value;
return this; return this;
} }
@@ -307,7 +307,7 @@ suite('Tasks Configuration parsing tests', () => {
let builder = new ConfiguationBuilder('tsc'); let builder = new ConfiguationBuilder('tsc');
builder.task('tsc'). builder.task('tsc').
suppressTaskName(true). suppressTaskName(true).
isWatching(true). isBackground(true).
promptOnClose(false); promptOnClose(false);
testGobalCommand( testGobalCommand(
{ {
@@ -627,7 +627,7 @@ suite('Tasks Configuration parsing tests', () => {
showOutput(TaskSystem.ShowOutput.Never). showOutput(TaskSystem.ShowOutput.Never).
echoCommand(true). echoCommand(true).
args(['--p']). args(['--p']).
isWatching(true). isBackground(true).
promptOnClose(false); promptOnClose(false);
let result = testConfiguration(external, builder); let result = testConfiguration(external, builder);
@@ -833,7 +833,7 @@ suite('Tasks Configuration parsing tests', () => {
] ]
}; };
let builder = new ConfiguationBuilder('tsc'); let builder = new ConfiguationBuilder('tsc');
builder.task('taskName').isWatching(true).promptOnClose(false); builder.task('taskName').isBackground(true).promptOnClose(false);
testConfiguration(external, builder); testConfiguration(external, builder);
}); });
@@ -943,7 +943,7 @@ suite('Tasks Configuration parsing tests', () => {
assert.strictEqual(actual.showOutput, expected.showOutput, 'showOutput'); assert.strictEqual(actual.showOutput, expected.showOutput, 'showOutput');
assert.strictEqual(actual.suppressTaskName, expected.suppressTaskName, 'suppressTaskName'); assert.strictEqual(actual.suppressTaskName, expected.suppressTaskName, 'suppressTaskName');
assert.strictEqual(actual.echoCommand, expected.echoCommand, 'echoCommand'); assert.strictEqual(actual.echoCommand, expected.echoCommand, 'echoCommand');
assert.strictEqual(actual.isWatching, expected.isWatching, 'isWatching'); assert.strictEqual(actual.isBackground, expected.isBackground, 'isBackground');
assert.strictEqual(actual.promptOnClose, expected.promptOnClose, 'promptOnClose'); assert.strictEqual(actual.promptOnClose, expected.promptOnClose, 'promptOnClose');
assert.strictEqual(typeof actual.problemMatchers, typeof expected.problemMatchers); assert.strictEqual(typeof actual.problemMatchers, typeof expected.problemMatchers);
if (actual.problemMatchers && expected.problemMatchers) { if (actual.problemMatchers && expected.problemMatchers) {
@@ -71,7 +71,8 @@ export class EditorState {
} }
interface ISerializedFileHistoryEntry { interface ISerializedFileHistoryEntry {
resource: any | string; // TODO@Ben migration resource?: string;
resourceJSON: any;
} }
export abstract class BaseHistoryService { export abstract class BaseHistoryService {
@@ -708,7 +709,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
return void 0; // only file resource inputs are serializable currently return void 0; // only file resource inputs are serializable currently
} }
return { resource: (input as IResourceInput).resource.toJSON() }; return { resourceJSON: (input as IResourceInput).resource.toJSON() };
}).filter(serialized => !!serialized); }).filter(serialized => !!serialized);
this.storageService.store(HistoryService.STORAGE_KEY, JSON.stringify(entries), StorageScope.WORKSPACE); this.storageService.store(HistoryService.STORAGE_KEY, JSON.stringify(entries), StorageScope.WORKSPACE);
@@ -724,8 +725,8 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
this.history = entries.map(entry => { this.history = entries.map(entry => {
const serializedFileInput = entry as ISerializedFileHistoryEntry; const serializedFileInput = entry as ISerializedFileHistoryEntry;
if (serializedFileInput.resource) { if (serializedFileInput.resource || serializedFileInput.resourceJSON) {
return { resource: typeof serializedFileInput.resource === 'string' ? URI.parse(serializedFileInput.resource) : URI.revive(serializedFileInput.resource) } as IResourceInput; return { resource: !!serializedFileInput.resourceJSON ? URI.revive(serializedFileInput.resourceJSON) : URI.parse(serializedFileInput.resource) } as IResourceInput;
} }
return void 0; return void 0;
@@ -48,4 +48,5 @@ export interface IThemeSetting {
export interface IThemeSettingStyle { export interface IThemeSettingStyle {
foreground?: string; foreground?: string;
background?: string;
} }
@@ -170,7 +170,24 @@ export class ThemeService implements IThemeService {
@ITelemetryService private telemetryService: ITelemetryService) { @ITelemetryService private telemetryService: ITelemetryService) {
this.knownColorThemes = []; this.knownColorThemes = [];
this.currentColorThemeDocument = null;
// In order to avoid paint flashing for tokens, because
// themes are loaded asynchronously, we need to initialize
// a color theme document with good defaults until the theme is loaded
let isLightTheme = (Array.prototype.indexOf.call(document.body.classList, 'vs') >= 0);
let foreground = isLightTheme ? '#000000' : '#D4D4D4';
let background = isLightTheme ? '#ffffff' : '#1E1E1E';
this.currentColorThemeDocument = {
name: null,
include: null,
settings: [{
settings: {
foreground: foreground,
background: background
}
}]
};
this.onColorThemeChange = new Emitter<string>(); this.onColorThemeChange = new Emitter<string>();
this.knownIconThemes = []; this.knownIconThemes = [];
this.currentIconTheme = ''; this.currentIconTheme = '';
@@ -151,7 +151,7 @@ suite('Editor - Range decorations', () => {
} }
function mockEditorService(editorInput: IEditorInput); function mockEditorService(editorInput: IEditorInput);
function mockEditorService(resource: URI) function mockEditorService(resource: URI);
function mockEditorService(arg: any) { function mockEditorService(arg: any) {
let editorInput: IEditorInput = arg instanceof URI ? instantiationService.createInstance(FileEditorInput, arg, void 0) : arg; let editorInput: IEditorInput = arg instanceof URI ? instantiationService.createInstance(FileEditorInput, arg, void 0) : arg;
instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, 'getActiveEditorInput', editorInput); instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, 'getActiveEditorInput', editorInput);
@@ -27,7 +27,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/common/quickOpen'; import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/common/quickOpen';
import { DocumentSymbolProviderRegistry, DocumentHighlightKind } from 'vs/editor/common/modes'; import { DocumentSymbolProviderRegistry, DocumentHighlightKind } from 'vs/editor/common/modes';
import { getCodeLensData } from 'vs/editor/contrib/codelens/common/codelens'; import { getCodeLensData } from 'vs/editor/contrib/codelens/common/codelens';
import { getDeclarationsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; import { getDeclarationsAtPosition, getTypeDefinitionAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
import { getHover } from 'vs/editor/contrib/hover/common/hover'; import { getHover } from 'vs/editor/contrib/hover/common/hover';
import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
import { provideReferences } from 'vs/editor/contrib/referenceSearch/common/referenceSearch'; import { provideReferences } from 'vs/editor/contrib/referenceSearch/common/referenceSearch';
@@ -351,6 +351,26 @@ suite('ExtHostLanguageFeatures', function () {
}); });
}); });
// --- type definition
test('TypeDefinition, data conversion', function () {
disposables.push(extHost.registerTypeDefinitionProvider(defaultSelector, <vscode.TypeDefinitionProvider>{
provideTypeDefinition(): any {
return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];
}
}));
return threadService.sync().then(() => {
return getTypeDefinitionAtPosition(model, new EditorPosition(1, 1)).then(value => {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });
assert.equal(entry.uri.toString(), model.uri.toString());
});
});
});
// --- extra info // --- extra info
test('HoverProvider, word range at pos', function () { test('HoverProvider, word range at pos', function () {