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

This commit is contained in:
Alex Dima 2017-01-05 12:31:43 +01:00
commit ebc43b3e8b
200 changed files with 4313 additions and 2328 deletions

View file

@ -40,7 +40,7 @@ const nodeModules = ['electron', 'original-fs']
const builtInExtensions = [
{ name: 'ms-vscode.node-debug', version: '1.9.0' },
{ name: 'ms-vscode.node-debug2', version: '1.9.0' }
{ name: 'ms-vscode.node-debug2', version: '1.9.1' }
];
const vscodeEntryPoints = _.flatten([
@ -110,7 +110,7 @@ const config = {
version: packageJson.electronVersion,
productAppName: product.nameLong,
companyName: 'Microsoft Corporation',
copyright: 'Copyright (C) 2016 Microsoft. All rights reserved',
copyright: 'Copyright (C) 2017 Microsoft. All rights reserved',
darwinIcon: 'resources/darwin/code.icns',
darwinBundleIdentifier: product.darwinBundleIdentifier,
darwinApplicationCategoryType: 'public.app-category.developer-tools',

View file

@ -318,9 +318,6 @@
{
"include": "#preprocessor-rule-other-block"
},
{
"include": "#sizeof"
},
{
"include": "#access"
},
@ -458,7 +455,7 @@
"line_continuation_character": {
"patterns": [
{
"match": "(\\\\)\\s*\\n",
"match": "(\\\\)\\n",
"captures": {
"1": {
"name": "constant.character.escape.line-continuation.c"
@ -891,6 +888,15 @@
}
},
"patterns": [
{
"include": "#access"
},
{
"include": "#libc"
},
{
"include": "#c_function_call"
},
{
"include": "$self"
}
@ -976,5 +982,5 @@
]
}
},
"version": "https://github.com/atom/language-c/commit/2a5fafe1d86f690b5ab2c877cea2fc6a598e001a"
"version": "https://github.com/atom/language-c/commit/0d0f32388e73fc91a86f4c31ff59c36191869d63"
}

View file

@ -141,6 +141,16 @@
"default": true,
"description": "%html.suggest.html5.desc%"
},
"html.validate.scripts": {
"type": "boolean",
"default": true,
"description": "%html.validate.scripts%"
},
"html.validate.styles": {
"type": "boolean",
"default": true,
"description": "%html.validate.styles%"
},
"html.trace.server": {
"type": "string",
"enum": [

View file

@ -10,5 +10,7 @@
"html.format.extraLiners.desc": "List of tags, comma separated, that should have an extra newline before them. 'null' defaults to \"head, body, /html\".",
"html.suggest.angular1.desc": "Configures if the built-in HTML language support suggests Angular V1 tags and properties.",
"html.suggest.ionic.desc": "Configures if the built-in HTML language support suggests Ionic tags, properties and values.",
"html.suggest.html5.desc":"Configures if the built-in HTML language support suggests HTML5 tags, properties and values."
"html.suggest.html5.desc":"Configures if the built-in HTML language support suggests HTML5 tags, properties and values.",
"html.validate.scripts": "Configures if the built-in HTML language support validates embedded scripts.",
"html.validate.styles": "Configures if the built-in HTML language support validates embedded styles."
}

View file

@ -6,9 +6,11 @@
import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType } from 'vscode-languageserver';
import { DocumentContext } from 'vscode-html-languageservice';
import { TextDocument, Diagnostic, DocumentLink, Range, TextEdit, SymbolInformation } from 'vscode-languageserver-types';
import { TextDocument, Diagnostic, DocumentLink, Range, SymbolInformation } from 'vscode-languageserver-types';
import { getLanguageModes, LanguageModes } from './modes/languageModes';
import { format } from './modes/formatting';
import * as url from 'url';
import * as path from 'path';
import uri from 'vscode-uri';
@ -69,9 +71,18 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
};
});
let validation = {
html: true,
css: true,
javascript: true
};
// The settings have changed. Is send on server activation as well.
connection.onDidChangeConfiguration((change) => {
settings = change.settings;
let validationSettings = settings && settings.html && settings.html.validate || {};
validation.css = validationSettings.styles !== false;
validation.javascript = validationSettings.scripts !== false;
languageModes.getAllModes().forEach(m => {
if (m.configure) {
@ -115,7 +126,7 @@ function triggerValidation(textDocument: TextDocument): void {
function validateTextDocument(textDocument: TextDocument): void {
let diagnostics: Diagnostic[] = [];
languageModes.getAllModesInDocument(textDocument).forEach(mode => {
if (mode.doValidation) {
if (mode.doValidation && validation[mode.getId()]) {
pushAll(diagnostics, mode.doValidation(textDocument));
}
});
@ -201,18 +212,11 @@ connection.onSignatureHelp(signatureHelpParms => {
connection.onDocumentRangeFormatting(formatParams => {
let document = documents.get(formatParams.textDocument.uri);
let ranges = languageModes.getModesInRange(document, formatParams.range);
let result: TextEdit[] = [];
let unformattedTags: string = settings && settings.html && settings.html.format && settings.html.format.unformatted || '';
let enabledModes = { css: !unformattedTags.match(/\bstyle\b/), javascript: !unformattedTags.match(/\bscript\b/), html: true };
ranges.forEach(r => {
let mode = r.mode;
if (mode && mode.format && enabledModes[mode.getId()] && !r.attributeValue) {
let edits = mode.format(document, r, formatParams.options);
pushAll(result, edits);
}
});
return result;
let enabledModes = { css: !unformattedTags.match(/\bstyle\b/), javascript: !unformattedTags.match(/\bscript\b/) };
return format(languageModes, document, formatParams.range, formatParams.options, enabledModes);
});
connection.onDocumentLinks(documentLinkParam => {

View file

@ -0,0 +1,55 @@
/*---------------------------------------------------------------------------------------------
* 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 { applyEdits } from '../utils/edits';
import { TextDocument, Range, TextEdit, FormattingOptions } from 'vscode-languageserver-types';
import { LanguageModes } from './languageModes';
export function format(languageModes: LanguageModes, document: TextDocument, formatRange: Range, formattingOptions: FormattingOptions, enabledModes: { [mode: string]: boolean }) {
// run the html formatter on the full range and pass the result content to the embedded formatters.
// from the final content create a single edit
// advantages of this approach are
// - correct indents in the html document
// - correct initial indent for embedded formatters
// - no worrying of overlapping edits
// perform a html format and apply changes to a new document
let htmlMode = languageModes.getMode('html');
let htmlEdits = htmlMode.format(document, formatRange, formattingOptions);
let htmlFormattedContent = applyEdits(document, htmlEdits);
let newDocument = TextDocument.create(document.uri + '.tmp', document.languageId, document.version, htmlFormattedContent);
try {
// run embedded formatters on html formatted content: - formatters see correct initial indent
let afterFormatRangeLength = document.getText().length - document.offsetAt(formatRange.end); // length of unchanged content after replace range
let newFormatRange = Range.create(formatRange.start, newDocument.positionAt(htmlFormattedContent.length - afterFormatRangeLength));
let embeddedRanges = languageModes.getModesInRange(newDocument, newFormatRange);
let embeddedEdits: TextEdit[] = [];
for (let r of embeddedRanges) {
let mode = r.mode;
if (mode && mode.format && enabledModes[mode.getId()] && !r.attributeValue) {
let edits = mode.format(newDocument, r, formattingOptions);
for (let edit of edits) {
embeddedEdits.push(edit);
}
}
};
if (embeddedEdits.length === 0) {
return htmlEdits;
}
// apply all embedded format edits and create a single edit for all changes
let resultContent = applyEdits(newDocument, embeddedEdits);
let resultReplaceText = resultContent.substring(document.offsetAt(formatRange.start), resultContent.length - afterFormatRangeLength);
return [TextEdit.replace(formatRange, resultReplaceText)];
} finally {
languageModes.onDocumentRemoved(newDocument);
}
}

View file

@ -20,7 +20,7 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService): LanguageM
settings = options && options.html;
},
doComplete(document: TextDocument, position: Position) {
let options = settings && settings.html && settings.html.suggest;
let options = settings && settings.suggest;
return htmlLanguageService.doComplete(document, position, htmlDocuments.get(document), options);
},
doHover(document: TextDocument, position: Position) {

View file

@ -8,6 +8,8 @@ import * as assert from 'assert';
import { getLanguageModes } from '../modes/languageModes';
import { TextDocument, Range, TextEdit, FormattingOptions } from 'vscode-languageserver-types';
import { format } from '../modes/formatting';
suite('HTML Embedded Formatting', () => {
function assertFormat(value: string, expected: string, options?: any): void {
@ -31,15 +33,8 @@ suite('HTML Embedded Formatting', () => {
let range = Range.create(document.positionAt(rangeStartOffset), document.positionAt(rangeEndOffset));
let formatOptions = FormattingOptions.create(2, true);
let ranges = languageModes.getModesInRange(document, range);
let result: TextEdit[] = [];
ranges.forEach(r => {
let mode = r.mode;
if (mode && mode.format) {
let edits = mode.format(document, r, formatOptions);
pushAll(result, edits);
}
});
let result = format(languageModes, document, range, formatOptions, { css: true, javascript: true });
let actual = applyEdits(document, result);
assert.equal(actual, expected);
}
@ -52,38 +47,38 @@ suite('HTML Embedded Formatting', () => {
test('HTML & Scripts', function (): any {
assertFormat('<html><head><script></script></head></html>', '<html>\n\n<head>\n <script></script>\n</head>\n\n</html>');
assertFormat('<html><head><script>var x=1;</script></head></html>', '<html>\n\n<head>\n <script>var x = 1;</script>\n</head>\n\n</html>');
assertFormat('<html><head><script>\nvar x=2;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 2;\n</script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=3;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 3;\n </script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=4;\nconsole.log("Hi");\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 4;\n console.log("Hi");\n </script>\n</head>\n\n</html>');
assertFormat('<html><head><script>var x=1;</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n </script>\n</head>\n\n</html>');
assertFormat('<html><head><script>\nvar x=2;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 2;\n\n </script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=3;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 3;\n\n </script>\n</head>\n\n</html>');
assertFormat('<html><head>\n <script>\nvar x=4;\nconsole.log("Hi");\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 4;\n console.log("Hi");\n\n </script>\n</head>\n\n</html>');
assertFormat('<html><head>\n |<script>\nvar x=5;\n</script>|</head></html>', '<html><head>\n <script>\n var x = 5;\n </script></head></html>');
assertFormat('<html><head>\n |<script>\nvar x=5;\n</script>|</head></html>', '<html><head>\n <script>\n var x = 5;\n\n </script></head></html>');
assertFormat('<html><head>\n <script>\n|var x=6;|\n</script></head></html>', '<html><head>\n <script>\n var x = 6;\n</script></head></html>');
});
test('Script end tag', function (): any {
assertFormat('<html>\n<head>\n <script>\nvar x = 0;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 0;\n </script>\n</head>\n\n</html>');
assertFormat('<html>\n<head>\n <script>\nvar x = 0;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 0;\n\n </script>\n</head>\n\n</html>');
});
test('HTML & Multiple Scripts', function (): any {
assertFormat('<html><head>\n<script>\nif(x){\nbar(); }\n</script><script>\nfunction(x){}\n</script></head></html>', '<html>\n\n<head>\n <script>\n if (x) {\n bar();\n }\n</script>\n<script>\n function(x) { }\n</script>\n</head>\n\n</html>');
assertFormat('<html><head>\n<script>\nif(x){\nbar(); }\n</script><script>\nfunction(x){}\n</script></head></html>', '<html>\n\n<head>\n <script>\n if (x) {\n bar();\n }\n\n </script>\n <script>\n function(x) { }\n\n </script>\n</head>\n\n</html>');
});
test('HTML & Styles', function (): any {
assertFormat('<html><head>\n<style>\n.foo{display:none;}\n</style></head></html>', '<html>\n\n<head>\n <style>\n.foo{display:none;}\n</style>\n</head>\n\n</html>');
assertFormat('<html><head>\n<style>\n.foo{display:none;}\n</style></head></html>', '<html>\n\n<head>\n <style>\n .foo {\n display: none;\n }\n </style>\n</head>\n\n</html>');
});
test('EndWithNewline', function (): any {
let options = {
html: {
format: {
endWithNewline : true
endWithNewline: true
}
}
};
assertFormat('<html><body><p>Hello</p></body></html>', '<html>\n\n<body>\n <p>Hello</p>\n</body>\n\n</html>\n', options);
assertFormat('<html>|<body><p>Hello</p></body>|</html>', '<html><body>\n <p>Hello</p>\n</body></html>', options);
assertFormat('<html><head><script>\nvar x=1;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n</script>\n</head>\n\n</html>\n', options);
assertFormat('<html><head><script>\nvar x=1;\n</script></head></html>', '<html>\n\n<head>\n <script>\n var x = 1;\n\n </script>\n</head>\n\n</html>\n', options);
});
});

View file

@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* 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, TextEdit, Position } from 'vscode-languageserver-types';
export function applyEdits(document: TextDocument, edits: TextEdit[]): string {
let text = document.getText();
let sortedEdits = edits.sort((a, b) => {
let startDiff = comparePositions(a.range.start, b.range.start);
if (startDiff === 0) {
return comparePositions(a.range.end, b.range.end);
}
return startDiff;
});
let lastOffset = text.length;
sortedEdits.forEach(e => {
let startOffset = document.offsetAt(e.range.start);
let endOffset = document.offsetAt(e.range.end);
text = text.substring(0, startOffset) + e.newText + text.substring(endOffset, text.length);
lastOffset = startOffset;
});
return text;
}
function comparePositions(p1: Position, p2: Position) {
let diff = p2.line - p1.line;
if (diff === 0) {
return p2.character - p1.character;
}
return diff;
}

View file

@ -67,7 +67,7 @@ export class PackageJSONContribution implements IJSONContribution {
let name = keys[0];
let insertText = new SnippetString().appendText(JSON.stringify(name));
if (addValue) {
insertText.appendText(': ').appendPlaceholder('*');
insertText.appendText(': "').appendPlaceholder('').appendText('"');
if (!isLast) {
insertText.appendText(',');
}
@ -99,7 +99,7 @@ export class PackageJSONContribution implements IJSONContribution {
this.mostDependedOn.forEach((name) => {
let insertText = new SnippetString().appendText(JSON.stringify(name));
if (addValue) {
insertText.appendText(': ').appendPlaceholder('*');
insertText.appendText(': "').appendPlaceholder('').appendText('"');
if (!isLast) {
insertText.appendText(',');
}

File diff suppressed because it is too large Load diff

View file

@ -1584,8 +1584,19 @@
}
},
{
"c": "````application/json",
"t": "text.html.markdown meta.paragraph.markdown",
"c": "````",
"t": "text.html.markdown markup.fenced_code.block.markdown punctuation.definition.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "application/json",
"t": "text.html.markdown markup.fenced_code.block.markdown fenced_code.block.language",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1596,7 +1607,7 @@
},
{
"c": " { value: [\"or with a mime type\"] }",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1607,7 +1618,7 @@
},
{
"c": "````",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown punctuation.definition.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1838,7 +1849,7 @@
},
{
"c": "~~~",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown punctuation.definition.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1849,7 +1860,7 @@
},
{
"c": "// Markdown extra adds un-indented code blocks too",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1859,74 +1870,8 @@
}
},
{
"c": "if (this",
"t": "text.html.markdown meta.paragraph.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "_",
"t": "text.html.markdown meta.paragraph.markdown markup.italic.markdown punctuation.definition.italic.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "is",
"t": "text.html.markdown meta.paragraph.markdown markup.italic.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "_",
"t": "text.html.markdown meta.paragraph.markdown markup.italic.markdown punctuation.definition.italic.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "more_code == true ",
"t": "text.html.markdown meta.paragraph.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "&&",
"t": "text.html.markdown meta.paragraph.markdown meta.other.valid-ampersand.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": " !indented) {",
"t": "text.html.markdown meta.paragraph.markdown",
"c": "if (this_is_more_code == true && !indented) {",
"t": "text.html.markdown markup.fenced_code.block.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1937,7 +1882,7 @@
},
{
"c": " // tild wrapped code blocks, also not indented",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1948,7 +1893,7 @@
},
{
"c": "}",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
@ -1959,7 +1904,7 @@
},
{
"c": "~~~",
"t": "text.html.markdown meta.paragraph.markdown",
"t": "text.html.markdown markup.fenced_code.block.markdown punctuation.definition.markdown",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",

View file

@ -220,7 +220,6 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
// Don't complete function calls inside of destructive assigments or imports
return this.client.execute('quickinfo', args).then(infoResponse => {
const info = infoResponse.body;
console.log(info && info.kind);
switch (info && info.kind) {
case 'var':
case 'let':

View file

@ -2,7 +2,7 @@
"name": "code-oss-dev",
"version": "1.9.0",
"electronVersion": "1.4.6",
"distro": "2eecc8b68318fba1fc5b62930287914ac9225e8a",
"distro": "ef07477c3bbf2aa2f274b13093cbe0d96fa59fdd",
"author": {
"name": "Microsoft Corporation"
},
@ -116,4 +116,4 @@
"windows-mutex": "^0.2.0",
"fsevents": "0.3.8"
}
}
}

View file

@ -4,7 +4,6 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# If root, ensure that --user-data-dir is specified
ARGS=$@
if [ "$(id -u)" = "0" ]; then
while test $# -gt 0
do
@ -34,5 +33,5 @@ fi
ELECTRON="$VSCODE_PATH/@@NAME@@"
CLI="$VSCODE_PATH/resources/app/out/cli.js"
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" $ARGS
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $?

View file

@ -692,7 +692,7 @@ export class Builder implements IDisposable {
}
};
return this.on(arg1, fn, listenerToUnbindContainer);
return this.on(arg1, fn, listenerToUnbindContainer, useCapture);
}
/**

View file

@ -114,14 +114,14 @@ export interface IDomEvent {
(element: EventHandler, type: string, useCapture?: boolean): _Event<any>;
}
export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?) => {
export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?: boolean) => {
const fn = e => emitter.fire(e);
const emitter = new Emitter<any>({
onFirstListenerAdd: () => {
element.addEventListener(type, fn);
element.addEventListener(type, fn, useCapture);
},
onLastListenerRemove: () => {
element.removeEventListener(type, fn);
element.removeEventListener(type, fn, useCapture);
}
});

View file

@ -91,7 +91,7 @@ function _renderHtml(content: IHTMLContentElement, options: RenderOptions = {}):
const renderer = new marked.Renderer();
renderer.image = (href: string, title: string, text: string) => {
let dimensions = [];
let dimensions: string[] = [];
if (href) {
const splitted = href.split('|').map(s => s.trim());
href = splitted[0];

View file

@ -7,7 +7,7 @@ import 'vs/css!./list';
import { IDisposable } from 'vs/base/common/lifecycle';
import { range } from 'vs/base/common/arrays';
import { IDelegate, IRenderer, IFocusChangeEvent, ISelectionChangeEvent } from './list';
import { List } from './listWidget';
import { List, IListOptions } from './listWidget';
import { IPagedModel } from 'vs/base/common/paging';
import Event, { mapEvent } from 'vs/base/common/event';
@ -67,10 +67,11 @@ export class PagedList<T> {
constructor(
container: HTMLElement,
delegate: IDelegate<number>,
renderers: IPagedRenderer<T, any>[]
renderers: IPagedRenderer<T, any>[],
options: IListOptions = {}
) {
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model));
this.list = new List(container, delegate, pagedRenderers);
this.list = new List(container, delegate, pagedRenderers, options);
}
get onFocusChange(): Event<IFocusChangeEvent<T>> {

View file

@ -240,7 +240,7 @@ export class ListView<T> implements IDisposable {
return DOM.addDisposableListener(domNode, type, handler, useCapture);
}
private fireScopedEvent(handler: (event: any) => void, index) {
private fireScopedEvent(handler: (event: any) => void, index: number) {
if (index < 0) {
return;
}

View file

@ -65,7 +65,7 @@ class Trait<T> implements IDisposable {
splice(start: number, deleteCount: number, insertCount: number): void {
const diff = insertCount - deleteCount;
const end = start + deleteCount;
const indexes = [];
const indexes: number[] = [];
for (let index of indexes) {
if (index >= start && index < end) {
@ -110,13 +110,13 @@ class Trait<T> implements IDisposable {
class FocusTrait<T> extends Trait<T> {
constructor(private getElementId: (number) => string) {
constructor(private getElementId: (number: number) => string) {
super('focused');
}
renderElement(element: T, index: number, container: HTMLElement): void {
super.renderElement(element, index, container);
container.setAttribute('role', 'option');
container.setAttribute('role', 'treeitem');
container.setAttribute('id', this.getElementId(index));
}
}
@ -201,6 +201,7 @@ class Controller<T> implements IDisposable {
}
export interface IListOptions extends IListViewOptions {
ariaLabel?: string;
}
const DefaultOptions: IListOptions = {};
@ -245,13 +246,17 @@ export class List<T> implements IDisposable {
});
this.view = new ListView(container, delegate, renderers, options);
this.view.domNode.setAttribute('role', 'listbox');
this.view.domNode.setAttribute('role', 'tree');
this.view.domNode.tabIndex = 0;
this.controller = new Controller(this, this.view);
this.disposables = [this.focus, this.selection, this.view, this.controller];
this._onDOMFocus = domEvent(this.view.domNode, 'focus');
this.onFocusChange(this._onFocusChange, this, this.disposables);
if (options.ariaLabel) {
this.view.domNode.setAttribute('aria-label', options.ariaLabel);
}
}
splice(start: number, deleteCount: number, ...elements: T[]): void {
@ -418,7 +423,16 @@ export class List<T> implements IDisposable {
}
private _onFocusChange(): void {
DOM.toggleClass(this.view.domNode, 'element-focused', this.focus.get().length > 0);
const focus = this.focus.get();
if (focus.length > 0) {
this.view.domNode.setAttribute('aria-activedescendant', this.getElementId(focus[0]));
} else {
this.view.domNode.removeAttribute('aria-activedescendant');
}
this.view.domNode.setAttribute('role', 'tree');
DOM.toggleClass(this.view.domNode, 'element-focused', focus.length > 0);
}
dispose(): void {

View file

@ -13,25 +13,12 @@ export function tail<T>(array: T[], n: number = 0): T {
return array[array.length - (1 + n)];
}
/**
* Iterates the provided array and allows to remove
* elements while iterating.
*/
export function forEach<T>(array: T[], callback: (element: T, remove: Function) => void): void {
for (var i = 0, len = array.length; i < len; i++) {
callback(array[i], function () {
array.splice(i, 1);
i--; len--;
});
}
}
export function equals<T>(one: T[], other: T[], itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
if (one.length !== other.length) {
return false;
}
for (var i = 0, len = one.length; i < len; i++) {
for (let i = 0, len = one.length; i < len; i++) {
if (!itemEquals(one[i], other[i])) {
return false;
}
@ -105,29 +92,6 @@ export function top<T>(array: T[], compare: (a: T, b: T) => number, n: number):
return result;
}
export function merge<T>(arrays: T[][], hashFn?: (element: T) => string): T[] {
const result = new Array<T>();
if (!hashFn) {
for (let i = 0, len = arrays.length; i < len; i++) {
result.push.apply(result, arrays[i]);
}
} else {
const map: { [k: string]: boolean } = {};
for (let i = 0; i < arrays.length; i++) {
for (let j = 0; j < arrays[i].length; j++) {
let element = arrays[i][j],
hash = hashFn(element);
if (!map.hasOwnProperty(hash)) {
map[hash] = true;
result.push(element);
}
}
}
}
return result;
}
/**
* @returns a new array with all undefined or null values removed. The original array is not modified at all.
*/
@ -139,24 +103,6 @@ export function coalesce<T>(array: T[]): T[] {
return array.filter(e => !!e);
}
/**
* @returns true if the given item is contained in the array.
*/
export function contains<T>(array: T[], item: T): boolean {
return array.indexOf(item) >= 0;
}
/**
* Swaps the elements in the array for the provided positions.
*/
export function swap(array: any[], pos1: number, pos2: number): void {
const element1 = array[pos1];
const element2 = array[pos2];
array[pos1] = element2;
array[pos2] = element1;
}
/**
* Moves the element in the array for the provided positions.
*/
@ -231,7 +177,7 @@ export function first<T>(array: T[], fn: (item: T) => boolean, notFoundValue: T
export function commonPrefixLength<T>(one: T[], other: T[], equals: (a: T, b: T) => boolean = (a, b) => a === b): number {
let result = 0;
for (var i = 0, len = Math.min(one.length, other.length); i < len && equals(one[i], other[i]); i++) {
for (let i = 0, len = Math.min(one.length, other.length); i < len && equals(one[i], other[i]); i++) {
result++;
}
@ -283,4 +229,4 @@ export function insert<T>(array: T[], element: T): () => void {
array.splice(index, 1);
}
};
}
}

View file

@ -71,8 +71,8 @@ export interface ITask<T> {
* The throttler implements this via the queue() method, by providing it a task
* factory. Following the example:
*
* var throttler = new Throttler();
* var letters = [];
* const throttler = new Throttler();
* const letters = [];
*
* function deliver() {
* const lettersToDeliver = letters;
@ -166,8 +166,8 @@ export class SimpleThrottler {
* to be executed and the waiting period (delay) must be passed in as arguments. Following
* the example:
*
* var delayer = new Delayer(WAITING_PERIOD);
* var letters = [];
* const delayer = new Delayer(WAITING_PERIOD);
* const letters = [];
*
* function letterReceived(l) {
* letters.push(l);
@ -402,7 +402,7 @@ export function sequence<T>(promiseFactories: ITask<TPromise<T>>[]): TPromise<T[
export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t: T) => boolean = t => !!t): TPromise<T> {
promiseFactories = [...promiseFactories.reverse()];
const loop = () => {
const loop: () => TPromise<T> = () => {
if (promiseFactories.length === 0) {
return TPromise.as(null);
}

View file

@ -65,12 +65,12 @@ function hsla2rgba(hsla: HSLA): RGBA {
let s = Math.min(hsla.s, 1);
let l = Math.min(hsla.l, 1);
let a = hsla.a === void 0 ? hsla.a : 1;
let r, g, b;
let r: number, g: number, b: number;
if (s === 0) {
r = g = b = l; // achromatic
} else {
let hue2rgb = function hue2rgb(p, q, t) {
let hue2rgb = function hue2rgb(p: number, q: number, t: number) {
if (t < 0) {
t += 1;
}
@ -115,7 +115,7 @@ export class Color {
* Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
*/
public getLuminosity(): number {
let luminosityFor = function (color): number {
let luminosityFor = function (color: number): number {
let c = color / 255;
return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);
};

View file

@ -83,8 +83,8 @@ export function compareByPrefix(one: string, other: string, lookFor: string): nu
}
export interface IScorableResourceAccessor<T> {
getLabel(T): string;
getResourcePath(T): string;
getLabel(t: T): string;
getResourcePath(t: T): string;
}
export function compareByScore<T>(elementA: T, elementB: T, accessor: IScorableResourceAccessor<T>, lookFor: string, lookForNormalizedLower: string, scorerCache?: { [key: string]: number }): number {

View file

@ -1,38 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import nls = require('vs/nls');
export function since(date: Date): string {
var seconds = (new Date().getTime() - date.getTime()) / 1000;
if (seconds < 60) {
return nls.localize('diff.seconds.verbose', "just now");
}
var minutes = seconds / 60;
if (minutes < 60) {
return Math.floor(minutes) === 1 ? nls.localize('diff.minute.verbose', "1 minute ago") : nls.localize('diff.minutes.verbose', "{0} minutes ago", Math.floor(minutes));
}
var hours = minutes / 60;
if (hours < 24) {
return Math.floor(hours) === 1 ? nls.localize('diff.hour.verbose', "1 hour ago") : nls.localize('diff.hours.verbose', "{0} hours ago", Math.floor(hours));
}
var days = hours / 24;
if (Math.floor(days) === 1) {
return nls.localize('diff.days.yesterday', "yesterday");
}
if (days > 6 && days < 8) {
return nls.localize('diff.days.week', "a week ago");
}
if (days > 30 && days < 40) {
return nls.localize('diff.days.month', "a month ago");
}
return nls.localize('diff.days.verbose', "{0} days ago", Math.floor(days));
}

View file

@ -23,7 +23,7 @@ export function memoize(target: any, key: string, descriptor: any) {
const memoizeKey = `$memoize$${key}`;
descriptor[fnKey] = function (...args) {
descriptor[fnKey] = function (...args: any[]) {
if (!this.hasOwnProperty(memoizeKey)) {
Object.defineProperty(this, memoizeKey, {
configurable: false,

View file

@ -19,7 +19,7 @@ globals.Monaco.Diagnostics = {};
var switches = globals.Monaco.Diagnostics;
var map = {};
var data = [];
var data: any[] = [];
function fifo(array: any[], size: number) {
while (array.length > size) {

View file

@ -148,8 +148,8 @@ export class LcsDiff2 {
// Construct the changes
let i = 0;
let j = 0;
let xChangeStart, yChangeStart;
let changes = [];
let xChangeStart: number, yChangeStart: number;
let changes: DiffChange[] = [];
while (i < xLength && j < yLength) {
if (this.resultX[i] && this.resultY[j]) {
// No change

View file

@ -218,7 +218,7 @@ export function once<T>(event: Event<T>): Event<T> {
}
export function any<T>(...events: Event<T>[]): Event<T> {
let listeners = [];
let listeners: IDisposable[] = [];
const emitter = new Emitter<T>({
onFirstListenerAdd() {
@ -297,7 +297,7 @@ export class EventBufferer {
}
bufferEvents(fn: () => void): void {
const buffer = [];
const buffer: Function[] = [];
this.buffers.push(buffer);
fn();
this.buffers.pop();
@ -334,7 +334,7 @@ class ChainableEvent<T> implements IChainableEvent<T> {
return new ChainableEvent(filterEvent(this._event, fn));
}
on(listener, thisArgs, disposables) {
on(listener, thisArgs, disposables: IDisposable[]) {
return this._event(listener, thisArgs, disposables);
}
}

View file

@ -209,7 +209,7 @@ function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis {
}
function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {
const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis;
const { upperPercent, lowerPercent } = analysis;
return lowerPercent === 0 && upperPercent > 0.6;
}
@ -272,10 +272,11 @@ export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[]
}
// Matches beginning of words supporting non-ASCII languages
// E.g. "gp" or "g p" will match "Git: Pull"
// If `contiguous` is true then matches word with beginnings of the words in the target. E.g. "pul" will match "Git: Pull"
// Otherwise also matches sub string of the word with beginnings of the words in the target. E.g. "gp" or "g p" will match "Git: Pull"
// Useful in cases where the target is words (e.g. command labels)
export function matchesWords(word: string, target: string): IMatch[] {
export function matchesWords(word: string, target: string, contiguous: boolean = false): IMatch[] {
if (!target || target.length === 0) {
return null;
}
@ -283,14 +284,14 @@ export function matchesWords(word: string, target: string): IMatch[] {
let result: IMatch[] = null;
let i = 0;
while (i < target.length && (result = _matchesWords(word.toLowerCase(), target, 0, i)) === null) {
while (i < target.length && (result = _matchesWords(word.toLowerCase(), target, 0, i, contiguous)) === null) {
i = nextWord(target, i + 1);
}
return result;
}
function _matchesWords(word: string, target: string, i: number, j: number): IMatch[] {
function _matchesWords(word: string, target: string, i: number, j: number, contiguous: boolean): IMatch[] {
if (i === word.length) {
return [];
} else if (j === target.length) {
@ -298,12 +299,14 @@ function _matchesWords(word: string, target: string, i: number, j: number): IMat
} else if (word[i] !== target[j].toLowerCase()) {
return null;
} else {
let result = null;
let result: IMatch[] = null;
let nextWordIndex = j + 1;
result = _matchesWords(word, target, i + 1, j + 1);
while (!result && (nextWordIndex = nextWord(target, nextWordIndex)) < target.length) {
result = _matchesWords(word, target, i + 1, nextWordIndex);
nextWordIndex++;
result = _matchesWords(word, target, i + 1, j + 1, contiguous);
if (!contiguous) {
while (!result && (nextWordIndex = nextWord(target, nextWordIndex)) < target.length) {
result = _matchesWords(word, target, i + 1, nextWordIndex, contiguous);
nextWordIndex++;
}
}
return result === null ? null : join({ start: j, end: j + 1 }, result);
}

View file

@ -42,7 +42,7 @@ export interface JSONScanner {
/**
* Sets the scan position to a new offset. A call to 'scan' is needed to get the first token.
*/
setPosition(pos: number);
setPosition(pos: number): void;
/**
* Read the next token. Returns the tolen code.
*/

View file

@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { isArray } from './types';
export const empty: IDisposable = Object.freeze({
dispose() { }
});
@ -14,17 +12,24 @@ export interface IDisposable {
dispose(): void;
}
export function dispose<T extends IDisposable>(...disposables: T[]): T;
export function dispose<T extends IDisposable>(disposable: T): T;
export function dispose<T extends IDisposable>(...disposables: T[]): T[];
export function dispose<T extends IDisposable>(disposables: T[]): T[];
export function dispose<T extends IDisposable>(...disposables: T[]): T[] {
const first = disposables[0];
export function dispose<T extends IDisposable>(first: T | T[], ...rest: T[]): T | T[] {
if (isArray(first)) {
disposables = first as any as T[];
if (Array.isArray(first)) {
first.forEach(d => d && d.dispose());
return [];
} else if (rest.length === 0) {
if (first) {
first.dispose();
return first;
}
} else {
dispose(first);
dispose(rest);
return [];
}
disposables.forEach(d => d && d.dispose());
return [];
}
export function combinedDisposable(disposables: IDisposable[]): IDisposable {
@ -105,4 +110,4 @@ export abstract class ReferenceCollection<T> {
export class ImmortalReference<T> implements IReference<T> {
constructor(public object: T) { }
dispose(): void { /* noop */ }
}
}

View file

@ -52,7 +52,7 @@ export class LinkedMap<K extends Key, T> {
}
public keys(): K[] {
var keys: K[] = [];
const keys: K[] = [];
for (let key in this.map) {
keys.push(this.map[key].key);
}
@ -60,7 +60,7 @@ export class LinkedMap<K extends Key, T> {
}
public values(): T[] {
var values: T[] = [];
const values: T[] = [];
for (let key in this.map) {
values.push(this.map[key].value);
}
@ -68,7 +68,7 @@ export class LinkedMap<K extends Key, T> {
}
public entries(): Entry<K, T>[] {
var entries: Entry<K, T>[] = [];
const entries: Entry<K, T>[] = [];
for (let key in this.map) {
entries.push(this.map[key]);
}
@ -310,7 +310,7 @@ class Node<E> {
*/
export class TrieMap<E> {
static PathSplitter = s => s.split(/[\\/]/).filter(s => !!s);
static PathSplitter = (s: string) => s.split(/[\\/]/).filter(s => !!s);
private _splitter: (s: string) => string[];
private _root = new Node<E>();

View file

@ -143,7 +143,7 @@ function guessMimeTypeByPath(path: string, filename: string, associations: IText
let patternMatch: ITextMimeAssociationItem;
let extensionMatch: ITextMimeAssociationItem;
for (var i = 0; i < associations.length; i++) {
for (let i = 0; i < associations.length; i++) {
let association = associations[i];
// First exact name match
@ -243,7 +243,7 @@ export function isUnspecific(mime: string[] | string): boolean {
}
export function suggestFilename(langId: string, prefix: string): string {
for (var i = 0; i < registeredAssociations.length; i++) {
for (let i = 0; i < registeredAssociations.length; i++) {
let association = registeredAssociations[i];
if (association.userConfigured) {
continue; // only support registered ones

View file

@ -12,23 +12,23 @@ export namespace Schemas {
* A schema that is used for models that exist in memory
* only and that have no correspondence on a server or such.
*/
export var inMemory: string = 'inmemory';
export const inMemory: string = 'inmemory';
/**
* A schema that is used for setting files
*/
export var vscode: string = 'vscode';
export const vscode: string = 'vscode';
/**
* A schema that is used for internal private files
*/
export var internal: string = 'private';
export const internal: string = 'private';
export var http: string = 'http';
export const http: string = 'http';
export var https: string = 'https';
export const https: string = 'https';
export var file: string = 'file';
export const file: string = 'file';
}
export interface IXHROptions {

View file

@ -11,12 +11,12 @@ import { CharCode } from 'vs/base/common/charCode';
/**
* The forward slash path separator.
*/
export var sep = '/';
export const sep = '/';
/**
* The native path separator depending on the OS.
*/
export var nativeSep = isWindows ? '\\' : '/';
export const nativeSep = isWindows ? '\\' : '/';
export function relative(from: string, to: string): string {
const originalNormalizedFrom = normalize(from);
@ -50,7 +50,7 @@ export function relative(from: string, to: string): string {
* @returns the directory name of a path.
*/
export function dirname(path: string): string {
var idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
if (idx === 0) {
return '.';
} else if (~idx === 0) {
@ -64,7 +64,7 @@ export function dirname(path: string): string {
* @returns the base name of a path.
*/
export function basename(path: string): string {
var idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
if (idx === 0) {
return path;
} else if (~idx === path.length - 1) {
@ -79,7 +79,7 @@ export function basename(path: string): string {
*/
export function extname(path: string): string {
path = basename(path);
var idx = ~path.lastIndexOf('.');
const idx = ~path.lastIndexOf('.');
return idx ? path.substring(~idx) : '';
}

View file

@ -13,8 +13,8 @@ let _isRootUser = false;
let _isNative = false;
let _isWeb = false;
let _isQunit = false;
let _locale = undefined;
let _language = undefined;
let _locale: string = undefined;
let _language: string = undefined;
interface NLSConfig {
locale: string;
@ -124,7 +124,7 @@ interface IGlobals {
clearTimeout(token: TimeoutToken): void;
setInterval(callback: (...args: any[]) => void, delay: number, ...args: any[]): IntervalToken;
clearInterval(token: IntervalToken);
clearInterval(token: IntervalToken): void;
}
const _globals = <IGlobals>(typeof self === 'object' ? self : global);

View file

@ -6,7 +6,7 @@
import { globals } from 'vs/base/common/platform';
var hasPerformanceNow = (globals.performance && typeof globals.performance.now === 'function');
const hasPerformanceNow = (globals.performance && typeof globals.performance.now === 'function');
export class StopWatch {

View file

@ -607,8 +607,8 @@ export function safeBtoa(str: string): string {
}
export function repeat(s: string, count: number): string {
var result = '';
for (var i = 0; i < count; i++) {
let result = '';
for (let i = 0; i < count; i++) {
result += s;
}
return result;

View file

@ -106,7 +106,7 @@ function read(zipPath: string, filePath: string): TPromise<Readable> {
export function buffer(zipPath: string, filePath: string): TPromise<Buffer> {
return read(zipPath, filePath).then(stream => {
return new TPromise<Buffer>((c, e) => {
const buffers = [];
const buffers: Buffer[] = [];
stream.once('error', e);
stream.on('data', b => buffers.push(b));
stream.on('end', () => c(Buffer.concat(buffers)));

View file

@ -689,15 +689,15 @@ export class QuickOpenModel implements
return this._entries;
}
getId(entry: QuickOpenEntry): string {
public getId(entry: QuickOpenEntry): string {
return entry.getId();
}
getLabel(entry: QuickOpenEntry): string {
public getLabel(entry: QuickOpenEntry): string {
return entry.getLabel();
}
getAriaLabel(entry: QuickOpenEntry): string {
public getAriaLabel(entry: QuickOpenEntry): string {
const ariaLabel = entry.getAriaLabel();
if (ariaLabel) {
return nls.localize('quickOpenAriaLabelEntry', "{0}, picker", entry.getAriaLabel());
@ -706,11 +706,11 @@ export class QuickOpenModel implements
return nls.localize('quickOpenAriaLabel', "picker");
}
isVisible(entry: QuickOpenEntry): boolean {
public isVisible(entry: QuickOpenEntry): boolean {
return !entry.isHidden();
}
run(entry: QuickOpenEntry, mode: Mode, context: IContext): boolean {
public run(entry: QuickOpenEntry, mode: Mode, context: IContext): boolean {
return entry.run(mode, context);
}
}

View file

@ -328,7 +328,7 @@ export interface ITree extends Events.IEventEmitter {
* Returns a navigator which allows to discover the visible and
* expanded elements in the tree.
*/
getNavigator(): INavigator<any>;
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any>;
/**
* Disposes the tree

View file

@ -318,8 +318,8 @@ export class Tree extends Events.EventEmitter implements _.ITree {
return this.model.hasTrait(trait, element);
}
getNavigator(): INavigator<any> {
return new MappedNavigator(this.model.getNavigator(), i => i && i.getElement());
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> {
return new MappedNavigator(this.model.getNavigator(fromElement, subTreeOnly), i => i && i.getElement());
}
public dispose(): void {

View file

@ -186,5 +186,8 @@ suite('Filters', () => {
filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 3 }, { start: 4, end: 7 }]);
filterOk(matchesWords, 'öäk', 'Öhm: Älles Klar', [{ start: 0, end: 1 }, { start: 5, end: 6 }, { start: 11, end: 12 }]);
assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null);
assert.deepEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]);
});
});

View file

@ -5,7 +5,7 @@
'use strict';
import { IWindowsMainService } from 'vs/code/electron-main/windows';
import { IWindowsMainService, OpenContext } from 'vs/code/electron-main/windows';
import { VSCodeWindow } from 'vs/code/electron-main/window';
import { TPromise } from 'vs/base/common/winjs.base';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
@ -82,6 +82,7 @@ export class LaunchService implements ILaunchService {
const openUrlArg = args['open-url'] || [];
const openUrl = typeof openUrlArg === 'string' ? [openUrlArg] : openUrlArg;
const context = !!userEnv['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.OTHER;
if (openUrl.length > 0) {
openUrl.forEach(url => this.urlService.open(url));
@ -91,17 +92,19 @@ export class LaunchService implements ILaunchService {
// Otherwise handle in windows service
let usedWindows: VSCodeWindow[];
if (!!args.extensionDevelopmentPath) {
this.windowsService.openExtensionDevelopmentHostWindow({ cli: args, userEnv });
this.windowsService.openExtensionDevelopmentHostWindow({ context, cli: args, userEnv });
} else if (args._.length === 0 && args['new-window']) {
usedWindows = this.windowsService.open({ cli: args, userEnv, forceNewWindow: true, forceEmpty: true });
usedWindows = this.windowsService.open({ context, cli: args, userEnv, forceNewWindow: true, forceEmpty: true });
} else if (args._.length === 0) {
usedWindows = [this.windowsService.focusLastActive(args)];
usedWindows = [this.windowsService.focusLastActive(args, context)];
} else {
usedWindows = this.windowsService.open({
context,
cli: args,
userEnv,
forceNewWindow: args.wait || args['new-window'],
preferNewWindow: !args['reuse-window'],
forceReuseWindow: args['reuse-window'],
diffMode: args.diff
});
}

View file

@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
import { parseMainProcessArgv } from 'vs/platform/environment/node/argv';
import { mkdirp } from 'vs/base/node/pfs';
import { validatePaths } from 'vs/code/electron-main/paths';
import { IWindowsMainService, WindowsManager } from 'vs/code/electron-main/windows';
import { IWindowsMainService, WindowsManager, OpenContext } from 'vs/code/electron-main/windows';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc';
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
@ -251,12 +251,13 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
windowsMainService.ready(userEnv);
// Open our first window
const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.OTHER;
if (environmentService.args['new-window'] && environmentService.args._.length === 0) {
windowsMainService.open({ cli: environmentService.args, forceNewWindow: true, forceEmpty: true, initialStartup: true }); // new window if "-n" was used without paths
windowsMainService.open({ context, cli: environmentService.args, forceNewWindow: true, forceEmpty: true, initialStartup: true }); // new window if "-n" was used without paths
} else if (global.macOpenFiles && global.macOpenFiles.length && (!environmentService.args._ || !environmentService.args._.length)) {
windowsMainService.open({ cli: environmentService.args, pathsToOpen: global.macOpenFiles, initialStartup: true }); // mac: open-file event received on startup
windowsMainService.open({ context: OpenContext.DOCK, cli: environmentService.args, pathsToOpen: global.macOpenFiles, initialStartup: true }); // mac: open-file event received on startup
} else {
windowsMainService.open({ cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff, initialStartup: true }); // default: read paths from cli
windowsMainService.open({ context, cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff, initialStartup: true }); // default: read paths from cli
}
// Install Menu

View file

@ -10,7 +10,7 @@ import * as platform from 'vs/base/common/platform';
import * as arrays from 'vs/base/common/arrays';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem } from 'electron';
import { IWindowsMainService } from 'vs/code/electron-main/windows';
import { IWindowsMainService, OpenContext } from 'vs/code/electron-main/windows';
import { VSCodeWindow } from 'vs/code/electron-main/window';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IStorageService } from 'vs/code/electron-main/storage';
@ -315,7 +315,7 @@ export class VSCodeMenu {
this.appMenuInstalled = true;
const dockMenu = new Menu();
dockMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")), click: () => this.windowsService.openNewWindow() }));
dockMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")), click: () => this.windowsService.openNewWindow(OpenContext.DOCK) }));
app.dock.setMenu(dockMenu);
}
@ -351,19 +351,19 @@ export class VSCodeMenu {
let newFile: Electron.MenuItem;
if (hasNoWindows) {
newFile = new MenuItem(this.likeAction('workbench.action.files.newUntitledFile', { label: mnemonicLabel(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File")), click: () => this.windowsService.openNewWindow() }));
newFile = new MenuItem(this.likeAction('workbench.action.files.newUntitledFile', { label: mnemonicLabel(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File")), click: () => this.windowsService.openNewWindow(OpenContext.MENU) }));
} else {
newFile = this.createMenuItem(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File"), 'workbench.action.files.newUntitledFile');
}
const open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: () => this.windowsService.openFileFolderPicker() }));
const openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: () => this.windowsService.openFolderPicker() }));
const open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: (menuItem, win, event) => this.windowsService.openFileFolderPicker(this.isOptionClick(event)) }));
const openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: (menuItem, win, event) => this.windowsService.openFolderPicker(this.isOptionClick(event)) }));
let openFile: Electron.MenuItem;
if (hasNoWindows) {
openFile = new MenuItem(this.likeAction('workbench.action.files.openFile', { label: mnemonicLabel(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...")), click: () => this.windowsService.openFilePicker() }));
openFile = new MenuItem(this.likeAction('workbench.action.files.openFile', { label: mnemonicLabel(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...")), click: (menuItem, win, event) => this.windowsService.openFilePicker(this.isOptionClick(event)) }));
} else {
openFile = this.createMenuItem(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File..."), 'workbench.action.files.openFile');
openFile = this.createMenuItem(nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File..."), ['workbench.action.files.openFile', 'workbench.action.files.openFileInNewWindow']);
}
const openRecentMenu = new Menu();
@ -379,7 +379,7 @@ export class VSCodeMenu {
const preferences = this.getPreferencesMenu();
const newWindow = new MenuItem(this.likeAction('workbench.action.newWindow', { label: mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")), click: () => this.windowsService.openNewWindow() }));
const newWindow = new MenuItem(this.likeAction('workbench.action.newWindow', { label: mnemonicLabel(nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")), click: () => this.windowsService.openNewWindow(OpenContext.MENU) }));
const revertFile = this.createMenuItem(nls.localize({ key: 'miRevert', comment: ['&& denotes a mnemonic'] }, "Re&&vert File"), 'workbench.action.files.revert', this.windowsService.getWindowCount() > 0);
const closeWindow = new MenuItem(this.likeAction('workbench.action.closeWindow', { label: mnemonicLabel(nls.localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window")), click: () => this.windowsService.getLastActiveWindow().win.close(), enabled: this.windowsService.getWindowCount() > 0 }));
@ -468,10 +468,15 @@ export class VSCodeMenu {
}
private createOpenRecentMenuItem(path: string, actionId: string): Electron.MenuItem {
let label = path;
if ((platform.isMacintosh || platform.isLinux) && path.indexOf(this.environmentService.userHome) === 0) {
label = `~${path.substr(this.environmentService.userHome.length)}`;
}
return new MenuItem(this.likeAction(actionId, {
label: unMnemonicLabel(path), click: (menuItem, win, event) => {
const openInNewWindow = event && ((!platform.isMacintosh && event.ctrlKey) || (platform.isMacintosh && event.metaKey));
const success = !!this.windowsService.open({ cli: this.environmentService.args, pathsToOpen: [path], forceNewWindow: openInNewWindow });
label: unMnemonicLabel(label), click: (menuItem, win, event) => {
const openInNewWindow = this.isOptionClick(event);
const success = !!this.windowsService.open({ context: OpenContext.MENU, cli: this.environmentService.args, pathsToOpen: [path], forceNewWindow: openInNewWindow });
if (!success) {
this.windowsService.removeFromRecentPathsList(path);
}
@ -479,6 +484,10 @@ export class VSCodeMenu {
}, false));
}
private isOptionClick(event: Electron.Event): boolean {
return event && ((!platform.isMacintosh && (event.ctrlKey || event.shiftKey)) || (platform.isMacintosh && (event.metaKey || event.altKey)));
}
private createRoleMenuItem(label: string, actionId: string, role: Electron.MenuItemRole): Electron.MenuItem {
const options: Electron.MenuItemOptions = {
label: mnemonicLabel(label),
@ -890,11 +899,18 @@ export class VSCodeMenu {
}
}
private createMenuItem(label: string, actionId: string, enabled?: boolean, checked?: boolean): Electron.MenuItem;
private createMenuItem(label: string, actionId: string | string[], enabled?: boolean, checked?: boolean): Electron.MenuItem;
private createMenuItem(label: string, click: () => void, enabled?: boolean, checked?: boolean): Electron.MenuItem;
private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): Electron.MenuItem {
const label = mnemonicLabel(arg1);
const click: () => void = (typeof arg2 === 'function') ? arg2 : () => this.windowsService.sendToFocused('vscode:runAction', arg2);
const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem, win, event) => {
let actionId = arg2;
if (Array.isArray(arg2)) {
actionId = this.isOptionClick(event) ? arg2[1] : arg2[0]; // support alternative action if we got multiple action Ids and the option key was pressed while invoking
}
this.windowsService.sendToFocused('vscode:runAction', actionId);
};
const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsService.getWindowCount() > 0;
const checked = typeof arg4 === 'boolean' ? arg4 : false;

View file

@ -205,21 +205,6 @@ export class VSCodeWindow implements IVSCodeWindow {
this._win = new BrowserWindow(options);
this._id = this._win.id;
// TODO@joao: hook this up to some initialization routine
// this causes a race between setting the headers and doing
// a request that needs them. chances are low
getCommonHTTPHeaders().done(headers => {
if (!this._win) {
return;
}
const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*'];
this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => {
cb({ cancel: false, requestHeaders: objects.assign(details.requestHeaders, headers) });
});
});
if (isFullscreenOrMaximized) {
this.win.maximize();
@ -238,9 +223,28 @@ export class VSCodeWindow implements IVSCodeWindow {
this.setMenuBarVisibility(false); // respect configured menu bar visibility
}
// TODO@joao: hook this up to some initialization routine
// this causes a race between setting the headers and doing
// a request that needs them. chances are low
this.setCommonHTTPHeaders();
this.registerListeners();
}
private setCommonHTTPHeaders(): void {
getCommonHTTPHeaders().done(headers => {
if (!this._win) {
return;
}
const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*'];
this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => {
cb({ cancel: false, requestHeaders: objects.assign(details.requestHeaders, headers) });
});
});
}
public hasHiddenTitleBarStyle(): boolean {
return this.hiddenTitleBarStyle;
}
@ -478,7 +482,7 @@ export class VSCodeWindow implements IVSCodeWindow {
windowConfiguration.fullscreen = this._win.isFullScreen();
// Set Accessibility Config
windowConfiguration.highContrast = platform.isWindows && systemPreferences.isInvertedColorScheme();
windowConfiguration.highContrast = platform.isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast);
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
// Perf Counters

View file

@ -34,12 +34,32 @@ enum WindowError {
CRASHED
}
export enum OpenContext {
// opening when running from the command line
CLI,
// macOS only: opening from the dock (also when opening files to a running instance from desktop)
DOCK,
// opening from the main application window
MENU,
// opening from a file or folder dialog
DIALOG,
// any other way of opening
OTHER
}
export interface IOpenConfiguration {
context: OpenContext;
cli: ParsedArgs;
userEnv?: platform.IProcessEnvironment;
pathsToOpen?: string[];
preferNewWindow?: boolean;
forceNewWindow?: boolean;
forceReuseWindow?: boolean;
forceEmpty?: boolean;
windowToUse?: VSCodeWindow;
diffMode?: boolean;
@ -96,10 +116,10 @@ export interface IWindowsMainService {
openFilePicker(forceNewWindow?: boolean, path?: string, window?: VSCodeWindow): void;
openFolderPicker(forceNewWindow?: boolean, window?: VSCodeWindow): void;
openAccessibilityOptions(): void;
focusLastActive(cli: ParsedArgs): VSCodeWindow;
focusLastActive(cli: ParsedArgs, context: OpenContext): VSCodeWindow;
getLastActiveWindow(): VSCodeWindow;
findWindow(workspacePath: string, filePath?: string, extensionDevelopmentPath?: string): VSCodeWindow;
openNewWindow(): void;
openNewWindow(context: OpenContext): void;
sendToFocused(channel: string, ...args: any[]): void;
sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void;
getFocusedWindow(): VSCodeWindow;
@ -166,7 +186,7 @@ export class WindowsManager implements IWindowsMainService {
// Mac only event: open new window when we get activated
if (!hasVisibleWindows) {
this.openNewWindow();
this.openNewWindow(OpenContext.DOCK);
}
});
@ -187,7 +207,12 @@ export class WindowsManager implements IWindowsMainService {
// Handle paths delayed in case more are coming!
runningTimeout = setTimeout(() => {
this.open({ cli: this.environmentService.args, pathsToOpen: macOpenFiles, preferNewWindow: true /* dropping on the dock prefers to open in a new window */ });
this.open({
context: OpenContext.DOCK /* can also be opening from finder while app is running */,
cli: this.environmentService.args,
pathsToOpen: macOpenFiles,
preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */
});
macOpenFiles = [];
runningTimeout = null;
}, 100);
@ -272,6 +297,8 @@ export class WindowsManager implements IWindowsMainService {
}
public open(openConfig: IOpenConfiguration): VSCodeWindow[] {
const windowConfig = this.configurationService.getConfiguration<IWindowSettings>('window');
let iPathsToOpen: IPath[];
const usedWindows: VSCodeWindow[] = [];
@ -345,22 +372,26 @@ export class WindowsManager implements IWindowsMainService {
filesToOpen = candidates;
}
let openInNewWindow = openConfig.preferNewWindow || openConfig.forceNewWindow;
// let the user settings override how folders are open in a new window or same window unless we are forced
let openFolderInNewWindow = (openConfig.preferNewWindow || openConfig.forceNewWindow) && !openConfig.forceReuseWindow;
if (!openConfig.forceNewWindow && !openConfig.forceReuseWindow && windowConfig && (windowConfig.openFoldersInNewWindow === 'on' || windowConfig.openFoldersInNewWindow === 'off')) {
openFolderInNewWindow = (windowConfig.openFoldersInNewWindow === 'on');
}
// Handle files to open/diff or to create when we dont open a folder
if (!foldersToOpen.length && (filesToOpen.length > 0 || filesToCreate.length > 0 || filesToDiff.length > 0)) {
// const the user settings override how files are open in a new window or same window unless we are forced
// let the user settings override how files are open in a new window or same window unless we are forced (not for extension development though)
let openFilesInNewWindow: boolean;
if (openConfig.forceNewWindow) {
openFilesInNewWindow = true;
if (openConfig.forceNewWindow || openConfig.forceReuseWindow) {
openFilesInNewWindow = openConfig.forceNewWindow && !openConfig.forceReuseWindow;
} else {
openFilesInNewWindow = openConfig.preferNewWindow;
if (openFilesInNewWindow && !openConfig.cli.extensionDevelopmentPath) { // can be overriden via settings (not for PDE though!)
const windowConfig = this.configurationService.getConfiguration<IWindowSettings>('window');
if (windowConfig && !windowConfig.openFilesInNewWindow) {
openFilesInNewWindow = false; // do not open in new window if user configured this explicitly
}
if (openConfig.context === OpenContext.DOCK) {
openFilesInNewWindow = true; // only on macOS do we allow to open files in a new window if this is triggered via DOCK context
}
if (!openConfig.cli.extensionDevelopmentPath && windowConfig && (windowConfig.openFilesInNewWindow === 'on' || windowConfig.openFilesInNewWindow === 'off' || <any>windowConfig.openFilesInNewWindow === false /* TODO@Ben migration */)) {
openFilesInNewWindow = (windowConfig.openFilesInNewWindow === 'on');
}
}
@ -368,8 +399,9 @@ export class WindowsManager implements IWindowsMainService {
const lastActiveWindow = this.getLastActiveWindow();
if (!openFilesInNewWindow && lastActiveWindow) {
lastActiveWindow.focus();
const files = { filesToOpen, filesToCreate, filesToDiff }; // copy to object because they get reset shortly after
lastActiveWindow.ready().then(readyWindow => {
readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff });
readyWindow.send('vscode:openFiles', files);
});
usedWindows.push(lastActiveWindow);
@ -381,7 +413,7 @@ export class WindowsManager implements IWindowsMainService {
const browserWindow = this.openInBrowserWindow(configuration, true /* new window */);
usedWindows.push(browserWindow);
openInNewWindow = true; // any other folders to open must open in new window then
openFolderInNewWindow = true; // any other folders to open must open in new window then
}
// Reset these because we handled them
@ -399,8 +431,9 @@ export class WindowsManager implements IWindowsMainService {
if (windowsOnWorkspacePath.length > 0) {
const browserWindow = windowsOnWorkspacePath[0];
browserWindow.focus(); // just focus one of them
const files = { filesToOpen, filesToCreate, filesToDiff }; // copy to object because they get reset shortly after
browserWindow.ready().then(readyWindow => {
readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff });
readyWindow.send('vscode:openFiles', files);
});
usedWindows.push(browserWindow);
@ -410,7 +443,7 @@ export class WindowsManager implements IWindowsMainService {
filesToCreate = [];
filesToDiff = [];
openInNewWindow = true; // any other folders to open must open in new window then
openFolderInNewWindow = true; // any other folders to open must open in new window then
}
// Open remaining ones
@ -420,7 +453,7 @@ export class WindowsManager implements IWindowsMainService {
}
const configuration = this.toConfiguration(openConfig, folderToOpen, filesToOpen, filesToCreate, filesToDiff);
const browserWindow = this.openInBrowserWindow(configuration, openInNewWindow, openInNewWindow ? void 0 : openConfig.windowToUse);
const browserWindow = this.openInBrowserWindow(configuration, openFolderInNewWindow, openFolderInNewWindow ? void 0 : openConfig.windowToUse);
usedWindows.push(browserWindow);
// Reset these because we handled them
@ -428,7 +461,7 @@ export class WindowsManager implements IWindowsMainService {
filesToCreate = [];
filesToDiff = [];
openInNewWindow = true; // any other folders to open must open in new window then
openFolderInNewWindow = true; // any other folders to open must open in new window then
});
}
@ -439,7 +472,7 @@ export class WindowsManager implements IWindowsMainService {
const browserWindow = this.openInBrowserWindow(configuration, true /* new window */, null, emptyWorkspaceBackupFolder);
usedWindows.push(browserWindow);
openInNewWindow = true; // any other folders to open must open in new window then
openFolderInNewWindow = true; // any other folders to open must open in new window then
});
}
@ -447,10 +480,10 @@ export class WindowsManager implements IWindowsMainService {
else if (emptyToOpen.length > 0) {
emptyToOpen.forEach(() => {
const configuration = this.toConfiguration(openConfig);
const browserWindow = this.openInBrowserWindow(configuration, openInNewWindow, openInNewWindow ? void 0 : openConfig.windowToUse);
const browserWindow = this.openInBrowserWindow(configuration, openFolderInNewWindow, openFolderInNewWindow ? void 0 : openConfig.windowToUse);
usedWindows.push(browserWindow);
openInNewWindow = true; // any other folders to open must open in new window then
openFolderInNewWindow = true; // any other folders to open must open in new window then
});
}
@ -609,7 +642,7 @@ export class WindowsManager implements IWindowsMainService {
}
// Open it
this.open({ cli: openConfig.cli, forceNewWindow: true, forceEmpty: openConfig.cli._.length === 0 });
this.open({ context: openConfig.context, cli: openConfig.cli, forceNewWindow: true, forceEmpty: openConfig.cli._.length === 0 });
}
private toConfiguration(config: IOpenConfiguration, workspacePath?: string, filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[]): IWindowConfiguration {
@ -889,7 +922,7 @@ export class WindowsManager implements IWindowsMainService {
private doPickAndOpen(options: INativeOpenDialogOptions): void {
this.getFileOrFolderPaths(options, (paths: string[]) => {
if (paths && paths.length) {
this.open({ cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: options.forceNewWindow });
this.open({ context: OpenContext.DIALOG, cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: options.forceNewWindow });
}
});
}
@ -922,7 +955,7 @@ export class WindowsManager implements IWindowsMainService {
});
}
public focusLastActive(cli: ParsedArgs): VSCodeWindow {
public focusLastActive(cli: ParsedArgs, context: OpenContext): VSCodeWindow {
const lastActive = this.getLastActiveWindow();
if (lastActive) {
lastActive.focus();
@ -932,7 +965,7 @@ export class WindowsManager implements IWindowsMainService {
// No window - open new one
this.windowsState.openedFolders = []; // make sure we do not open too much
const res = this.open({ cli: cli });
const res = this.open({ context, cli });
return res && res[0];
}
@ -994,8 +1027,8 @@ export class WindowsManager implements IWindowsMainService {
return null;
}
public openNewWindow(): void {
this.open({ cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true });
public openNewWindow(context: OpenContext): void {
this.open({ context, cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true });
}
public sendToFocused(channel: string, ...args: any[]): void {

View file

@ -5,7 +5,7 @@
'use strict';
import * as nls from 'vs/nls';
import { merge } from 'vs/base/common/arrays';
import { flatten } from 'vs/base/common/arrays';
import { IStringDictionary, forEach, values } from 'vs/base/common/collections';
import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
@ -34,7 +34,7 @@ class ChangeRecorder {
private _fileService: IFileService;
constructor(fileService: IFileService) {
constructor(fileService?: IFileService) {
this._fileService = fileService;
}
@ -42,24 +42,27 @@ class ChangeRecorder {
const changes: IStringDictionary<IFileChange[]> = Object.create(null);
const stop = this._fileService.onFileChanges((event) => {
event.changes.forEach(change => {
let stop: IDisposable;
if (this._fileService) {
stop = this._fileService.onFileChanges((event) => {
event.changes.forEach(change => {
const key = String(change.resource);
let array = changes[key];
const key = String(change.resource);
let array = changes[key];
if (!array) {
changes[key] = array = [];
}
if (!array) {
changes[key] = array = [];
}
array.push(change);
array.push(change);
});
});
});
}
return {
stop: () => { stop.dispose(); },
stop: () => { return stop && stop.dispose(); },
hasChanged: (resource: URI) => !!changes[resource.toString()],
allChanges: () => merge(values(changes))
allChanges: () => flatten(values(changes))
};
}
}
@ -273,14 +276,14 @@ export interface BulkEdit {
finish(): TPromise<ISelection>;
}
export function bulkEdit(fileService: IFileService, textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor, edits: IResourceEdit[], progress: IProgressRunner = null): TPromise<any> {
let bulk = createBulkEdit(fileService, textModelResolverService, editor);
export function bulkEdit(textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor, edits: IResourceEdit[], fileService?: IFileService, progress: IProgressRunner = null): TPromise<any> {
let bulk = createBulkEdit(textModelResolverService, editor, fileService);
bulk.add(edits);
bulk.progress(progress);
return bulk.finish();
}
export function createBulkEdit(fileService: IFileService, textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor): BulkEdit {
export function createBulkEdit(textModelResolverService: ITextModelResolverService, editor?: ICommonCodeEditor, fileService?: IFileService): BulkEdit {
let all: IResourceEdit[] = [];
let recording = new ChangeRecorder(fileService).start();

View file

@ -11,12 +11,11 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import * as dom from 'vs/base/browser/dom';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { ICommonCodeEditor, IEditorContribution, MouseTargetType, EditorContextKeys, IScrollEvent } from 'vs/editor/common/editorCommon';
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
@ -125,9 +124,17 @@ export class ContextMenuController implements IEditorContribution {
private _getMenuActions(): IAction[] {
const result: IAction[] = [];
const contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService);
fillInActions(contextMenu, this._editor.getModel().uri, result);
let contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService);
const groups = contextMenu.getActions(this._editor.getModel().uri);
contextMenu.dispose();
for (let group of groups) {
const [, actions] = group;
result.push(...actions);
result.push(new Separator());
}
result.pop(); // remove last separator
return result;
}

View file

@ -105,10 +105,12 @@
}
.monaco-editor .find-widget.no-results .matchesCount {
background-color: rgba(255,0,0,0.5);
color: #A1260D;
}
.monaco-editor.vs-dark .find-widget.no-results .matchesCount {
background-color: rgba(255,0,0,0.3);
.monaco-editor.vs-dark .find-widget.no-results .matchesCount,
.monaco-editor.hc-black .find-widget.no-results .matchesCount {
color: #F48771
}
.monaco-editor .find-widget .matchesCount {

View file

@ -43,7 +43,7 @@ const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replac
const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode");
const NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', "Only the first 999 results are highlighted, but all find operations work on the entire text.");
const NLS_MATCHES_LOCATION = nls.localize('label.matchesLocation', "{0} of {1}");
const NLS_NO_RESULTS = nls.localize('label.noResults', "No results");
const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
let MAX_MATCHES_COUNT_WIDTH = 69;
const WIDGET_FIXED_WIDTH = 411 - 69;

View file

@ -8,6 +8,8 @@
display: flex;
align-items: center;
justify-content: center;
height: 16px;
width: 16px;
}
.monaco-editor .lightbulb-glyph:hover {
@ -16,12 +18,18 @@
.monaco-editor.vs .lightbulb-glyph {
background: url('lightbulb.svg') center center no-repeat;
height: 16px;
width: 16px;
}
.monaco-editor.vs-dark .lightbulb-glyph, .monaco-editor.hc-black .lightbulb-glyph {
background: url('lightbulb-dark.svg') center center no-repeat;
height: 16px;
width: 16px;
.monaco-editor.vs .lightbulb-glyph[data-severity="high"]{
background: url('lightbulb.svg') center center no-repeat;
}
.monaco-editor.vs-dark .lightbulb-glyph,
.monaco-editor.hc-black .lightbulb-glyph {
background: url('lightbulb-dark.svg') center center no-repeat;
}
.monaco-editor.vs-dark .lightbulb-glyph[data-severity="high"],
.monaco-editor.hc-black .lightbulb-glyph[data-severity="high"] {
background: url('lightbulb-dark.svg') center center no-repeat;
}

View file

@ -7,9 +7,10 @@
import 'vs/css!./lightBulbWidget';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import Event, { Emitter, any } from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import * as dom from 'vs/base/browser/dom';
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { QuickFixComputeEvent } from './quickFixModel';
import { QuickFixComputeEvent } from 'vs/editor/contrib/quickFix/common/quickFixModel';
export class LightBulbWidget implements IOverlayWidget, IDisposable {
@ -86,7 +87,7 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable {
const modelNow = this._model;
e.fixes.done(fixes => {
if (modelNow === this._model && fixes && fixes.length > 0) {
this.show(e.range.startLineNumber);
this.show(e);
} else {
this.hide();
}
@ -99,7 +100,8 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable {
return this._model;
}
show(line: number): void {
show(e: QuickFixComputeEvent): void {
const line = e.range.startLineNumber;
if (!this._hasSpaceInGlyphMargin(line)) {
return;
}
@ -107,6 +109,7 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable {
this._line = line;
this._visible = true;
this._layout();
this._domNode.dataset['severity'] = e.severity >= Severity.Warning ? 'high' : '';
}
}

View file

@ -16,9 +16,9 @@ import { ICommonCodeEditor, EditorContextKeys, ModeContextKeys, IEditorContribut
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
import { QuickFixContextMenu } from './quickFixWidget';
import { LightBulbWidget } from './lightBulbWidget';
import { QuickFixModel, QuickFixComputeEvent } from './quickFixModel';
import { QuickFixContextMenu } from 'vs/editor/contrib/quickFix/browser/quickFixWidget';
import { LightBulbWidget } from 'vs/editor/contrib/quickFix/browser/lightBulbWidget';
import { QuickFixModel, QuickFixComputeEvent } from 'vs/editor/contrib/quickFix/common/quickFixModel';
@editorContribution
export class QuickFixController implements IEditorContribution {
@ -88,7 +88,7 @@ export class QuickFixController implements IEditorContribution {
}
public triggerFromEditorSelection(): void {
this._model.triggerManual(this._editor.getSelection());
this._model.triggerManual();
}
private _updateLightBulbTitle(): void {

View file

@ -6,21 +6,21 @@
import * as arrays from 'vs/base/common/arrays';
import Event, { Emitter } from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IMarker, IMarkerService } from 'vs/platform/markers/common/markers';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { ICommonCodeEditor, IPosition, IRange } from 'vs/editor/common/editorCommon';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CodeActionProviderRegistry, CodeAction } from 'vs/editor/common/modes';
import { getCodeActions } from '../common/quickFix';
class QuickFixOracle {
export class QuickFixOracle {
private _disposables: IDisposable[] = [];
private _currentRange: IRange;
constructor(private _editor: ICommonCodeEditor, private _markerService: IMarkerService, private _signalChange: (e: QuickFixComputeEvent) => any) {
@ -34,29 +34,57 @@ class QuickFixOracle {
this._disposables = dispose(this._disposables);
}
private _onMarkerChanges(resources: URI[]): void {
const {uri} = this._editor.getModel();
let affectedBy = false;
for (const resource of resources) {
if (resource.toString() === uri.toString()) {
affectedBy = true;
break;
}
trigger(): void {
let {range, severity} = this._rangeAtPosition();
if (!range) {
range = this._editor.getSelection();
}
if (affectedBy) {
this._onCursorChange();
}
}
private _onCursorChange(): void {
const range = this._markerAtPosition() || this._wordAtPosition();
this._signalChange({
type: 'auto',
type: 'manual',
severity,
range,
position: this._editor.getPosition(),
fixes: range && getCodeActions(this._editor.getModel(), this._editor.getModel().validateRange(range))
});
}
private _onMarkerChanges(resources: URI[]): void {
const {uri} = this._editor.getModel();
for (const resource of resources) {
if (resource.toString() === uri.toString()) {
this._onCursorChange();
return;
}
}
}
private _onCursorChange(): void {
const {range, severity} = this._rangeAtPosition();
if (!Range.equalsRange(this._currentRange, range)) {
this._currentRange = range;
this._signalChange({
type: 'auto',
severity,
range,
position: this._editor.getPosition(),
fixes: range && getCodeActions(this._editor.getModel(), this._editor.getModel().validateRange(range))
});
}
}
private _rangeAtPosition(): { range: IRange, severity: Severity; } {
let range: IRange;
let severity: Severity;
const marker = this._markerAtPosition();
if (marker) {
range = Range.lift(marker);
severity = marker.severity;
} else {
range = this._wordAtPosition();
severity = Severity.Info;
}
return { range, severity };
}
private _markerAtPosition(): IMarker {
@ -76,26 +104,23 @@ class QuickFixOracle {
}
private _wordAtPosition(): IRange {
return;
// todo@joh - enable once we decide to eagerly show the
// light bulb as the cursor moves
// const {positionLineNumber, positionColumn} = this._editor.getSelection();
// const model = this._editor.getModel();
// const info = model.getWordAtPosition({ lineNumber: positionLineNumber, column: positionColumn });
// if (info) {
// return {
// startLineNumber: positionLineNumber,
// startColumn: info.startColumn,
// endLineNumber: positionLineNumber,
// endColumn: info.endColumn
// };
// }
const {positionLineNumber, positionColumn} = this._editor.getSelection();
const model = this._editor.getModel();
const info = model.getWordAtPosition({ lineNumber: positionLineNumber, column: positionColumn });
if (info) {
return {
startLineNumber: positionLineNumber,
startColumn: info.startColumn,
endLineNumber: positionLineNumber,
endColumn: info.endColumn
};
}
}
}
export interface QuickFixComputeEvent {
type: 'auto' | 'manual';
severity: Severity;
range: IRange;
position: IPosition;
fixes: TPromise<CodeAction[]>;
@ -109,7 +134,7 @@ export class QuickFixModel {
private _onDidChangeFixes = new Emitter<QuickFixComputeEvent>();
private _disposables: IDisposable[] = [];
constructor(editor: ICodeEditor, markerService: IMarkerService) {
constructor(editor: ICommonCodeEditor, markerService: IMarkerService) {
this._editor = editor;
this._markerService = markerService;
@ -132,7 +157,8 @@ export class QuickFixModel {
private _update(): void {
if (this._quickFixOracle) {
dispose(this._quickFixOracle);
this._quickFixOracle.dispose();
this._quickFixOracle = undefined;
this._onDidChangeFixes.fire(undefined);
}
@ -144,16 +170,9 @@ export class QuickFixModel {
}
}
triggerManual(selection: Selection): void {
const model = this._editor.getModel();
if (model) {
const fixes = getCodeActions(model, selection);
this._onDidChangeFixes.fire({
type: 'manual',
range: selection,
position: { lineNumber: selection.positionLineNumber, column: selection.positionColumn },
fixes
});
triggerManual(): void {
if (this._quickFixOracle) {
this._quickFixOracle.trigger();
}
}
}

View file

@ -0,0 +1,130 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { Model } from 'vs/editor/common/model/model';
import { mockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { QuickFixOracle } from 'vs/editor/contrib/quickFix/common/quickFixModel';
import { CodeActionProviderRegistry, LanguageIdentifier } from 'vs/editor/common/modes';
suite('QuickFix', () => {
const languageIdentifier = new LanguageIdentifier('foo-lang', 3);
let uri = URI.parse('fake:path');
let model = Model.createFromString('foobar foo bar\nfarboo far boo', undefined, languageIdentifier, uri);
let markerService: MarkerService;
let editor: ICommonCodeEditor;
let reg = CodeActionProviderRegistry.register(languageIdentifier.sid, {
provideCodeActions() {
return [{ command: { id: 'test-command', title: 'test', arguments: [] }, score: 1 }];
}
});
setup(() => {
markerService = new MarkerService();
editor = mockCodeEditor([], { model });
editor.setPosition({ lineNumber: 1, column: 1 });
});
suiteTeardown(() => {
reg.dispose();
model.dispose();
});
test('Orcale -> marker added', done => {
const oracle = new QuickFixOracle(editor, markerService, e => {
assert.equal(e.type, 'auto');
assert.ok(e.fixes);
e.fixes.then(fixes => {
oracle.dispose();
assert.equal(fixes.length, 1);
done();
}, done);
});
// start here
markerService.changeOne('fake', uri, [{
startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6,
message: 'error',
severity: 1,
code: '',
source: ''
}]);
});
test('Orcale -> position changed', done => {
markerService.changeOne('fake', uri, [{
startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6,
message: 'error',
severity: 1,
code: '',
source: ''
}]);
editor.setPosition({ lineNumber: 2, column: 1 });
const oracle = new QuickFixOracle(editor, markerService, e => {
assert.equal(e.type, 'auto');
assert.ok(e.fixes);
e.fixes.then(fixes => {
oracle.dispose();
assert.equal(fixes.length, 1);
done();
}, done);
});
// start here
editor.setPosition({ lineNumber: 1, column: 1 });
});
test('Oracle -> ask once per marker/word', () => {
let counter = 0;
let reg = CodeActionProviderRegistry.register(languageIdentifier.sid, {
provideCodeActions() {
counter += 1;
return [];
}
});
markerService.changeOne('fake', uri, [{
startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6,
message: 'error',
severity: 1,
code: '',
source: ''
}]);
let fixes: TPromise<any>[] = [];
let oracle = new QuickFixOracle(editor, markerService, e => {
fixes.push(e.fixes);
});
editor.setPosition({ lineNumber: 1, column: 3 }); // marker
editor.setPosition({ lineNumber: 1, column: 6 }); // (same) marker
editor.setPosition({ lineNumber: 1, column: 8 }); // whitespace
editor.setPosition({ lineNumber: 2, column: 2 }); // word
editor.setPosition({ lineNumber: 2, column: 6 }); // (same) word
return TPromise.join(fixes).then(_ => {
reg.dispose();
oracle.dispose();
assert.equal(counter, 2);
});
});
});

View file

@ -50,8 +50,8 @@ class DecorationsManager implements IDisposable {
private _callOnDispose: IDisposable[] = [];
private _callOnModelChange: IDisposable[] = [];
constructor(private editor: ICodeEditor, private model: ReferencesModel) {
this._callOnDispose.push(this.editor.onDidChangeModel(() => this._onModelChanged()));
constructor(private _editor: ICodeEditor, private _model: ReferencesModel) {
this._callOnDispose.push(this._editor.onDidChangeModel(() => this._onModelChanged()));
this._onModelChanged();
}
@ -62,30 +62,25 @@ class DecorationsManager implements IDisposable {
}
private _onModelChanged(): void {
this.removeDecorations();
this._callOnModelChange = dispose(this._callOnModelChange);
var model = this.editor.getModel();
if (!model) {
return;
}
for (var i = 0, len = this.model.groups.length; i < len; i++) {
if (this.model.groups[i].uri.toString() === model.uri.toString()) {
this._addDecorations(this.model.groups[i]);
return;
const model = this._editor.getModel();
if (model) {
for (const ref of this._model.groups) {
if (ref.uri.toString() === model.uri.toString()) {
this._addDecorations(ref);
return;
}
}
}
}
private _addDecorations(reference: FileReferences): void {
this._callOnModelChange.push(this.editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged(event)));
this._callOnModelChange.push(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged(event)));
this.editor.changeDecorations(accessor => {
this._editor.changeDecorations(accessor => {
var newDecorations: editorCommon.IModelDeltaDecoration[] = [];
var newDecorationsActualIndex: number[] = [];
const newDecorations: editorCommon.IModelDeltaDecoration[] = [];
const newDecorationsActualIndex: number[] = [];
for (let i = 0, len = reference.children.length; i < len; i++) {
let oneReference = reference.children[i];
@ -99,26 +94,25 @@ class DecorationsManager implements IDisposable {
newDecorationsActualIndex.push(i);
}
var decorations = accessor.deltaDecorations([], newDecorations);
for (var i = 0; i < decorations.length; i++) {
const decorations = accessor.deltaDecorations([], newDecorations);
for (let i = 0; i < decorations.length; i++) {
this._decorations.set(decorations[i], reference.children[newDecorationsActualIndex[i]]);
}
});
}
private _onDecorationChanged(event: editorCommon.IModelDecorationsChangedEvent): void {
var changedDecorations = event.changedDecorations,
const changedDecorations = event.changedDecorations,
toRemove: string[] = [];
for (var i = 0, len = changedDecorations.length; i < len; i++) {
for (let i = 0, len = changedDecorations.length; i < len; i++) {
let reference = this._decorations.get(changedDecorations[i]);
if (!reference) {
continue;
}
var newRange = this.editor.getModel().getDecorationRange(changedDecorations[i]),
ignore = false;
const newRange = this._editor.getModel().getDecorationRange(changedDecorations[i]);
let ignore = false;
if (Range.equalsRange(newRange, reference.range)) {
continue;
@ -127,8 +121,8 @@ class DecorationsManager implements IDisposable {
ignore = true;
} else {
var lineLength = reference.range.endColumn - reference.range.startColumn,
newLineLength = newRange.endColumn - newRange.startColumn;
const lineLength = reference.range.endColumn - reference.range.startColumn;
const newLineLength = newRange.endColumn - newRange.startColumn;
if (lineLength !== newLineLength) {
ignore = true;
@ -143,7 +137,7 @@ class DecorationsManager implements IDisposable {
}
}
this.editor.changeDecorations((accessor) => {
this._editor.changeDecorations((accessor) => {
for (let i = 0, len = toRemove.length; i < len; i++) {
delete this._decorations[toRemove[i]];
}
@ -152,7 +146,7 @@ class DecorationsManager implements IDisposable {
}
public removeDecorations(): void {
this.editor.changeDecorations(accessor => {
this._editor.changeDecorations(accessor => {
this._decorations.forEach((value, key) => {
accessor.removeDecoration(key);
});

View file

@ -22,6 +22,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { rename } from '../common/rename';
import RenameInputField from './renameInputField';
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
import { optional } from 'vs/platform/instantiation/common/instantiation';
// --- register actions and commands
@ -42,10 +43,10 @@ class RenameController implements IEditorContribution {
constructor(
private editor: ICodeEditor,
@IMessageService private _messageService: IMessageService,
@IFileService private _fileService: IFileService,
@ITextModelResolverService private _textModelResolverService: ITextModelResolverService,
@IProgressService private _progressService: IProgressService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@optional(IFileService) private _fileService: IFileService
) {
this._renameInputField = new RenameInputField(editor);
this._renameInputVisible = CONTEXT_RENAME_INPUT_VISIBLE.bindTo(contextKeyService);
@ -132,7 +133,7 @@ class RenameController implements IEditorContribution {
// start recording of file changes so that we can figure out if a file that
// is to be renamed conflicts with another (concurrent) modification
let edit = createBulkEdit(this._fileService, this._textModelResolverService, <ICodeEditor>this.editor);
let edit = createBulkEdit(this._textModelResolverService, <ICodeEditor>this.editor, this._fileService);
return rename(this.editor.getModel(), this.editor.getPosition(), newName).then(result => {
if (result.rejectReason) {

View file

@ -122,15 +122,15 @@ export class CodeSnippet implements ICodeSnippet {
for (let {startLineNumber, startColumn, endLineNumber, endColumn} of originalPlaceHolder.occurences) {
if (startColumn > 1) {
// placeholders that aren't at the beginning of the snippet line
if (startColumn > 1 || startLineNumber === 1) {
// placeholders that aren't at the beginning of new snippet lines
// will be moved by how many characters the indentation has been
// adjusted
startColumn = startColumn + deltaColumns[startLineNumber];
endColumn = endColumn + deltaColumns[endLineNumber];
} else {
// placeholders at the beginning of the snippet line
// placeholders at the beginning of new snippet lines
// will be indented by the reference indentation
startColumn += referenceIndentation.length;
endColumn += referenceIndentation.length;
@ -140,7 +140,7 @@ export class CodeSnippet implements ICodeSnippet {
startLineNumber: startLineNumber + deltaLine,
startColumn,
endLineNumber: endLineNumber + deltaLine,
endColumn
endColumn,
});
}

View file

@ -225,7 +225,7 @@ suite('Editor Contrib - Snippets', () => {
});
test('issue #11890: Bad cursor position', () => {
test('issue #11890: Bad cursor position 1/2', () => {
let snippet = CodeSnippet.fromTextmate([
'afterEach((done) => {',
@ -242,6 +242,7 @@ suite('Editor Contrib - Snippets', () => {
assert.equal(boundSnippet.lines[1], ' test');
assert.equal(boundSnippet.placeHolders.length, 3);
assert.equal(boundSnippet.finishPlaceHolderIndex, 2);
let [first, second] = boundSnippet.placeHolders;
assert.equal(first.occurences.length, 1);
assert.equal(first.occurences[0].startColumn, 1);
@ -249,6 +250,49 @@ suite('Editor Contrib - Snippets', () => {
assert.equal(second.occurences[0].startColumn, 7);
});
test('issue #11890: Bad cursor position 2/2', () => {
let snippet = CodeSnippet.fromTextmate('${1}\ttest');
let boundSnippet = snippet.bind('abc abc abc prefix3', 0, 12, {
normalizeIndentation(str: string): string {
return str.replace(/\t/g, ' ');
}
});
assert.equal(boundSnippet.lines[0], '\ttest');
assert.equal(boundSnippet.placeHolders.length, 2);
assert.equal(boundSnippet.finishPlaceHolderIndex, 1);
let [first, second] = boundSnippet.placeHolders;
assert.equal(first.occurences.length, 1);
assert.equal(first.occurences[0].startColumn, 13);
assert.equal(second.occurences.length, 1);
assert.equal(second.occurences[0].startColumn, 18);
});
test('issue #17989: Bad selection', () => {
let snippet = CodeSnippet.fromTextmate('${1:HoldMeTight}');
let boundSnippet = snippet.bind('abc abc abc prefix3', 0, 12, {
normalizeIndentation(str: string): string {
return str.replace(/\t/g, ' ');
}
});
assert.equal(boundSnippet.lines[0], 'HoldMeTight');
assert.equal(boundSnippet.placeHolders.length, 2);
assert.equal(boundSnippet.finishPlaceHolderIndex, 1);
let [first, second] = boundSnippet.placeHolders;
assert.equal(first.occurences.length, 1);
assert.equal(first.occurences[0].startColumn, 13);
assert.equal(second.occurences.length, 1);
assert.equal(second.occurences[0].startColumn, 24);
});
test('variables, simple', () => {
const resolver: ISnippetVariableResolver = {

View file

@ -19,23 +19,32 @@ interface ISnippetPick extends IPickOpenEntry {
snippet: ISnippet;
}
class NameAndLangId {
class Args {
static fromArg(arg: any): NameAndLangId {
static fromUser(arg: any): Args {
if (typeof arg !== 'object') {
return new NameAndLangId(undefined, undefined);
return Args._empty;
}
let {snippet, name, langId} = arg;
if (typeof snippet !== 'string') {
snippet = undefined;
}
let {name, langId} = arg;
if (typeof name !== 'string') {
name = undefined;
}
if (typeof langId !== 'string') {
langId = undefined;
}
return new NameAndLangId(name, langId);
return new Args(snippet, name, langId);
}
private constructor(public readonly name: string, public readonly langId: string) {
private static _empty = new Args(undefined, undefined, undefined);
private constructor(
public readonly snippet: string,
public readonly name: string,
public readonly langId: string
) {
}
@ -62,16 +71,28 @@ class InsertSnippetAction extends EditorAction {
const quickOpenService = accessor.get(IQuickOpenService);
const {lineNumber, column} = editor.getPosition();
let {name, langId} = NameAndLangId.fromArg(arg);
let {snippet, name, langId} = Args.fromUser(arg);
let languageId: LanguageId;
if (langId) {
languageId = modeService.getLanguageIdentifier(langId).iid;
} else {
languageId = editor.getModel().getLanguageIdAtPosition(lineNumber, column);
}
return new TPromise<ISnippet>((resolve, reject) => {
if (snippet) {
return resolve({
codeSnippet: snippet,
description: undefined,
name: undefined,
owner: undefined,
prefix: undefined
});
}
let languageId: LanguageId;
if (langId) {
languageId = modeService.getLanguageIdentifier(langId).iid;
} else {
languageId = editor.getModel().getLanguageIdAtPosition(lineNumber, column);
}
if (name) {
// take selected snippet
Registry.as<ISnippetsRegistry>(Extensions.Snippets).visitSnippets(languageId, snippet => {

View file

@ -9,9 +9,8 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { forEach } from 'vs/base/common/collections';
import Event, { Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { startsWith } from 'vs/base/common/strings';
import { TPromise } from 'vs/base/common/winjs.base';
import { ICommonCodeEditor, ICursorSelectionChangedEvent, CursorChangeReason, IModel, IPosition } from 'vs/editor/common/editorCommon';
import { ICommonCodeEditor, ICursorSelectionChangedEvent, CursorChangeReason, IModel, IPosition, IWordAtPosition } from 'vs/editor/common/editorCommon';
import { ISuggestSupport, SuggestRegistry } from 'vs/editor/common/modes';
import { provideSuggestionItems, getSuggestionComparator, ISuggestionItem } from './suggest';
import { CompletionModel } from './completionModel';
@ -30,104 +29,51 @@ export interface ISuggestEvent {
auto: boolean;
}
export class Context {
export class LineContext {
static shouldAutoTrigger(editor: ICommonCodeEditor): boolean {
const model = editor.getModel();
if (!model) {
return false;
}
const pos = editor.getPosition();
const word = model.getWordAtPosition(pos);
if (!word) {
return false;
}
if (word.endColumn !== pos.column) {
return false;
}
if (!isNaN(Number(word.word))) {
return false;
}
return true;
}
static isInEditableRange(editor: ICommonCodeEditor): boolean {
const model = editor.getModel();
const position = editor.getPosition();
if (model.hasEditableRange()) {
const editableRange = model.getEditableRange();
if (!editableRange.containsPosition(position)) {
return false;
}
}
return true;
}
readonly lineNumber: number;
readonly column: number;
readonly isInEditableRange: boolean;
readonly lineContentBefore: string;
readonly wordBefore: string;
readonly wordAfter: string;
constructor(model: IModel, position: IPosition, private auto: boolean) {
const lineContent = model.getLineContent(position.lineNumber);
const wordUnderCursor = model.getWordAtPosition(position);
if (wordUnderCursor) {
this.wordBefore = lineContent.substring(wordUnderCursor.startColumn - 1, position.column - 1);
this.wordAfter = lineContent.substring(position.column - 1, wordUnderCursor.endColumn - 1);
} else {
this.wordBefore = '';
this.wordAfter = '';
}
readonly leadingLineContent: string;
readonly leadingWord: IWordAtPosition;
readonly auto;
constructor(model: IModel, position: IPosition, auto: boolean) {
this.leadingLineContent = model.getLineContent(position.lineNumber).substr(0, position.column - 1);
this.leadingWord = model.getWordUntilPosition(position);
this.lineNumber = position.lineNumber;
this.column = position.column;
this.lineContentBefore = lineContent.substr(0, position.column - 1);
this.isInEditableRange = true;
if (model.hasEditableRange()) {
const editableRange = model.getEditableRange();
if (!editableRange.containsPosition(position)) {
this.isInEditableRange = false;
}
}
}
shouldAutoTrigger(): boolean {
if (this.wordBefore.length === 0) {
// Word before position is empty
return false;
}
if (!isNaN(Number(this.wordBefore))) {
// Word before is number only
return false;
}
if (this.wordAfter.length > 0) {
// Word after position is non empty
return false;
}
return true;
}
isDifferentContext(context: Context): boolean {
if (this.lineNumber !== context.lineNumber) {
// Line number has changed
return true;
}
if (context.column < this.column - this.wordBefore.length) {
// column went before word start
return true;
}
if (!startsWith(context.lineContentBefore, this.lineContentBefore)) {
// Line has changed before position
return true;
}
if (context.wordBefore === '' && context.lineContentBefore !== this.lineContentBefore) {
// Most likely a space has been typed
return true;
}
return false;
}
shouldRetrigger(context: Context): boolean {
if (!startsWith(this.lineContentBefore, context.lineContentBefore)) {
// Doesn't look like the same line
return false;
}
if (this.lineContentBefore.length > context.lineContentBefore.length && this.wordBefore.length === 0) {
// Text was deleted and previous current word was empty
return false;
}
if (this.auto && context.wordBefore.length === 0) {
// Currently in auto mode and new current word is empty
return false;
}
return true;
this.auto = auto;
}
}
@ -147,7 +93,7 @@ export class SuggestModel implements IDisposable {
private state: State;
private requestPromise: TPromise<void>;
private context: Context;
private context: LineContext;
private completionModel: CompletionModel;
@ -274,12 +220,11 @@ export class SuggestModel implements IDisposable {
}
private onCursorChange(e: ICursorSelectionChangedEvent): void {
if (!e.selection.isEmpty()) {
this.cancel();
return;
}
if (e.source !== 'keyboard' || e.reason !== CursorChangeReason.NotSet) {
if (!e.selection.isEmpty()
|| e.source !== 'keyboard'
|| e.reason !== CursorChangeReason.NotSet) {
this.cancel();
return;
}
@ -288,32 +233,28 @@ export class SuggestModel implements IDisposable {
return;
}
const isInactive = this.state === State.Idle;
if (isInactive && !this.editor.getConfiguration().contribInfo.quickSuggestions) {
return;
}
const model = this.editor.getModel();
if (!model) {
return;
}
const ctx = new Context(model, this.editor.getPosition(), false);
if (this.state === State.Idle) {
if (isInactive) {
// trigger was not called or it was canceled
this.cancel();
if (ctx.shouldAutoTrigger()) {
this.triggerAutoSuggestPromise = TPromise.timeout(this.quickSuggestDelay);
this.triggerAutoSuggestPromise.then(() => {
this.triggerAutoSuggestPromise = null;
this.trigger(true);
});
if (this.editor.getConfiguration().contribInfo.quickSuggestions) {
// trigger 24x7 IntelliSense when idle and enabled
this.cancel();
if (LineContext.shouldAutoTrigger(this.editor)) {
this.triggerAutoSuggestPromise = TPromise.timeout(this.quickSuggestDelay);
this.triggerAutoSuggestPromise.then(() => {
this.triggerAutoSuggestPromise = null;
this.trigger(true);
});
}
}
} else {
// refine active suggestion
const ctx = new LineContext(model, this.editor.getPosition(), this.state === State.Auto);
this.onNewContext(ctx);
}
}
@ -326,9 +267,9 @@ export class SuggestModel implements IDisposable {
return;
}
const ctx = new Context(model, this.editor.getPosition(), auto);
const ctx = new LineContext(model, this.editor.getPosition(), auto);
if (!ctx.isInEditableRange) {
if (!LineContext.isInEditableRange(this.editor)) {
return;
}
@ -359,9 +300,9 @@ export class SuggestModel implements IDisposable {
items = items.concat(existingItems).sort(cmpFn);
}
const ctx = new Context(model, this.editor.getPosition(), auto);
const ctx = new LineContext(model, this.editor.getPosition(), auto);
this.completionModel = new CompletionModel(items, this.context.column, {
leadingLineContent: ctx.lineContentBefore,
leadingLineContent: ctx.leadingLineContent,
characterCountDelta: this.context ? ctx.column - this.context.column : 0
});
this.onNewContext(ctx);
@ -369,42 +310,66 @@ export class SuggestModel implements IDisposable {
}).then(null, onUnexpectedError);
}
private onNewContext(ctx: Context): void {
if (this.context && this.context.isDifferentContext(ctx)) {
if (this.context.shouldRetrigger(ctx)) {
this.trigger(this.state === State.Auto, true);
} else {
this.cancel();
private onNewContext(ctx: LineContext): void {
if (!this.context) {
// happens when 24x7 IntelliSense is enabled and still in its delay
return;
}
if (ctx.lineNumber !== this.context.lineNumber) {
// e.g. happens when pressing Enter while IntelliSense is computed
this.cancel();
return;
}
if (ctx.column < this.context.column) {
// typed -> moved cursor LEFT -> retrigger if still on a word
if (ctx.leadingWord.word) {
this.trigger(this.context.auto, true);
}
return;
}
} else if (this.completionModel) {
if (!this.completionModel) {
// happens when IntelliSense is not yet computed
return;
}
if (this.completionModel.incomplete && ctx.column > this.context.column) {
const {complete, incomplete} = this.completionModel.resolveIncompleteInfo();
this.trigger(this.state === State.Auto, true, incomplete, complete);
return;
}
if (ctx.column > this.context.column && this.completionModel.incomplete) {
// typed -> moved cursor RIGHT & incomple model -> retrigger
const {complete, incomplete} = this.completionModel.resolveIncompleteInfo();
this.trigger(this.state === State.Auto, true, incomplete, complete);
const auto = this.state === State.Auto;
const oldLineContext = this.completionModel.lineContext;
} else {
// typed -> moved cursor RIGHT -> update UI
let oldLineContext = this.completionModel.lineContext;
let isFrozen = false;
this.completionModel.lineContext = {
leadingLineContent: ctx.lineContentBefore,
characterCountDelta: this.context ? ctx.column - this.context.column : 0
leadingLineContent: ctx.leadingLineContent,
characterCountDelta: ctx.column - this.context.column
};
// when explicitly request when the next context goes
// from 'results' to 'no results' freeze
if (!auto && this.completionModel.items.length === 0) {
this.completionModel.lineContext = oldLineContext;
isFrozen = this.completionModel.items.length > 0;
if (this.completionModel.items.length === 0) {
if (LineContext.shouldAutoTrigger(this.editor) && this.context.leadingWord.endColumn < ctx.leadingWord.startColumn) {
// retrigger when heading into a new word
this.trigger(this.context.auto, true);
return;
}
if (!this.context.auto) {
// freeze when IntelliSense was manually requested
this.completionModel.lineContext = oldLineContext;
isFrozen = this.completionModel.items.length > 0;
}
}
this._onDidSuggest.fire({
completionModel: this.completionModel,
auto: this.context.auto,
isFrozen,
auto
});
}
}

View file

@ -12,7 +12,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { Model } from 'vs/editor/common/model/model';
import { ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon';
import { ISuggestSupport, ISuggestResult, SuggestRegistry } from 'vs/editor/common/modes';
import { SuggestModel, Context } from 'vs/editor/contrib/suggest/common/suggestModel';
import { SuggestModel, LineContext } from 'vs/editor/contrib/suggest/common/suggestModel';
import { MockCodeEditor, MockScopeLocation } from 'vs/editor/test/common/mocks/mockCodeEditor';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
@ -49,8 +49,10 @@ suite('SuggestModel - Context', function () {
function assertAutoTrigger(offset: number, expected: boolean): void {
const pos = model.getPositionAt(offset);
const ctx = new Context(model, pos, false);
assert.equal(ctx.shouldAutoTrigger(), expected);
const editor = createMockEditor(model);
editor.setPosition(pos);
assert.equal(LineContext.shouldAutoTrigger(editor), expected);
editor.dispose();
}
assertAutoTrigger(3, true); // end of word, Das|
@ -59,28 +61,6 @@ suite('SuggestModel - Context', function () {
assertAutoTrigger(55, false); // number, 1861|
});
test('Context - isDifferentContext', function () {
// different line
const ctx = new Context(model, { lineNumber: 1, column: 8 }, true); // Das Pfer|d
assert.equal(ctx.isDifferentContext(new Context(model, { lineNumber: 2, column: 1 }, true)), true);
function createEndContext(value: string) {
const model = Model.createFromString(value);
const ctx = new Context(model, model.getPositionAt(value.length), true); // Das Pfer|d
return ctx;
}
// got shorter -> redo
assert.equal(createEndContext('One Two').isDifferentContext(createEndContext('One Tw')), true);
// got longer inside word -> keep
assert.equal(createEndContext('One Tw').isDifferentContext(createEndContext('One Two')), false);
// got longer new word -> redo
assert.equal(createEndContext('One Two').isDifferentContext(createEndContext('One Two ')), true);
});
});
suite('SuggestModel - TriggerAndCancelOracle', function () {
@ -239,4 +219,49 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
});
});
});
});
test('#17400: Keep filtering suggestModel.ts after space', function () {
disposables.push(SuggestRegistry.register({ scheme: 'test' }, {
triggerCharacters: [],
provideCompletionItems(doc, pos) {
return <ISuggestResult>{
currentWord: '',
incomplete: false,
suggestions: [{
label: 'My Table',
type: 'property',
insertText: 'My Table'
}]
};
}
}));
model.setValue('');
return withOracle((model, editor) => {
return assertEvent(model.onDidSuggest, () => {
editor.setPosition({ lineNumber: 1, column: 1 });
editor.trigger('keyboard', Handler.Type, { text: 'My' });
}, event => {
assert.equal(event.auto, true);
assert.equal(event.completionModel.items.length, 1);
const [first] = event.completionModel.items;
assert.equal(first.suggestion.label, 'My Table');
return assertEvent(model.onDidSuggest, () => {
editor.setPosition({ lineNumber: 1, column: 3 });
editor.trigger('keyboard', Handler.Type, { text: ' ' });
}, event => {
assert.equal(event.auto, true);
assert.equal(event.completionModel.items.length, 1);
const [first] = event.completionModel.items;
assert.equal(first.suggestion.label, 'My Table');
});
});
});
});
});

View file

@ -17,7 +17,7 @@ import { domEvent } from 'vs/base/browser/event';
import { Emitter } from 'vs/base/common/event';
export function fillInActions(menu: IMenu, context: any, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, ignoreAltKey?: boolean): void {
export function fillInActions(menu: IMenu, context: any, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }): void {
const groups = menu.getActions(context);
if (groups.length === 0) {
return;
@ -25,11 +25,6 @@ export function fillInActions(menu: IMenu, context: any, target: IAction[] | { p
for (let tuple of groups) {
let [group, actions] = tuple;
if (!ignoreAltKey && _altKey.value) {
swapWithAltActionsIfPossible(actions);
}
if (group === 'navigation') {
const head = Array.isArray<IAction>(target) ? target : target.primary;
@ -67,13 +62,6 @@ export function fillInActions(menu: IMenu, context: any, target: IAction[] | { p
}
}
function swapWithAltActionsIfPossible(actions: MenuItemAction[]): void {
for (let i = 0; i < actions.length; i++) {
if (actions[i].alt) {
actions[i] = actions[i].alt;
}
}
}
export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService): ActionItem {
if (action instanceof MenuItemAction) {
@ -86,8 +74,6 @@ const _altKey = new class extends Emitter<boolean> {
private _subscriptions: IDisposable[] = [];
private _value = false;
constructor() {
super();
@ -97,15 +83,6 @@ const _altKey = new class extends Emitter<boolean> {
this._subscriptions.push(domEvent(document.body, 'blur')(e => this.fire(false)));
}
fire(value: boolean) {
super.fire(value);
this._value = value;
}
get value() {
return this._value;
}
dispose() {
super.dispose();
this._subscriptions = dispose(this._subscriptions);

View file

@ -50,7 +50,7 @@ class Menu implements IMenu {
this._extensionService.onReady().then(_ => {
const menuItems = MenuRegistry.getMenuItems(id);
const keysFilter: { [key: string]: boolean } = Object.create(null);
const keysFilter = new Set<string>();
let group: MenuItemGroup;
menuItems.sort(Menu._compareMenuItems);
@ -71,7 +71,7 @@ class Menu implements IMenu {
// subscribe to context changes
this._disposables.push(this._contextKeyService.onDidChangeContext(keys => {
for (let k of keys) {
if (keysFilter[k]) {
if (keysFilter.has(k)) {
this._onDidChange.fire();
return;
}
@ -110,10 +110,10 @@ class Menu implements IMenu {
return result;
}
private static _fillInKbExprKeys(exp: ContextKeyExpr, set: { [k: string]: boolean }): void {
private static _fillInKbExprKeys(exp: ContextKeyExpr, set: Set<string>): void {
if (exp) {
for (let key of exp.keys()) {
set[key] = true;
set.add(key);
}
}
}

View file

@ -51,7 +51,7 @@ function isCommand(thing: any): thing is ICommand {
export const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry {
private _commands: { [id: string]: ICommand | ICommand[] } = Object.create(null);
private _commands = new Map<string, ICommand | ICommand[]>();
registerCommand(id: string, commandOrDesc: ICommandHandler | ICommand): IDisposable {
@ -86,18 +86,18 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
}
// find a place to store the command
const commandOrArray = this._commands[id];
const commandOrArray = this._commands.get(id);
if (commandOrArray === void 0) {
this._commands[id] = command;
this._commands.set(id, command);
} else if (Array.isArray(commandOrArray)) {
commandOrArray.unshift(command);
} else {
this._commands[id] = [command, commandOrArray];
this._commands.set(id, [command, commandOrArray]);
}
return {
dispose: () => {
const commandOrArray = this._commands[id];
const commandOrArray = this._commands.get(id);
if (Array.isArray(commandOrArray)) {
// remove from array, remove array
// if last element removed
@ -105,19 +105,19 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
if (idx >= 0) {
commandOrArray.splice(idx, 1);
if (commandOrArray.length === 0) {
delete this._commands[id];
this._commands.delete(id);
}
}
} else if (isCommand(commandOrArray)) {
// remove from map
delete this._commands[id];
this._commands.delete(id);
}
}
};
}
getCommand(id: string): ICommand {
const commandOrArray = this._commands[id];
const commandOrArray = this._commands.get(id);
if (Array.isArray(commandOrArray)) {
return commandOrArray[0];
} else {
@ -127,9 +127,9 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
getCommands(): ICommandsMap {
const result: ICommandsMap = Object.create(null);
for (let id in this._commands) {
result[id] = this.getCommand(id);
}
this._commands.forEach((value, key) => {
result[key] = this.getCommand(key);
});
return result;
}
};
@ -139,4 +139,4 @@ export const NullCommandService: ICommandService = {
executeCommand() {
return TPromise.as(undefined);
}
};
};

View file

@ -82,7 +82,7 @@ export function getConfigurationValue<T>(config: any, settingPath: string, defau
let current = config;
for (let i = 0; i < path.length; i++) {
current = current[path[i]];
if (typeof current === 'undefined') {
if (typeof current === 'undefined' || current === null) {
return undefined;
}
}

View file

@ -148,7 +148,7 @@ export function formatOptions(options: { [name: string]: string; }, columns: num
}
function wrapText(text: string, columns: number): string[] {
let lines = [];
let lines: string[] = [];
while (text.length) {
let index = text.length < columns ? text.length : text.lastIndexOf(' ', columns);
let line = text.slice(0, index).trim();

View file

@ -23,7 +23,7 @@ export interface ICommandAndKeybindingRule extends IKeybindingRule {
}
export interface IKeybindingsRegistry {
registerKeybindingRule(rule: IKeybindingRule);
registerKeybindingRule(rule: IKeybindingRule): void;
registerCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): void;
getDefaultKeybindings(): IKeybindingItem[];

View file

@ -25,6 +25,7 @@ export interface IWindowsService {
openDevTools(windowId: number): TPromise<void>;
toggleDevTools(windowId: number): TPromise<void>;
// TODO@joao: rename, shouldn't this be closeWindow?
// @ben: no, this actually leaves the window open but changes it to have no workspace opened
closeFolder(windowId: number): TPromise<void>;
toggleFullScreen(windowId: number): TPromise<void>;
setRepresentedFilename(windowId: number, fileName: string): TPromise<void>;
@ -40,8 +41,7 @@ export interface IWindowsService {
quit(): TPromise<void>;
// Global methods
// TODO@joao: rename, shouldn't this be openWindow?
windowOpen(paths: string[], forceNewWindow?: boolean): TPromise<void>;
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void>;
openNewWindow(): TPromise<void>;
showWindow(windowId: number): TPromise<void>;
getWindows(): TPromise<{ id: number; path: string; title: string; }[]>;
@ -87,7 +87,8 @@ export interface IWindowService {
}
export interface IWindowSettings {
openFilesInNewWindow: boolean;
openFilesInNewWindow: 'on' | 'off' | 'default';
openFoldersInNewWindow: 'on' | 'off' | 'default';
reopenFolders: 'all' | 'one' | 'none';
restoreFullscreen: boolean;
zoomLevel: number;

View file

@ -31,7 +31,7 @@ export interface IWindowsChannel extends IChannel {
call(command: 'setDocumentEdited', arg: [number, boolean]): TPromise<void>;
call(command: 'toggleMenuBar', arg: number): TPromise<void>;
call(command: 'quit'): TPromise<void>;
call(command: 'windowOpen', arg: [string[], boolean]): TPromise<void>;
call(command: 'openWindow', arg: [string[], { forceNewWindow?: boolean, forceReuseWindow?: boolean }]): TPromise<void>;
call(command: 'openNewWindow'): TPromise<void>;
call(command: 'showWindow', arg: number): TPromise<void>;
call(command: 'getWindows'): TPromise<{ id: number; path: string; title: string; }[]>;
@ -76,7 +76,7 @@ export class WindowsChannel implements IWindowsChannel {
case 'unmaximizeWindow': return this.service.unmaximizeWindow(arg);
case 'setDocumentEdited': return this.service.setDocumentEdited(arg[0], arg[1]);
case 'toggleMenuBar': return this.service.toggleMenuBar(arg);
case 'windowOpen': return this.service.windowOpen(arg[0], arg[1]);
case 'openWindow': return this.service.openWindow(arg[0], arg[1]);
case 'openNewWindow': return this.service.openNewWindow();
case 'showWindow': return this.service.showWindow(arg);
case 'getWindows': return this.service.getWindows();
@ -179,8 +179,8 @@ export class WindowsChannelClient implements IWindowsService {
return this.channel.call('quit');
}
windowOpen(paths: string[], forceNewWindow?: boolean): TPromise<void> {
return this.channel.call('windowOpen', [paths, forceNewWindow]);
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void> {
return this.channel.call('openWindow', [paths, options]);
}
openNewWindow(): TPromise<void> {

View file

@ -16,7 +16,7 @@ import { fromEventEmitter } from 'vs/base/node/event';
import { IURLService } from 'vs/platform/url/common/url';
// TODO@Joao: remove this dependency, move all implementation to this class
import { IWindowsMainService } from 'vs/code/electron-main/windows';
import { IWindowsMainService, OpenContext } from 'vs/code/electron-main/windows';
export class WindowsService implements IWindowsService, IDisposable {
@ -94,7 +94,7 @@ export class WindowsService implements IWindowsService, IDisposable {
const vscodeWindow = this.windowsMainService.getWindowById(windowId);
if (vscodeWindow) {
this.windowsMainService.open({ cli: this.environmentService.args, forceEmpty: true, windowToUse: vscodeWindow });
this.windowsMainService.open({ context: OpenContext.OTHER, cli: this.environmentService.args, forceEmpty: true, windowToUse: vscodeWindow });
}
return TPromise.as(null);
@ -198,17 +198,17 @@ export class WindowsService implements IWindowsService, IDisposable {
return TPromise.as(null);
}
windowOpen(paths: string[], forceNewWindow?: boolean): TPromise<void> {
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void> {
if (!paths || !paths.length) {
return TPromise.as(null);
}
this.windowsMainService.open({ cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: forceNewWindow });
this.windowsMainService.open({ context: OpenContext.OTHER, cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: options && options.forceNewWindow, forceReuseWindow: options && options.forceReuseWindow });
return TPromise.as(null);
}
openNewWindow(): TPromise<void> {
this.windowsMainService.openNewWindow();
this.windowsMainService.openNewWindow(OpenContext.OTHER);
return TPromise.as(null);
}
@ -271,7 +271,7 @@ export class WindowsService implements IWindowsService, IDisposable {
const cli = assign(Object.create(null), this.environmentService.args, { goto: true });
const pathsToOpen = [filePath];
this.windowsMainService.open({ cli, pathsToOpen });
this.windowsMainService.open({ context: OpenContext.OTHER, cli, pathsToOpen });
return TPromise.as(null);
}

View file

@ -466,7 +466,7 @@ function createExtensionPathIndex(extensionService: ExtHostExtensionService): TP
function defineAPI(factory: IExtensionApiFactory, extensionPaths: TrieMap<IExtensionDescription>): void {
// each extension is meant to get its own api implementation
const extApiImpl: { [id: string]: typeof vscode } = Object.create(null);
const extApiImpl = new Map<string, typeof vscode>();
let defaultApiImpl: typeof vscode;
const node_module = <any>require.__$__nodeRequire('module');
@ -479,9 +479,10 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TrieMap<IExten
// get extension id from filename and api for extension
const ext = extensionPaths.findSubstr(parent.filename);
if (ext) {
let apiImpl = extApiImpl[ext.id];
let apiImpl = extApiImpl.get(ext.id);
if (!apiImpl) {
apiImpl = extApiImpl[ext.id] = factory(ext);
apiImpl = factory(ext);
extApiImpl.set(ext.id, apiImpl);
}
return apiImpl;
}

View file

@ -26,7 +26,7 @@ interface CommandHandler {
export class ExtHostCommands extends ExtHostCommandsShape {
private _commands: { [n: string]: CommandHandler } = Object.create(null);
private _commands = new Map<string, CommandHandler>();
private _proxy: MainThreadCommandsShape;
private _extHostEditors: ExtHostEditors;
private _converter: CommandsConverter;
@ -52,15 +52,15 @@ export class ExtHostCommands extends ExtHostCommandsShape {
throw new Error('invalid id');
}
if (this._commands[id]) {
if (this._commands.has(id)) {
throw new Error('command with id already exists');
}
this._commands[id] = { callback, thisArg, description };
this._commands.set(id, { callback, thisArg, description });
this._proxy.$registerCommand(id);
return new extHostTypes.Disposable(() => {
if (delete this._commands[id]) {
if (this._commands.delete(id)) {
this._proxy.$unregisterCommand(id);
}
});
@ -68,7 +68,7 @@ export class ExtHostCommands extends ExtHostCommandsShape {
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
if (this._commands[id]) {
if (this._commands.has(id)) {
// we stay inside the extension host and support
// to pass any kind of parameters around
return this.$executeContributedCommand(id, ...args);
@ -97,7 +97,7 @@ export class ExtHostCommands extends ExtHostCommandsShape {
}
$executeContributedCommand<T>(id: string, ...args: any[]): Thenable<T> {
let command = this._commands[id];
let command = this._commands.get(id);
if (!command) {
return TPromise.wrapError<T>(`Contributed command '${id}' does not exist.`);
}
@ -139,12 +139,12 @@ export class ExtHostCommands extends ExtHostCommandsShape {
$getContributedCommandHandlerDescriptions(): TPromise<{ [id: string]: string | ICommandHandlerDescription }> {
const result: { [id: string]: string | ICommandHandlerDescription } = Object.create(null);
for (let id in this._commands) {
let {description} = this._commands[id];
this._commands.forEach((command, id) => {
let {description} = command;
if (description) {
result[id] = description;
}
}
});
return TPromise.as(result);
}
}
@ -212,4 +212,4 @@ export class CommandsConverter {
return this._commands.executeCommand(actualCmd.command, ...actualCmd.arguments);
}
}
}

View file

@ -15,13 +15,13 @@ import { DiagnosticSeverity } from './extHostTypes';
export class DiagnosticCollection implements vscode.DiagnosticCollection {
private static _maxDiagnosticsPerFile: number = 250;
private static readonly _maxDiagnosticsPerFile: number = 250;
private readonly _name: string;
private _name: string;
private _proxy: MainThreadDiagnosticsShape;
private _isDisposed = false;
private _data: { [uri: string]: vscode.Diagnostic[] } = Object.create(null);
private _data = new Map<string, vscode.Diagnostic[]>();
constructor(name: string, proxy: MainThreadDiagnosticsShape) {
this._name = name;
@ -66,7 +66,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
}
// update single row
this._data[first.toString()] = diagnostics;
this._data.set(first.toString(), diagnostics);
toSync = [first];
} else if (Array.isArray(first)) {
@ -83,19 +83,19 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
for (const {tuple} of sortedTuples) {
const [uri, diagnostics] = tuple;
if (!lastUri || uri.toString() !== lastUri.toString()) {
if (lastUri && this._data[lastUri.toString()].length === 0) {
delete this._data[lastUri.toString()];
if (lastUri && this._data.get(lastUri.toString()).length === 0) {
this._data.delete(lastUri.toString());
}
lastUri = uri;
toSync.push(uri);
this._data[uri.toString()] = [];
this._data.set(uri.toString(), []);
}
if (!diagnostics) {
// [Uri, undefined] means clear this
this._data[uri.toString()].length = 0;
this._data.get(uri.toString()).length = 0;
} else {
this._data[uri.toString()].push(...diagnostics);
this._data.get(uri.toString()).push(...diagnostics);
}
}
}
@ -104,7 +104,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
const entries: [URI, IMarkerData[]][] = [];
for (let uri of toSync) {
let marker: IMarkerData[];
let diagnostics = this._data[uri.toString()];
let diagnostics = this._data.get(uri.toString());
if (diagnostics) {
// no more than 250 diagnostics per file
@ -144,27 +144,27 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
delete(uri: vscode.Uri): void {
this._checkDisposed();
delete this._data[uri.toString()];
this._data.delete(uri.toString());
this._proxy.$changeMany(this.name, [[<URI>uri, undefined]]);
}
clear(): void {
this._checkDisposed();
this._data = Object.create(null);
this._data.clear();
this._proxy.$clear(this.name);
}
forEach(callback: (uri: URI, diagnostics: vscode.Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void {
this._checkDisposed();
for (let key in this._data) {
this._data.forEach((value, key) => {
let uri = URI.parse(key);
callback.apply(thisArg, [uri, this.get(uri), this]);
}
});
}
get(uri: URI): vscode.Diagnostic[] {
this._checkDisposed();
let result = this._data[uri.toString()];
let result = this._data.get(uri.toString());
if (Array.isArray(result)) {
return <vscode.Diagnostic[]>Object.freeze(result.slice(0));
}
@ -172,7 +172,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
has(uri: URI): boolean {
this._checkDisposed();
return Array.isArray(this._data[uri.toString()]);
return Array.isArray(this._data.get(uri.toString()));
}
private _checkDisposed() {

View file

@ -20,16 +20,14 @@ import { asWinJsPromise } from 'vs/base/common/async';
import { getWordAtText, ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
import { MainContext, MainThreadDocumentsShape, ExtHostDocumentsShape, IModelAddedData } from './extHost.protocol';
const _modeId2WordDefinition: {
[modeId: string]: RegExp;
} = Object.create(null);
const _modeId2WordDefinition = new Map<string, RegExp>();
function setWordDefinitionFor(modeId: string, wordDefinition: RegExp): void {
_modeId2WordDefinition[modeId] = wordDefinition;
_modeId2WordDefinition.set(modeId, wordDefinition);
}
function getWordDefinitionFor(modeId: string): RegExp {
return _modeId2WordDefinition[modeId];
return _modeId2WordDefinition.get(modeId);
}
export class ExtHostDocuments extends ExtHostDocumentsShape {
@ -48,9 +46,9 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
private _onDidSaveDocumentEventEmitter: Emitter<vscode.TextDocument>;
public onDidSaveDocument: Event<vscode.TextDocument>;
private _documentData: { [modelUri: string]: ExtHostDocumentData; };
private _documentLoader: { [modelUri: string]: TPromise<ExtHostDocumentData> };
private _documentContentProviders: { [handle: number]: vscode.TextDocumentContentProvider; };
private _documentData = new Map<string, ExtHostDocumentData>();
private _documentLoader = new Map<string, TPromise<ExtHostDocumentData>>();
private _documentContentProviders = new Map<number, vscode.TextDocumentContentProvider>();
private _proxy: MainThreadDocumentsShape;
@ -69,17 +67,11 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
this._onDidSaveDocumentEventEmitter = new Emitter<vscode.TextDocument>();
this.onDidSaveDocument = this._onDidSaveDocumentEventEmitter.event;
this._documentData = Object.create(null);
this._documentLoader = Object.create(null);
this._documentContentProviders = Object.create(null);
}
public getAllDocumentData(): ExtHostDocumentData[] {
const result: ExtHostDocumentData[] = [];
for (let key in this._documentData) {
result.push(this._documentData[key]);
}
this._documentData.forEach(data => result.push(data));
return result;
}
@ -87,7 +79,7 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
if (!resource) {
return;
}
const data = this._documentData[resource.toString()];
const data = this._documentData.get(resource.toString());
if (data) {
return data;
}
@ -95,21 +87,21 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
public ensureDocumentData(uri: URI): TPromise<ExtHostDocumentData> {
let cached = this._documentData[uri.toString()];
let cached = this._documentData.get(uri.toString());
if (cached) {
return TPromise.as(cached);
}
let promise = this._documentLoader[uri.toString()];
let promise = this._documentLoader.get(uri.toString());
if (!promise) {
promise = this._proxy.$tryOpenDocument(uri).then(() => {
delete this._documentLoader[uri.toString()];
return this._documentData[uri.toString()];
this._documentLoader.delete(uri.toString());
return this._documentData.get(uri.toString());
}, err => {
delete this._documentLoader[uri.toString()];
this._documentLoader.delete(uri.toString());
return TPromise.wrapError(err);
});
this._documentLoader[uri.toString()] = promise;
this._documentLoader.set(uri.toString(), promise);
}
return promise;
@ -122,13 +114,13 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
const handle = ExtHostDocuments._handlePool++;
this._documentContentProviders[handle] = provider;
this._documentContentProviders.set(handle, provider);
this._proxy.$registerTextContentProvider(handle, scheme);
let subscription: IDisposable;
if (typeof provider.onDidChange === 'function') {
subscription = provider.onDidChange(uri => {
if (this._documentData[uri.toString()]) {
if (this._documentData.has(uri.toString())) {
this.$provideTextDocumentContent(handle, <URI>uri).then(value => {
return this._proxy.$onVirtualDocumentChange(<URI>uri, value);
}, onUnexpectedError);
@ -136,7 +128,7 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
});
}
return new Disposable(() => {
if (delete this._documentContentProviders[handle]) {
if (this._documentContentProviders.delete(handle)) {
this._proxy.$unregisterTextContentProvider(handle);
}
if (subscription) {
@ -147,7 +139,7 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
}
$provideTextDocumentContent(handle: number, uri: URI): TPromise<string> {
const provider = this._documentContentProviders[handle];
const provider = this._documentContentProviders.get(handle);
if (!provider) {
return TPromise.wrapError<string>(`unsupported uri-scheme: ${uri.scheme}`);
}
@ -157,15 +149,15 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
public $acceptModelAdd(initData: IModelAddedData): void {
let data = new ExtHostDocumentData(this._proxy, initData.url, initData.value.lines, initData.value.EOL, initData.modeId, initData.versionId, initData.isDirty);
let key = data.document.uri.toString();
if (this._documentData[key]) {
if (this._documentData.has(key)) {
throw new Error('Document `' + key + '` already exists.');
}
this._documentData[key] = data;
this._documentData.set(key, data);
this._onDidAddDocumentEventEmitter.fire(data.document);
}
public $acceptModelModeChanged(strURL: string, oldModeId: string, newModeId: string): void {
let data = this._documentData[strURL];
let data = this._documentData.get(strURL);
// Treat a mode change as a remove + add
@ -175,33 +167,33 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
}
public $acceptModelSaved(strURL: string): void {
let data = this._documentData[strURL];
let data = this._documentData.get(strURL);
data._acceptIsDirty(false);
this._onDidSaveDocumentEventEmitter.fire(data.document);
}
public $acceptModelDirty(strURL: string): void {
let document = this._documentData[strURL];
let document = this._documentData.get(strURL);
document._acceptIsDirty(true);
}
public $acceptModelReverted(strURL: string): void {
let document = this._documentData[strURL];
let document = this._documentData.get(strURL);
document._acceptIsDirty(false);
}
public $acceptModelRemoved(strURL: string): void {
if (!this._documentData[strURL]) {
if (!this._documentData.has(strURL)) {
throw new Error('Document `' + strURL + '` does not exist.');
}
let data = this._documentData[strURL];
delete this._documentData[strURL];
let data = this._documentData.get(strURL);
this._documentData.delete(strURL);
this._onDidRemoveDocumentEventEmitter.fire(data.document);
data.dispose();
}
public $acceptModelChanged(strURL: string, events: editorCommon.IModelContentChangedEvent2[], isDirty: boolean): void {
let data = this._documentData[strURL];
let data = this._documentData.get(strURL);
data._acceptIsDirty(isDirty);
data.onEvents(events);
this._onDidChangeDocumentEventEmitter.fire({

View file

@ -30,7 +30,7 @@ export class ExtHostEditors extends ExtHostEditorsShape {
public onDidChangeTextEditorViewColumn: Event<vscode.TextEditorViewColumnChangeEvent>;
private _onDidChangeTextEditorViewColumn: Emitter<vscode.TextEditorViewColumnChangeEvent>;
private _editors: { [id: string]: ExtHostTextEditor };
private _editors: Map<string, ExtHostTextEditor>;
private _proxy: MainThreadEditorsShape;
private _onDidChangeActiveTextEditor: Emitter<vscode.TextEditor>;
private _onDidChangeVisibleTextEditors: Emitter<vscode.TextEditor[]>;
@ -56,17 +56,17 @@ export class ExtHostEditors extends ExtHostEditorsShape {
this._proxy = threadService.get(MainContext.MainThreadEditors);
this._onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor>();
this._onDidChangeVisibleTextEditors = new Emitter<vscode.TextEditor[]>();
this._editors = Object.create(null);
this._editors = new Map<string, ExtHostTextEditor>();
this._visibleEditorIds = [];
}
getActiveTextEditor(): vscode.TextEditor {
return this._editors[this._activeEditorId];
return this._editors.get(this._activeEditorId);
}
getVisibleTextEditors(): vscode.TextEditor[] {
return this._visibleEditorIds.map(id => this._editors[id]);
return this._visibleEditorIds.map(id => this._editors.get(id));
}
get onDidChangeActiveTextEditor(): Event<vscode.TextEditor> {
@ -79,7 +79,7 @@ export class ExtHostEditors extends ExtHostEditorsShape {
showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): TPromise<vscode.TextEditor> {
return this._proxy.$tryShowTextDocument(<URI>document.uri, TypeConverters.fromViewColumn(column), preserveFocus).then(id => {
let editor = this._editors[id];
let editor = this._editors.get(id);
if (editor) {
return editor;
} else {
@ -97,11 +97,11 @@ export class ExtHostEditors extends ExtHostEditorsShape {
$acceptTextEditorAdd(data: ITextEditorAddData): void {
let document = this._extHostDocuments.getDocumentData(data.document);
let newEditor = new ExtHostTextEditor(this._proxy, data.id, document, data.selections.map(TypeConverters.toSelection), data.options, TypeConverters.toViewColumn(data.editorPosition));
this._editors[data.id] = newEditor;
this._editors.set(data.id, newEditor);
}
$acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void {
let editor = this._editors[id];
let editor = this._editors.get(id);
editor._acceptOptions(opts);
this._onDidChangeTextEditorOptions.fire({
textEditor: editor,
@ -112,7 +112,7 @@ export class ExtHostEditors extends ExtHostEditorsShape {
$acceptSelectionsChanged(id: string, event: ISelectionChangeEvent): void {
const kind = TextEditorSelectionChangeKind.fromValue(event.source);
const selections = event.selections.map(TypeConverters.toSelection);
const textEditor = this._editors[id];
const textEditor = this._editors.get(id);
textEditor._acceptSelections(selections);
this._onDidChangeTextEditorSelection.fire({
textEditor,
@ -145,7 +145,7 @@ export class ExtHostEditors extends ExtHostEditorsShape {
$acceptEditorPositionData(data: ITextEditorPositionData): void {
for (let id in data) {
let textEditor = this._editors[id];
let textEditor = this._editors.get(id);
let viewColumn = TypeConverters.toViewColumn(data[id]);
if (textEditor.viewColumn !== viewColumn) {
textEditor._acceptViewColumn(viewColumn);
@ -165,9 +165,9 @@ export class ExtHostEditors extends ExtHostEditorsShape {
this.$acceptActiveEditorAndVisibleEditors(this._activeEditorId, newVisibleEditors);
}
let editor = this._editors[id];
let editor = this._editors.get(id);
editor.dispose();
delete this._editors[id];
this._editors.delete(id);
}
}

View file

@ -10,20 +10,20 @@ export class ExtHostHeapService extends ExtHostHeapServiceShape {
private static _idPool = 0;
private _data: { [n: number]: any } = Object.create(null);
private _data = new Map<number, any>();
keep(obj: any): number {
const id = ExtHostHeapService._idPool++;
this._data[id] = obj;
this._data.set(id, obj);
return id;
}
delete(id: number): boolean {
return this._data[id];
return this._data.delete(id);
}
get<T>(id: number): T {
return this._data[id];
return this._data.get(id);
}
$onGarbageCollection(ids: number[]): void {
@ -31,4 +31,4 @@ export class ExtHostHeapService extends ExtHostHeapServiceShape {
this.delete(id);
}
}
}
}

View file

@ -624,7 +624,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
private _commands: ExtHostCommands;
private _heapService: ExtHostHeapService;
private _diagnostics: ExtHostDiagnostics;
private _adapter: { [handle: number]: Adapter } = Object.create(null);
private _adapter = new Map<number, Adapter>();
constructor(
threadService: IThreadService,
@ -643,7 +643,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
private _createDisposable(handle: number): Disposable {
return new Disposable(() => {
delete this._adapter[handle];
this._adapter.delete(handle);
this._proxy.$unregister(handle);
});
}
@ -653,7 +653,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
}
private _withAdapter<A, R>(handle: number, ctor: { new (...args: any[]): A }, callback: (adapter: A) => TPromise<R>): TPromise<R> {
let adapter = this._adapter[handle];
let adapter = this._adapter.get(handle);
if (!(adapter instanceof ctor)) {
return TPromise.wrapError(new Error('no adapter found'));
}
@ -664,7 +664,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new OutlineAdapter(this._documents, provider);
this._adapter.set(handle, new OutlineAdapter(this._documents, provider));
this._proxy.$registerOutlineSupport(handle, selector);
return this._createDisposable(handle);
}
@ -679,7 +679,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
const handle = this._nextHandle();
const eventHandle = typeof provider.onDidChangeCodeLenses === 'function' ? this._nextHandle() : undefined;
this._adapter[handle] = new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider);
this._adapter.set(handle, new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider));
this._proxy.$registerCodeLensSupport(handle, selector, eventHandle);
let result = this._createDisposable(handle);
@ -703,7 +703,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new DefinitionAdapter(this._documents, provider);
this._adapter.set(handle, new DefinitionAdapter(this._documents, provider));
this._proxy.$registerDeclaractionSupport(handle, selector);
return this._createDisposable(handle);
}
@ -716,7 +716,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new HoverAdapter(this._documents, provider);
this._adapter.set(handle, new HoverAdapter(this._documents, provider));
this._proxy.$registerHoverProvider(handle, selector);
return this._createDisposable(handle);
}
@ -729,7 +729,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new DocumentHighlightAdapter(this._documents, provider);
this._adapter.set(handle, new DocumentHighlightAdapter(this._documents, provider));
this._proxy.$registerDocumentHighlightProvider(handle, selector);
return this._createDisposable(handle);
}
@ -742,7 +742,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new ReferenceAdapter(this._documents, provider);
this._adapter.set(handle, new ReferenceAdapter(this._documents, provider));
this._proxy.$registerReferenceSupport(handle, selector);
return this._createDisposable(handle);
}
@ -755,7 +755,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new QuickFixAdapter(this._documents, this._commands.converter, this._diagnostics, this._heapService, provider);
this._adapter.set(handle, new QuickFixAdapter(this._documents, this._commands.converter, this._diagnostics, this._heapService, provider));
this._proxy.$registerQuickFixSupport(handle, selector);
return this._createDisposable(handle);
}
@ -768,7 +768,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new DocumentFormattingAdapter(this._documents, provider);
this._adapter.set(handle, new DocumentFormattingAdapter(this._documents, provider));
this._proxy.$registerDocumentFormattingSupport(handle, selector);
return this._createDisposable(handle);
}
@ -779,7 +779,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new RangeFormattingAdapter(this._documents, provider);
this._adapter.set(handle, new RangeFormattingAdapter(this._documents, provider));
this._proxy.$registerRangeFormattingSupport(handle, selector);
return this._createDisposable(handle);
}
@ -790,7 +790,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new OnTypeFormattingAdapter(this._documents, provider);
this._adapter.set(handle, new OnTypeFormattingAdapter(this._documents, provider));
this._proxy.$registerOnTypeFormattingSupport(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}
@ -803,7 +803,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new NavigateTypeAdapter(provider, this._heapService);
this._adapter.set(handle, new NavigateTypeAdapter(provider, this._heapService));
this._proxy.$registerNavigateTypeSupport(handle);
return this._createDisposable(handle);
}
@ -820,7 +820,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new RenameAdapter(this._documents, provider);
this._adapter.set(handle, new RenameAdapter(this._documents, provider));
this._proxy.$registerRenameSupport(handle, selector);
return this._createDisposable(handle);
}
@ -833,7 +833,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider);
this._adapter.set(handle, new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider));
this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}
@ -850,7 +850,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new SignatureHelpAdapter(this._documents, provider);
this._adapter.set(handle, new SignatureHelpAdapter(this._documents, provider));
this._proxy.$registerSignatureHelpProvider(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}
@ -863,7 +863,7 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new LinkProviderAdapter(this._documents, provider);
this._adapter.set(handle, new LinkProviderAdapter(this._documents, provider));
this._proxy.$registerDocumentLinkProvider(handle, selector);
return this._createDisposable(handle);
}

View file

@ -465,7 +465,7 @@ export class Uri extends URI { }
export class WorkspaceEdit {
private _values: [Uri, TextEdit[]][] = [];
private _index: { [uri: string]: number } = Object.create(null);
private _index = new Map<string, number>();
replace(uri: Uri, range: Range, newText: string): void {
let edit = new TextEdit(range, newText);
@ -486,21 +486,21 @@ export class WorkspaceEdit {
}
has(uri: Uri): boolean {
return typeof this._index[uri.toString()] !== 'undefined';
return this._index.has(uri.toString());
}
set(uri: Uri, edits: TextEdit[]): void {
let idx = this._index[uri.toString()];
const idx = this._index.get(uri.toString());
if (typeof idx === 'undefined') {
let newLen = this._values.push([uri, edits]);
this._index[uri.toString()] = newLen - 1;
this._index.set(uri.toString(), newLen - 1);
} else {
this._values[idx][1] = edits;
}
}
get(uri: Uri): TextEdit[] {
let idx = this._index[uri.toString()];
let idx = this._index.get(uri.toString());
return typeof idx !== 'undefined' && this._values[idx][1];
}

View file

@ -579,7 +579,7 @@ export class MainThreadEditorsTracker {
}
private _findVisibleTextEditorIds(): string[] {
let result = [];
let result: string[] = [];
let modelUris = Object.keys(this._model2TextEditors);
for (let i = 0, len = modelUris.length; i < len; i++) {
let editors = this._model2TextEditors[modelUris[i]];

View file

@ -16,7 +16,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape {
private _proxy: ExtHostTreeExplorersShape;
constructor(
@IThreadService private threadService: IThreadService,
@IThreadService threadService: IThreadService,
@ITreeExplorerService private treeExplorerService: ITreeExplorerService,
@IMessageService private messageService: IMessageService,
@ICommandService private commandService: ICommandService

View file

@ -30,9 +30,9 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape {
constructor(
@ISearchService searchService: ISearchService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@ITextFileService textFileService,
@IWorkbenchEditorService editorService,
@ITextModelResolverService textModelResolverService,
@ITextFileService textFileService: ITextFileService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@ITextModelResolverService textModelResolverService: ITextModelResolverService,
@IFileService fileService: IFileService
) {
super();
@ -99,7 +99,7 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape {
}
}
return bulkEdit(this._fileService, this._textModelResolverService, codeEditor, edits)
return bulkEdit(this._textModelResolverService, codeEditor, edits, this._fileService)
.then(() => true);
}
}

View file

@ -92,7 +92,7 @@ export class ContributableActionProvider implements IActionProvider {
private registry: IActionBarRegistry;
constructor() {
this.registry = (<IActionBarRegistry>Registry.as(Extensions.Actionbar));
this.registry = Registry.as<IActionBarRegistry>(Extensions.Actionbar);
}
private toContext(tree: ITree, element: any): any {

View file

@ -89,5 +89,5 @@ const schema: IJSONSchema =
}
};
const jsonRegistry = <IJSONContributionRegistry>Registry.as(JSONExtensions.JSONContribution);
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema(schemaId, schema);

View file

@ -10,7 +10,7 @@ import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
import { Registry } from 'vs/platform/platform';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
import { IPartService, IZenModeOptions } from 'vs/workbench/services/part/common/partService';
import { IPartService } from 'vs/workbench/services/part/common/partService';
class ToggleZenMode extends Action {
@ -26,8 +26,8 @@ class ToggleZenMode extends Action {
this.enabled = !!this.partService;
}
public run(options: IZenModeOptions): TPromise<any> {
this.partService.toggleZenMode(options);
public run(): TPromise<any> {
this.partService.toggleZenMode();
return TPromise.as(null);
}
}

View file

@ -46,14 +46,10 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
return null;
}
public get telemetryService(): ITelemetryService {
protected get telemetryService(): ITelemetryService {
return this._telemetryService;
}
public get telemetryData(): any {
return this._telemetryData;
}
public get onTitleAreaUpdate(): Event<void> {
return this._onTitleAreaUpdate.event;
}
@ -102,7 +98,7 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
// Only submit telemetry data when not running from an integration test
if (this._telemetryService && this._telemetryService.publicLog) {
let eventName: string = 'compositeOpen';
const eventName: string = 'compositeOpen';
this._telemetryService.publicLog(eventName, { composite: this.getId() });
}
}
@ -114,7 +110,7 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
// Only submit telemetry data when not running from an integration test
if (this._telemetryService && this._telemetryService.publicLog) {
let eventName: string = 'compositeShown';
const eventName: string = 'compositeShown';
this._telemetryData.composite = this.getId();
this._telemetryService.publicLog(eventName, this._telemetryData);
}
@ -223,10 +219,10 @@ export abstract class CompositeDescriptor<T extends Composite> extends AsyncDesc
}
export abstract class CompositeRegistry<T extends Composite> {
private composits: CompositeDescriptor<T>[];
private composites: CompositeDescriptor<T>[];
constructor() {
this.composits = [];
this.composites = [];
}
protected registerComposite(descriptor: CompositeDescriptor<T>): void {
@ -234,25 +230,25 @@ export abstract class CompositeRegistry<T extends Composite> {
return;
}
this.composits.push(descriptor);
this.composites.push(descriptor);
}
public getComposite(id: string): CompositeDescriptor<T> {
return this.compositeById(id);
}
protected getComposits(): CompositeDescriptor<T>[] {
return this.composits.slice(0);
protected getComposites(): CompositeDescriptor<T>[] {
return this.composites.slice(0);
}
protected setComposits(compositsToSet: CompositeDescriptor<T>[]): void {
this.composits = compositsToSet;
protected setComposites(compositesToSet: CompositeDescriptor<T>[]): void {
this.composites = compositesToSet;
}
private compositeById(id: string): CompositeDescriptor<T> {
for (let i = 0; i < this.composits.length; i++) {
if (this.composits[i].id === id) {
return this.composits[i];
for (let i = 0; i < this.composites.length; i++) {
if (this.composites[i].id === id) {
return this.composites[i];
}
}

View file

@ -180,31 +180,23 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe
}
if (path) {
const basename = paths.basename(path);
const dotSegments = basename.split('.');
const basename = cssEscape(paths.basename(path).toLowerCase());
// Folders
if (isFolder) {
if (basename) {
classes.push(`${basename.toLowerCase()}-name-folder-icon`);
}
classes.push(`${basename}-name-folder-icon`);
}
// Files
else {
// Name
const name = dotSegments[0]; // file.txt => "file", .dockerfile => "", file.some.txt => "file"
if (name) {
classes.push(`${cssEscape(name.toLowerCase())}-name-file-icon`);
}
classes.push(`${basename}-name-file-icon`);
// Extension(s)
const extensions = dotSegments.splice(1);
if (extensions.length > 0) {
for (let i = 0; i < extensions.length; i++) {
classes.push(`${cssEscape(extensions.slice(i).join('.').toLowerCase())}-ext-file-icon`); // add each combination of all found extensions if more than one
}
const dotSegments = basename.split('.');
for (let i = 1; i < dotSegments.length; i++) {
classes.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one
}
// Configured Language
@ -215,7 +207,6 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe
}
}
}
return classes;
}

View file

@ -44,7 +44,7 @@ export class PanelRegistry extends CompositeRegistry<Panel> {
* Returns an array of registered panels known to the platform.
*/
public getPanels(): PanelDescriptor[] {
return this.getComposits();
return this.getComposites();
}
/**
@ -92,13 +92,14 @@ export abstract class TogglePanelAction extends Action {
}
private isPanelShowing(): boolean {
let panel = this.panelService.getActivePanel();
const panel = this.panelService.getActivePanel();
return panel && panel.getId() === this.panelId;
}
protected isPanelFocussed(): boolean {
let activePanel = this.panelService.getActivePanel();
let activeElement = document.activeElement;
const activePanel = this.panelService.getActivePanel();
const activeElement = document.activeElement;
return activePanel && activeElement && DOM.isAncestor(activeElement, (<Panel>activePanel).getContainer().getHTMLElement());
}

View file

@ -49,45 +49,31 @@ export abstract class Part extends WorkbenchComponent {
/**
* Subclasses override to provide a title area implementation.
*/
public createTitleArea(parent: Builder): Builder {
protected createTitleArea(parent: Builder): Builder {
return null;
}
/**
* Returns the title area container.
*/
public getTitleArea(): Builder {
return this.titleArea;
}
/**
* Subclasses override to provide a content area implementation.
*/
public createContentArea(parent: Builder): Builder {
protected createContentArea(parent: Builder): Builder {
return null;
}
/**
* Returns the content area container.
*/
public getContentArea(): Builder {
protected getContentArea(): Builder {
return this.contentArea;
}
/**
* Subclasses override to provide a status area implementation.
*/
public createStatusArea(parent: Builder): Builder {
protected createStatusArea(parent: Builder): Builder {
return null;
}
/**
* Returns the status area container.
*/
public getStatusArea(): Builder {
return this.statusArea;
}
/**
* Layout title, content and status area in the given dimension.
*/
@ -138,7 +124,7 @@ export class PartLayout {
}
public computeStyle(): void {
let containerStyle = this.container.getComputedStyle();
const containerStyle = this.container.getComputedStyle();
this.containerStyle = {
borderLeftWidth: parseInt(containerStyle.getPropertyValue('border-left-width'), 10),
borderRightWidth: parseInt(containerStyle.getPropertyValue('border-right-width'), 10),
@ -147,7 +133,7 @@ export class PartLayout {
};
if (this.titleArea) {
let titleStyle = this.titleArea.getComputedStyle();
const titleStyle = this.titleArea.getComputedStyle();
this.titleStyle = {
display: titleStyle.getPropertyValue('display'),
height: this.titleArea.getTotalSize().height
@ -155,7 +141,7 @@ export class PartLayout {
}
if (this.statusArea) {
let statusStyle = this.statusArea.getComputedStyle();
const statusStyle = this.statusArea.getComputedStyle();
this.statusStyle = {
display: statusStyle.getPropertyValue('display'),
height: this.statusArea.getTotalSize().height
@ -168,11 +154,11 @@ export class PartLayout {
this.computeStyle();
}
let width = dimension.width - (this.containerStyle.borderLeftWidth + this.containerStyle.borderRightWidth);
let height = dimension.height - (this.containerStyle.borderTopWidth + this.containerStyle.borderBottomWidth);
const width = dimension.width - (this.containerStyle.borderLeftWidth + this.containerStyle.borderRightWidth);
const height = dimension.height - (this.containerStyle.borderTopWidth + this.containerStyle.borderBottomWidth);
// Return the applied sizes to title, content and status
let sizes: Dimension[] = [];
const sizes: Dimension[] = [];
// Title Size: Width (Fill), Height (Variable)
let titleSize: Dimension;
@ -192,7 +178,7 @@ export class PartLayout {
}
// Content Size: Width (Fill), Height (Variable)
let contentSize = new Dimension(width, height - titleSize.height - statusSize.height);
const contentSize = new Dimension(width, height - titleSize.height - statusSize.height);
sizes.push(titleSize);
sizes.push(contentSize);

View file

@ -41,7 +41,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
private mapProgressServiceToComposite: { [compositeId: string]: IProgressService; };
private activeComposite: Composite;
private lastActiveCompositeId: string;
private instantiatedComposits: Composite[];
private instantiatedComposites: Composite[];
private titleLabel: Builder;
private toolBar: ToolBar;
private compositeLoaderPromises: { [compositeId: string]: TPromise<Composite>; };
@ -74,7 +74,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.mapActionsBindingToComposite = {};
this.mapProgressServiceToComposite = {};
this.activeComposite = null;
this.instantiatedComposits = [];
this.instantiatedComposites = [];
this.compositeLoaderPromises = {};
}
@ -152,9 +152,9 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected createComposite(id: string, isActive?: boolean): TPromise<Composite> {
// Check if composite is already created
for (let i = 0; i < this.instantiatedComposits.length; i++) {
if (this.instantiatedComposits[i].getId() === id) {
return TPromise.as(this.instantiatedComposits[i]);
for (let i = 0; i < this.instantiatedComposites.length; i++) {
if (this.instantiatedComposites[i].getId() === id) {
return TPromise.as(this.instantiatedComposites[i]);
}
}
@ -170,7 +170,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.mapProgressServiceToComposite[composite.getId()] = progressService;
// Remember as Instantiated
this.instantiatedComposits.push(composite);
this.instantiatedComposites.push(composite);
// Register to title area update events from the composite
this.instantiatedCompositeListeners.push(composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId())));
@ -181,7 +181,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
return composite;
});
// Report progress for slow loading composits
// Report progress for slow loading composites
progressService.showWhile(loaderPromise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */);
// Add to Promise Cache until Loaded
@ -207,7 +207,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
let createCompositePromise: TPromise<void>;
// Composits created for the first time
// Composites created for the first time
let compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()];
if (!compositeContainer) {
@ -228,7 +228,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
createCompositePromise = TPromise.as(null);
}
// Report progress for slow loading composits (but only if we did not create the composits before already)
// Report progress for slow loading composites (but only if we did not create the composites before already)
let progressService = this.mapProgressServiceToComposite[composite.getId()];
if (progressService && !compositeContainer) {
this.mapProgressServiceToComposite[composite.getId()].showWhile(createCompositePromise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */);
@ -351,7 +351,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
secondaryActions.push(...this.getSecondaryActions());
// From Contributions
let actionBarRegistry = <IActionBarRegistry>Registry.as(Extensions.Actionbar);
let actionBarRegistry = Registry.as<IActionBarRegistry>(Extensions.Actionbar);
primaryActions.push(...actionBarRegistry.getActionBarActionsForContext(this.actionContributionScope, composite));
secondaryActions.push(...actionBarRegistry.getSecondaryActionBarActionsForContext(this.actionContributionScope, composite));
@ -443,7 +443,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
// Check Registry
if (!actionItem) {
let actionBarRegistry = <IActionBarRegistry>Registry.as(Extensions.Actionbar);
let actionBarRegistry = Registry.as<IActionBarRegistry>(Extensions.Actionbar);
actionItem = actionBarRegistry.getActionItemForContext(this.actionContributionScope, ToolBarContext, action);
}
@ -486,7 +486,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
}
public shutdown(): void {
this.instantiatedComposits.forEach(i => i.shutdown());
this.instantiatedComposites.forEach(i => i.shutdown());
super.shutdown();
}
@ -496,11 +496,11 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.mapProgressServiceToComposite = null;
this.mapActionsBindingToComposite = null;
for (let i = 0; i < this.instantiatedComposits.length; i++) {
this.instantiatedComposits[i].dispose();
for (let i = 0; i < this.instantiatedComposites.length; i++) {
this.instantiatedComposites[i].dispose();
}
this.instantiatedComposits = [];
this.instantiatedComposites = [];
this.instantiatedCompositeListeners = dispose(this.instantiatedCompositeListeners);

View file

@ -30,7 +30,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
* This class is only intended to be subclassed and not instantiated.
*/
export abstract class BaseEditor extends Panel implements IEditor {
private _input: EditorInput;
protected _input: EditorInput;
private _options: EditorOptions;
private _position: Position;
@ -42,24 +42,10 @@ export abstract class BaseEditor extends Panel implements IEditor {
return this._input;
}
/**
* Returns the current input of this editor or null if none.
*/
public getInput(): EditorInput {
return this._input || null;
}
public get options(): EditorOptions {
return this._options;
}
/**
* Returns the current options of this editor or null if none.
*/
public getOptions(): EditorOptions {
return this._options || null;
}
/**
* Note: Clients should not call this method, the workbench calls this
* method. Calling it otherwise may result in unexpected behavior.

View file

@ -56,7 +56,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
}
public getTitle(): string {
return this.getInput() ? this.getInput().getName() : nls.localize('binaryDiffEditor', "Binary Diff Viewer");
return this.input ? this.input.getName() : nls.localize('binaryDiffEditor', "Binary Diff Viewer");
}
public createEditor(parent: Builder): void {
@ -92,7 +92,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
}
public setInput(input: EditorInput, options?: EditorOptions): TPromise<void> {
const oldInput = this.getInput();
const oldInput = this.input;
super.setInput(input, options);
// Detect options
@ -112,7 +112,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
}
// Assert that the current input is still the one we expect. This prevents a race condition when loading a diff takes long and another input was set meanwhile
if (!this.getInput() || this.getInput() !== input) {
if (!this.input || this.input !== input) {
return null;
}

View file

@ -41,7 +41,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
}
public getTitle(): string {
return this.getInput() ? this.getInput().getName() : nls.localize('binaryEditor', "Binary Viewer");
return this.input ? this.input.getName() : nls.localize('binaryEditor', "Binary Viewer");
}
public createEditor(parent: Builder): void {
@ -58,7 +58,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
}
public setInput(input: EditorInput, options?: EditorOptions): TPromise<void> {
const oldInput = this.getInput();
const oldInput = this.input;
super.setInput(input, options);
// Detect options
@ -78,7 +78,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
}
// Assert that the current input is still the one we expect. This prevents a race condition when loading takes long and another input was set meanwhile
if (!this.getInput() || this.getInput() !== input) {
if (!this.input || this.input !== input) {
return null;
}

View file

@ -14,7 +14,7 @@ import { StatusbarItemDescriptor, StatusbarAlignment, IStatusbarRegistry, Extens
import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorInput, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, SideBySideEditorInput } from 'vs/workbench/common/editor';
import { StringEditorInput } from 'vs/workbench/common/editor/stringEditorInput';
import { StringEditor } from 'vs/workbench/browser/parts/editor/stringEditor';
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
@ -44,10 +44,10 @@ import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommand
// Register String Editor
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
new EditorDescriptor(
StringEditor.ID,
TextResourceEditor.ID,
nls.localize('textEditor', "Text Editor"),
'vs/workbench/browser/parts/editor/stringEditor',
'StringEditor'
'vs/workbench/browser/parts/editor/textResourceEditor',
'TextResourceEditor'
),
[
new SyncDescriptor(StringEditorInput),

View file

@ -8,11 +8,11 @@ import * as types from 'vs/base/common/types';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { ActiveEditorMoveArguments, ActiveEditorMovePositioning, ActiveEditorMovePositioningBy, EditorCommands } from 'vs/workbench/common/editor';
import { ActiveEditorMoveArguments, ActiveEditorMovePositioning, ActiveEditorMovePositioningBy, EditorCommands, TextCompareEditorVisible } from 'vs/workbench/common/editor';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditor, Position, POSITIONS } from 'vs/platform/editor/common/editor';
import { EditorContextKeys } from 'vs/editor/common/editorCommon';
import { TextCompareEditorVisible, TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IMessageService, Severity, CloseAction } from 'vs/platform/message/common/message';
@ -210,7 +210,6 @@ function handleCommandDeprecations(): void {
'workbench.files.action.reopenClosedFile': 'workbench.action.reopenClosedEditor',
'workbench.files.action.workingFilesPicker': 'workbench.action.showAllEditors',
'workbench.action.cycleEditor': 'workbench.action.navigateEditorGroups',
'workbench.action.terminal.focus': 'workbench.action.focusPanel',
'workbench.action.showEditorsInLeftGroup': 'workbench.action.showEditorsInFirstGroup',
'workbench.action.showEditorsInCenterGroup': 'workbench.action.showEditorsInSecondGroup',
'workbench.action.showEditorsInRightGroup': 'workbench.action.showEditorsInThirdGroup',

View file

@ -22,7 +22,6 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import { Position, POSITIONS } from 'vs/platform/editor/common/editor';
import { IEditorGroupService, ITabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@ -139,7 +138,6 @@ export class EditorGroupsControl implements IEditorGroupsControl, IVerticalSashL
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@ITelemetryService private telemetryService: ITelemetryService,
@IConfigurationService private configurationService: IConfigurationService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IExtensionService private extensionService: IExtensionService,
@IInstantiationService private instantiationService: IInstantiationService,

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