mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
Merge remote-tracking branch 'origin/master' into tyriar/node-pty
This commit is contained in:
@@ -9,6 +9,8 @@
|
|||||||
a code editor with what developers need for their core edit-build-debug cycle. Code
|
a code editor with what developers need for their core edit-build-debug cycle. Code
|
||||||
provides comprehensive editing and debugging support, an extensibility model, and lightweight integration with existing tools.
|
provides comprehensive editing and debugging support, an extensibility model, and lightweight integration with existing tools.
|
||||||
|
|
||||||
|
VS Code is updated monthly with new features and bug fixes. You can download it for Windows, Mac and Linux on [VS Code's website](https://code.visualstudio.com/Download). To get the latest releases everyday, you can install the [Insiders version of VS Code](https://code.visualstudio.com/insiders). This builds from the master branch and is updated at least daily.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="VS Code in action" src="https://cloud.githubusercontent.com/assets/11839736/16642200/6624dde0-43bd-11e6-8595-c81885ba0dc2.png">
|
<img alt="VS Code in action" src="https://cloud.githubusercontent.com/assets/11839736/16642200/6624dde0-43bd-11e6-8595-c81885ba0dc2.png">
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ const nodeModules = ['electron', 'original-fs']
|
|||||||
// Build
|
// Build
|
||||||
|
|
||||||
const builtInExtensions = [
|
const builtInExtensions = [
|
||||||
{ name: 'ms-vscode.node-debug', version: '1.9.0' },
|
{ name: 'ms-vscode.node-debug', version: '1.9.1' },
|
||||||
{ name: 'ms-vscode.node-debug2', version: '1.9.0' }
|
{ name: 'ms-vscode.node-debug2', version: '1.9.1' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const vscodeEntryPoints = _.flatten([
|
const vscodeEntryPoints = _.flatten([
|
||||||
@@ -110,7 +110,7 @@ const config = {
|
|||||||
version: packageJson.electronVersion,
|
version: packageJson.electronVersion,
|
||||||
productAppName: product.nameLong,
|
productAppName: product.nameLong,
|
||||||
companyName: 'Microsoft Corporation',
|
companyName: 'Microsoft Corporation',
|
||||||
copyright: 'Copyright (C) 2016 Microsoft. All rights reserved',
|
copyright: 'Copyright (C) 2017 Microsoft. All rights reserved',
|
||||||
darwinIcon: 'resources/darwin/code.icns',
|
darwinIcon: 'resources/darwin/code.icns',
|
||||||
darwinBundleIdentifier: product.darwinBundleIdentifier,
|
darwinBundleIdentifier: product.darwinBundleIdentifier,
|
||||||
darwinApplicationCategoryType: 'public.app-category.developer-tools',
|
darwinApplicationCategoryType: 'public.app-category.developer-tools',
|
||||||
|
|||||||
+15
-15
@@ -188,21 +188,21 @@ function format(text) {
|
|||||||
}
|
}
|
||||||
function getDefaultOptions() {
|
function getDefaultOptions() {
|
||||||
return {
|
return {
|
||||||
IndentSize: 4,
|
indentSize: 4,
|
||||||
TabSize: 4,
|
tabSize: 4,
|
||||||
NewLineCharacter: '\r\n',
|
newLineCharacter: '\r\n',
|
||||||
ConvertTabsToSpaces: true,
|
convertTabsToSpaces: true,
|
||||||
IndentStyle: ts.IndentStyle.Block,
|
indentStyle: ts.IndentStyle.Block,
|
||||||
InsertSpaceAfterCommaDelimiter: true,
|
insertSpaceAfterCommaDelimiter: true,
|
||||||
InsertSpaceAfterSemicolonInForStatements: true,
|
insertSpaceAfterSemicolonInForStatements: true,
|
||||||
InsertSpaceBeforeAndAfterBinaryOperators: true,
|
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||||
InsertSpaceAfterKeywordsInControlFlowStatements: true,
|
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true,
|
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true,
|
||||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
placeOpenBraceOnNewLineForFunctions: false,
|
||||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -217,22 +217,22 @@ function format(text:string): string {
|
|||||||
|
|
||||||
function getDefaultOptions(): ts.FormatCodeOptions {
|
function getDefaultOptions(): ts.FormatCodeOptions {
|
||||||
return {
|
return {
|
||||||
IndentSize: 4,
|
indentSize: 4,
|
||||||
TabSize: 4,
|
tabSize: 4,
|
||||||
NewLineCharacter: '\r\n',
|
newLineCharacter: '\r\n',
|
||||||
ConvertTabsToSpaces: true,
|
convertTabsToSpaces: true,
|
||||||
IndentStyle: ts.IndentStyle.Block,
|
indentStyle: ts.IndentStyle.Block,
|
||||||
|
|
||||||
InsertSpaceAfterCommaDelimiter: true,
|
insertSpaceAfterCommaDelimiter: true,
|
||||||
InsertSpaceAfterSemicolonInForStatements: true,
|
insertSpaceAfterSemicolonInForStatements: true,
|
||||||
InsertSpaceBeforeAndAfterBinaryOperators: true,
|
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||||
InsertSpaceAfterKeywordsInControlFlowStatements: true,
|
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true,
|
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true,
|
||||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
placeOpenBraceOnNewLineForFunctions: false,
|
||||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,16 @@
|
|||||||
"default": true,
|
"default": true,
|
||||||
"description": "%html.suggest.html5.desc%"
|
"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": {
|
"html.trace.server": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
@@ -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.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.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.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."
|
||||||
}
|
}
|
||||||
@@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType } from 'vscode-languageserver';
|
import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType } from 'vscode-languageserver';
|
||||||
import { DocumentContext } from 'vscode-html-languageservice';
|
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 { getLanguageModes, LanguageModes } from './modes/languageModes';
|
||||||
|
|
||||||
|
import { format } from './modes/formatting';
|
||||||
|
|
||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import uri from 'vscode-uri';
|
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.
|
// The settings have changed. Is send on server activation as well.
|
||||||
connection.onDidChangeConfiguration((change) => {
|
connection.onDidChangeConfiguration((change) => {
|
||||||
settings = change.settings;
|
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 => {
|
languageModes.getAllModes().forEach(m => {
|
||||||
if (m.configure) {
|
if (m.configure) {
|
||||||
@@ -115,7 +126,7 @@ function triggerValidation(textDocument: TextDocument): void {
|
|||||||
function validateTextDocument(textDocument: TextDocument): void {
|
function validateTextDocument(textDocument: TextDocument): void {
|
||||||
let diagnostics: Diagnostic[] = [];
|
let diagnostics: Diagnostic[] = [];
|
||||||
languageModes.getAllModesInDocument(textDocument).forEach(mode => {
|
languageModes.getAllModesInDocument(textDocument).forEach(mode => {
|
||||||
if (mode.doValidation) {
|
if (mode.doValidation && validation[mode.getId()]) {
|
||||||
pushAll(diagnostics, mode.doValidation(textDocument));
|
pushAll(diagnostics, mode.doValidation(textDocument));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -201,18 +212,11 @@ connection.onSignatureHelp(signatureHelpParms => {
|
|||||||
|
|
||||||
connection.onDocumentRangeFormatting(formatParams => {
|
connection.onDocumentRangeFormatting(formatParams => {
|
||||||
let document = documents.get(formatParams.textDocument.uri);
|
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 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 };
|
let enabledModes = { css: !unformattedTags.match(/\bstyle\b/), javascript: !unformattedTags.match(/\bscript\b/) };
|
||||||
ranges.forEach(r => {
|
|
||||||
let mode = r.mode;
|
return format(languageModes, document, formatParams.range, formatParams.options, enabledModes);
|
||||||
if (mode && mode.format && enabledModes[mode.getId()] && !r.attributeValue) {
|
|
||||||
let edits = mode.format(document, r, formatParams.options);
|
|
||||||
pushAll(result, edits);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.onDocumentLinks(documentLinkParam => {
|
connection.onDocumentLinks(documentLinkParam => {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService): LanguageM
|
|||||||
settings = options && options.html;
|
settings = options && options.html;
|
||||||
},
|
},
|
||||||
doComplete(document: TextDocument, position: Position) {
|
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);
|
return htmlLanguageService.doComplete(document, position, htmlDocuments.get(document), options);
|
||||||
},
|
},
|
||||||
doHover(document: TextDocument, position: Position) {
|
doHover(document: TextDocument, position: Position) {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import * as assert from 'assert';
|
|||||||
import { getLanguageModes } from '../modes/languageModes';
|
import { getLanguageModes } from '../modes/languageModes';
|
||||||
import { TextDocument, Range, TextEdit, FormattingOptions } from 'vscode-languageserver-types';
|
import { TextDocument, Range, TextEdit, FormattingOptions } from 'vscode-languageserver-types';
|
||||||
|
|
||||||
|
import { format } from '../modes/formatting';
|
||||||
|
|
||||||
suite('HTML Embedded Formatting', () => {
|
suite('HTML Embedded Formatting', () => {
|
||||||
|
|
||||||
function assertFormat(value: string, expected: string, options?: any): void {
|
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 range = Range.create(document.positionAt(rangeStartOffset), document.positionAt(rangeEndOffset));
|
||||||
let formatOptions = FormattingOptions.create(2, true);
|
let formatOptions = FormattingOptions.create(2, true);
|
||||||
|
|
||||||
let ranges = languageModes.getModesInRange(document, range);
|
let result = format(languageModes, document, range, formatOptions, { css: true, javascript: true });
|
||||||
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 actual = applyEdits(document, result);
|
let actual = applyEdits(document, result);
|
||||||
assert.equal(actual, expected);
|
assert.equal(actual, expected);
|
||||||
}
|
}
|
||||||
@@ -52,38 +47,38 @@ suite('HTML Embedded Formatting', () => {
|
|||||||
|
|
||||||
test('HTML & Scripts', function (): any {
|
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></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>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</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 </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 </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>');
|
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 {
|
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 {
|
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 {
|
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 {
|
test('EndWithNewline', function (): any {
|
||||||
let options = {
|
let options = {
|
||||||
html: {
|
html: {
|
||||||
format: {
|
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>\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>|<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);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1584,8 +1584,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "````application/json",
|
"c": "````",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.definition.fenced_code.markdown.markup.punctuation",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1594,9 +1594,20 @@
|
|||||||
"hc_black": ".hc-black .token rgb(255, 255, 255)"
|
"hc_black": ".hc-black .token rgb(255, 255, 255)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"c": "application/json",
|
||||||
|
"r": {
|
||||||
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
|
"dark_vs": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
|
"hc_black": ".hc-black .token rgb(255, 255, 255)",
|
||||||
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
|
"light_vs": ".vs .token rgb(0, 0, 0)"
|
||||||
|
},
|
||||||
|
"t": "block.fenced_code.language.markdown.markup"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"c": " { value: [\"or with a mime type\"] }",
|
"c": " { value: [\"or with a mime type\"] }",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.fenced_code.markdown.markup",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1607,7 +1618,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "````",
|
"c": "````",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.definition.fenced_code.markdown.markup.punctuation",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1827,7 +1838,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "~~~",
|
"c": "~~~",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.definition.fenced_code.markdown.markup.punctuation",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1838,7 +1849,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "// Markdown extra adds un-indented code blocks too",
|
"c": "// Markdown extra adds un-indented code blocks too",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.fenced_code.markdown.markup",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1848,74 +1859,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "if (this",
|
"c": "if (this_is_more_code == true && !indented) {",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.fenced_code.markdown.markup",
|
||||||
"r": {
|
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
|
||||||
"dark_vs": ".vs-dark .token rgb(212, 212, 212)",
|
|
||||||
"light_vs": ".vs .token rgb(0, 0, 0)",
|
|
||||||
"hc_black": ".hc-black .token rgb(255, 255, 255)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"c": "_",
|
|
||||||
"t": "definition.italic.markdown.markup.meta.paragraph.punctuation",
|
|
||||||
"r": {
|
|
||||||
"dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.markup.italic rgb(212, 212, 212)",
|
|
||||||
"light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.markup.italic rgb(0, 0, 0)",
|
|
||||||
"dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.markup.italic rgb(212, 212, 212)",
|
|
||||||
"light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.markup.italic rgb(0, 0, 0)",
|
|
||||||
"hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.markup.italic rgb(255, 255, 255)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"c": "is",
|
|
||||||
"t": "italic.markdown.markup.meta.paragraph",
|
|
||||||
"r": {
|
|
||||||
"dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.markup.italic rgb(212, 212, 212)",
|
|
||||||
"light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.markup.italic rgb(0, 0, 0)",
|
|
||||||
"dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.markup.italic rgb(212, 212, 212)",
|
|
||||||
"light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.markup.italic rgb(0, 0, 0)",
|
|
||||||
"hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.markup.italic rgb(255, 255, 255)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"c": "_",
|
|
||||||
"t": "definition.italic.markdown.markup.meta.paragraph.punctuation",
|
|
||||||
"r": {
|
|
||||||
"dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.markup.italic rgb(212, 212, 212)",
|
|
||||||
"light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.markup.italic rgb(0, 0, 0)",
|
|
||||||
"dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.markup.italic rgb(212, 212, 212)",
|
|
||||||
"light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.markup.italic rgb(0, 0, 0)",
|
|
||||||
"hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.markup.italic rgb(255, 255, 255)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"c": "more_code == true ",
|
|
||||||
"t": "markdown.meta.paragraph",
|
|
||||||
"r": {
|
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
|
||||||
"dark_vs": ".vs-dark .token rgb(212, 212, 212)",
|
|
||||||
"light_vs": ".vs .token rgb(0, 0, 0)",
|
|
||||||
"hc_black": ".hc-black .token rgb(255, 255, 255)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"c": "&&",
|
|
||||||
"t": "markdown.meta.other.paragraph.valid-ampersand",
|
|
||||||
"r": {
|
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
|
||||||
"dark_vs": ".vs-dark .token rgb(212, 212, 212)",
|
|
||||||
"light_vs": ".vs .token rgb(0, 0, 0)",
|
|
||||||
"hc_black": ".hc-black .token rgb(255, 255, 255)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"c": " !indented) {",
|
|
||||||
"t": "markdown.meta.paragraph",
|
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1926,7 +1871,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": " // tild wrapped code blocks, also not indented",
|
"c": " // tild wrapped code blocks, also not indented",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.fenced_code.markdown.markup",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1937,7 +1882,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "}",
|
"c": "}",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.fenced_code.markdown.markup",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
@@ -1948,7 +1893,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "~~~",
|
"c": "~~~",
|
||||||
"t": "markdown.meta.paragraph",
|
"t": "block.definition.fenced_code.markdown.markup.punctuation",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
"dark_plus": ".vs-dark .token rgb(212, 212, 212)",
|
||||||
"light_plus": ".vs .token rgb(0, 0, 0)",
|
"light_plus": ".vs .token rgb(0, 0, 0)",
|
||||||
|
|||||||
@@ -99,6 +99,11 @@
|
|||||||
"default": true,
|
"default": true,
|
||||||
"description": "%typescript.check.tscVersion%"
|
"description": "%typescript.check.tscVersion%"
|
||||||
},
|
},
|
||||||
|
"typescript.referencesCodeLens.enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "%typescript.referencesCodeLens.enabled%"
|
||||||
|
},
|
||||||
"typescript.tsserver.trace": {
|
"typescript.tsserver.trace": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
@@ -24,5 +24,6 @@
|
|||||||
"format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Defines space handling after opening and before closing JSX expression braces. Requires TypeScript >= 2.0.6.",
|
"format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Defines space handling after opening and before closing JSX expression braces. Requires TypeScript >= 2.0.6.",
|
||||||
"format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.",
|
"format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.",
|
||||||
"format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.",
|
"format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.",
|
||||||
"javascript.validate.enable": "Enable/disable JavaScript validation."
|
"javascript.validate.enable": "Enable/disable JavaScript validation.",
|
||||||
|
"typescript.referencesCodeLens.enabled": "Enable/disable the references code lens"
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, Uri, workspace, WorkspaceEdit, TextEdit } from 'vscode';
|
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, Uri, workspace, WorkspaceEdit, TextEdit, Position } from 'vscode';
|
||||||
|
|
||||||
import * as Proto from '../protocol';
|
import * as Proto from '../protocol';
|
||||||
import { ITypescriptServiceClient } from '../typescriptService';
|
import { ITypescriptServiceClient } from '../typescriptService';
|
||||||
@@ -46,7 +46,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider
|
|||||||
public provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): Thenable<Command[]> {
|
public provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): Thenable<Command[]> {
|
||||||
const file = this.client.asAbsolutePath(document.uri);
|
const file = this.client.asAbsolutePath(document.uri);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve<Command[]>([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const source: Source = {
|
const source: Source = {
|
||||||
@@ -99,11 +99,29 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider
|
|||||||
private onCodeAction(source: Source, workspaceEdit: WorkspaceEdit) {
|
private onCodeAction(source: Source, workspaceEdit: WorkspaceEdit) {
|
||||||
workspace.applyEdit(workspaceEdit).then(success => {
|
workspace.applyEdit(workspaceEdit).then(success => {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return Promise.reject(null);
|
return Promise.reject<boolean>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let firstEdit: TextEdit | null = null;
|
||||||
|
for (const [uri, edits] of workspaceEdit.entries()) {
|
||||||
|
if (uri.fsPath === source.uri.fsPath) {
|
||||||
|
firstEdit = edits[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstEdit) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newLines = firstEdit.newText.match(/\n/g);
|
||||||
|
const editedRange = new Range(
|
||||||
|
new Position(firstEdit.range.start.line, 0),
|
||||||
|
new Position(firstEdit.range.end.line + 1 + (newLines ? newLines.length : 0), 0));
|
||||||
|
|
||||||
// TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/12249
|
// TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/12249
|
||||||
// apply formatting to the source range until TS returns formatted results
|
// apply formatting to the source range until TS returns formatted results
|
||||||
return commands.executeCommand('vscode.executeFormatRangeProvider', source.uri, source.range, {}).then((edits: TextEdit[]) => {
|
return commands.executeCommand('vscode.executeFormatRangeProvider', source.uri, editedRange, {}).then((edits: TextEdit[]) => {
|
||||||
if (!edits || !edits.length) {
|
if (!edits || !edits.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||||||
|
|
||||||
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise<CompletionItem[]> {
|
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise<CompletionItem[]> {
|
||||||
if (this.typingsStatus.isAcquiringTypings) {
|
if (this.typingsStatus.isAcquiringTypings) {
|
||||||
return Promise.reject({
|
return Promise.reject<CompletionItem[]>({
|
||||||
label: localize('acquiringTypingsLabel', 'Acquiring typings...'),
|
label: localize('acquiringTypingsLabel', 'Acquiring typings...'),
|
||||||
detail: localize('acquiringTypingsDetail', 'Acquiring typings definitions for IntelliSense.')
|
detail: localize('acquiringTypingsDetail', 'Acquiring typings definitions for IntelliSense.')
|
||||||
});
|
});
|
||||||
@@ -220,7 +220,6 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||||||
// Don't complete function calls inside of destructive assigments or imports
|
// Don't complete function calls inside of destructive assigments or imports
|
||||||
return this.client.execute('quickinfo', args).then(infoResponse => {
|
return this.client.execute('quickinfo', args).then(infoResponse => {
|
||||||
const info = infoResponse.body;
|
const info = infoResponse.body;
|
||||||
console.log(info && info.kind);
|
|
||||||
switch (info && info.kind) {
|
switch (info && info.kind) {
|
||||||
case 'var':
|
case 'var':
|
||||||
case 'let':
|
case 'let':
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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 { CodeLensProvider, CodeLens, CancellationToken, TextDocument, Range, Uri, Location, Position, workspace, WorkspaceConfiguration } from 'vscode';
|
||||||
|
import * as Proto from '../protocol';
|
||||||
|
import * as PConst from '../protocol.const';
|
||||||
|
|
||||||
|
import { ITypescriptServiceClient } from '../typescriptService';
|
||||||
|
|
||||||
|
import * as nls from 'vscode-nls';
|
||||||
|
let localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
|
|
||||||
|
class ReferencesCodeLens extends CodeLens {
|
||||||
|
public document: Uri;
|
||||||
|
public file: string;
|
||||||
|
|
||||||
|
constructor(document: Uri, file: string, range: Range) {
|
||||||
|
super(range);
|
||||||
|
this.document = document;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TypeScriptReferencesCodeLensProvider implements CodeLensProvider {
|
||||||
|
private client: ITypescriptServiceClient;
|
||||||
|
private enabled = false;
|
||||||
|
|
||||||
|
constructor(client: ITypescriptServiceClient) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateConfiguration(config: WorkspaceConfiguration): void {
|
||||||
|
let typeScriptConfig = workspace.getConfiguration('typescript');
|
||||||
|
this.enabled = typeScriptConfig.get('referencesCodeLens.enabled', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
provideCodeLenses(document: TextDocument, token: CancellationToken): Promise<CodeLens[]> {
|
||||||
|
if (!this.enabled) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filepath = this.client.asAbsolutePath(document.uri);
|
||||||
|
if (!filepath) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
return this.client.execute('navtree', { file: filepath }, token).then(response => {
|
||||||
|
const tree = response.body;
|
||||||
|
const referenceableSpans: Range[] = [];
|
||||||
|
if (tree && tree.childItems) {
|
||||||
|
tree.childItems.forEach(item => this.extractReferenceableSymbols(document, item, referenceableSpans));
|
||||||
|
}
|
||||||
|
return Promise.resolve(referenceableSpans.map(span => new ReferencesCodeLens(document.uri, filepath, span)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise<CodeLens> {
|
||||||
|
const codeLens = inputCodeLens as ReferencesCodeLens;
|
||||||
|
if (!codeLens.document) {
|
||||||
|
return Promise.reject<CodeLens>(codeLens);
|
||||||
|
}
|
||||||
|
const args: Proto.FileLocationRequestArgs = {
|
||||||
|
file: codeLens.file,
|
||||||
|
line: codeLens.range.start.line + 1,
|
||||||
|
offset: codeLens.range.start.character + 1
|
||||||
|
};
|
||||||
|
return this.client.execute('references', args, token).then(response => {
|
||||||
|
if (response && response.body) {
|
||||||
|
const referenceCount = Math.max(0, response.body.refs.length - 1);
|
||||||
|
const locations = response.body.refs.map(reference =>
|
||||||
|
new Location(Uri.file(reference.file),
|
||||||
|
new Range(
|
||||||
|
new Position(reference.start.line - 1, reference.start.offset - 1),
|
||||||
|
new Position(reference.end.line - 1, reference.end.offset - 1))));
|
||||||
|
|
||||||
|
codeLens.command = {
|
||||||
|
title: referenceCount + ' ' + (referenceCount === 1 ? localize('oneReferenceLabel', 'reference') : localize('manyReferenceLabel', 'references')),
|
||||||
|
command: 'editor.action.showReferences',
|
||||||
|
arguments: [codeLens.document, codeLens.range.start, locations]
|
||||||
|
};
|
||||||
|
return Promise.resolve(codeLens);
|
||||||
|
}
|
||||||
|
return Promise.reject(codeLens);
|
||||||
|
}).catch(() => {
|
||||||
|
codeLens.command = {
|
||||||
|
title: localize('referenceErrorLabel', 'Could not determine references'),
|
||||||
|
command: ''
|
||||||
|
};
|
||||||
|
return Promise.resolve(codeLens);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractReferenceableSymbols(document: TextDocument, item: Proto.NavigationTree, results: Range[]) {
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const span = item.spans && item.spans[0];
|
||||||
|
if (span) {
|
||||||
|
const range = new Range(
|
||||||
|
new Position(span.start.line - 1, span.start.offset - 1),
|
||||||
|
new Position(span.end.line - 1, span.end.offset - 1));
|
||||||
|
|
||||||
|
// TODO: TS currently requires the position for 'references 'to be inside of the identifer
|
||||||
|
// Massage the range to make sure this is the case
|
||||||
|
const text = document.getText(range);
|
||||||
|
|
||||||
|
switch (item.kind) {
|
||||||
|
case PConst.Kind.const:
|
||||||
|
case PConst.Kind.let:
|
||||||
|
case PConst.Kind.variable:
|
||||||
|
case PConst.Kind.function:
|
||||||
|
// Only show references for exported variables
|
||||||
|
if (!item.kindModifiers.match(/\bexport\b/)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fallthrough
|
||||||
|
|
||||||
|
case PConst.Kind.memberFunction:
|
||||||
|
case PConst.Kind.memberVariable:
|
||||||
|
case PConst.Kind.memberGetAccessor:
|
||||||
|
case PConst.Kind.memberSetAccessor:
|
||||||
|
case PConst.Kind.constructorImplementation:
|
||||||
|
case PConst.Kind.class:
|
||||||
|
case PConst.Kind.interface:
|
||||||
|
case PConst.Kind.type:
|
||||||
|
case PConst.Kind.enum:
|
||||||
|
const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${item.text}`, 'g');
|
||||||
|
const match = identifierMatch.exec(text);
|
||||||
|
const start = match ? match.index + match[1].length : 0;
|
||||||
|
results.push(new Range(
|
||||||
|
new Position(range.start.line, range.start.character + start),
|
||||||
|
new Position(range.start.line, range.start.character + start + item.text.length)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(item.childItems || []).forEach(item => this.extractReferenceableSymbols(document, item, results));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -35,6 +35,7 @@ import BufferSyncSupport from './features/bufferSyncSupport';
|
|||||||
import CompletionItemProvider from './features/completionItemProvider';
|
import CompletionItemProvider from './features/completionItemProvider';
|
||||||
import WorkspaceSymbolProvider from './features/workspaceSymbolProvider';
|
import WorkspaceSymbolProvider from './features/workspaceSymbolProvider';
|
||||||
import CodeActionProvider from './features/codeActionProvider';
|
import CodeActionProvider from './features/codeActionProvider';
|
||||||
|
import ReferenceCodeLensProvider from './features/referencesCodeLensProvider';
|
||||||
|
|
||||||
import * as BuildStatus from './utils/buildStatus';
|
import * as BuildStatus from './utils/buildStatus';
|
||||||
import * as ProjectStatus from './utils/projectStatus';
|
import * as ProjectStatus from './utils/projectStatus';
|
||||||
@@ -107,6 +108,7 @@ class LanguageProvider {
|
|||||||
private formattingProvider: FormattingProvider;
|
private formattingProvider: FormattingProvider;
|
||||||
private formattingProviderRegistration: Disposable | null;
|
private formattingProviderRegistration: Disposable | null;
|
||||||
private typingsStatus: TypingsStatus;
|
private typingsStatus: TypingsStatus;
|
||||||
|
private referenceCodeLensProvider: ReferenceCodeLensProvider;
|
||||||
|
|
||||||
private _validate: boolean;
|
private _validate: boolean;
|
||||||
|
|
||||||
@@ -156,6 +158,12 @@ class LanguageProvider {
|
|||||||
this.formattingProviderRegistration = languages.registerDocumentRangeFormattingEditProvider(this.description.modeIds, this.formattingProvider);
|
this.formattingProviderRegistration = languages.registerDocumentRangeFormattingEditProvider(this.description.modeIds, this.formattingProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.referenceCodeLensProvider = new ReferenceCodeLensProvider(client);
|
||||||
|
this.referenceCodeLensProvider.updateConfiguration(config);
|
||||||
|
if (client.apiVersion.has206Features()) {
|
||||||
|
languages.registerCodeLensProvider(this.description.modeIds, this.referenceCodeLensProvider);
|
||||||
|
}
|
||||||
|
|
||||||
this.description.modeIds.forEach(modeId => {
|
this.description.modeIds.forEach(modeId => {
|
||||||
let selector: DocumentFilter = { scheme: 'file', language: modeId };
|
let selector: DocumentFilter = { scheme: 'file', language: modeId };
|
||||||
languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.');
|
languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.');
|
||||||
@@ -171,6 +179,7 @@ class LanguageProvider {
|
|||||||
if (client.apiVersion.has213Features()) {
|
if (client.apiVersion.has213Features()) {
|
||||||
languages.registerCodeActionsProvider(selector, new CodeActionProvider(client, modeId));
|
languages.registerCodeActionsProvider(selector, new CodeActionProvider(client, modeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
languages.setLanguageConfiguration(modeId, {
|
languages.setLanguageConfiguration(modeId, {
|
||||||
indentationRules: {
|
indentationRules: {
|
||||||
// ^(.*\*/)?\s*\}.*$
|
// ^(.*\*/)?\s*\}.*$
|
||||||
@@ -217,6 +226,9 @@ class LanguageProvider {
|
|||||||
if (this.completionItemProvider) {
|
if (this.completionItemProvider) {
|
||||||
this.completionItemProvider.updateConfiguration(config);
|
this.completionItemProvider.updateConfiguration(config);
|
||||||
}
|
}
|
||||||
|
if (this.referenceCodeLensProvider) {
|
||||||
|
this.referenceCodeLensProvider.updateConfiguration(config);
|
||||||
|
}
|
||||||
if (this.formattingProvider) {
|
if (this.formattingProvider) {
|
||||||
this.formattingProvider.updateConfiguration(config);
|
this.formattingProvider.updateConfiguration(config);
|
||||||
if (!this.formattingProvider.isEnabled() && this.formattingProviderRegistration) {
|
if (!this.formattingProvider.isEnabled() && this.formattingProviderRegistration) {
|
||||||
|
|||||||
@@ -346,17 +346,20 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||||||
switch (selected.id) {
|
switch (selected.id) {
|
||||||
case MessageAction.useLocal:
|
case MessageAction.useLocal:
|
||||||
let pathValue = './node_modules/typescript/lib';
|
let pathValue = './node_modules/typescript/lib';
|
||||||
tsConfig.update('tsdk', pathValue, false);
|
tsConfig.update('tsdk', pathValue, false).then(
|
||||||
window.showInformationMessage(localize('updatedtsdk', 'Updated workspace setting \'typescript.tsdk\' to {0}', pathValue));
|
() => window.showInformationMessage(localize('updatedtsdk', 'Updated workspace setting \'typescript.tsdk\' to {0}', pathValue)),
|
||||||
|
() => window.showErrorMessage(localize('updateTsdkFailed', 'Could not update the \'typescript.tsdk\' workspace setting. Please check that the workspace settings file is valid')));
|
||||||
showVersionStatusItem = true;
|
showVersionStatusItem = true;
|
||||||
return localModulePath;
|
return localModulePath;
|
||||||
case MessageAction.useBundled:
|
case MessageAction.useBundled:
|
||||||
tsConfig.update(checkWorkspaceVersionKey, false, false);
|
tsConfig.update(checkWorkspaceVersionKey, false, false).then(
|
||||||
window.showInformationMessage(localize('updateLocalWorkspaceCheck', 'Updated workspace setting \'typescript.check.workspaceVersion\' to false'));
|
() => window.showInformationMessage(localize('updateLocalWorkspaceCheck', 'Updated workspace setting \'typescript.check.workspaceVersion\' to false')),
|
||||||
|
() => window.showErrorMessage(localize('updateLocalWorkspaceCheckFailed', 'Could not update the \'typescript.check.workspaceVersion\' workspace setting. Please check that the workspace settings file is valid')));
|
||||||
return modulePath;
|
return modulePath;
|
||||||
case MessageAction.neverCheckLocalVersion:
|
case MessageAction.neverCheckLocalVersion:
|
||||||
window.showInformationMessage(localize('updateGlobalWorkspaceCheck', 'Updated user setting \'typescript.check.workspaceVersion\' to false'));
|
tsConfig.update(checkWorkspaceVersionKey, false, true).then(
|
||||||
tsConfig.update(checkWorkspaceVersionKey, false, true);
|
() => window.showInformationMessage(localize('updateGlobalWorkspaceCheck', 'Updated user setting \'typescript.check.workspaceVersion\' to false')),
|
||||||
|
() => window.showErrorMessage(localize('updateGlobalWorkspaceCheckFailed', 'Could not update \'typescript.check.workspaceVersion\' user setting. Please check that your user settings file is valid')));
|
||||||
return modulePath;
|
return modulePath;
|
||||||
default:
|
default:
|
||||||
return modulePath;
|
return modulePath;
|
||||||
|
|||||||
+5
-5
@@ -2,7 +2,7 @@
|
|||||||
"name": "code-oss-dev",
|
"name": "code-oss-dev",
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
"electronVersion": "1.4.6",
|
"electronVersion": "1.4.6",
|
||||||
"distro": "2eecc8b68318fba1fc5b62930287914ac9225e8a",
|
"distro": "ef07477c3bbf2aa2f274b13093cbe0d96fa59fdd",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Microsoft Corporation"
|
"name": "Microsoft Corporation"
|
||||||
},
|
},
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
"eslint": "^3.4.0",
|
"eslint": "^3.4.0",
|
||||||
"event-stream": "^3.1.7",
|
"event-stream": "^3.1.7",
|
||||||
"express": "^4.13.1",
|
"express": "^4.13.1",
|
||||||
|
"flatpak-bundler": "^0.1.1",
|
||||||
"ghooks": "1.0.3",
|
"ghooks": "1.0.3",
|
||||||
"glob": "^5.0.13",
|
"glob": "^5.0.13",
|
||||||
"gulp": "^3.8.9",
|
"gulp": "^3.8.9",
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
"gulp-cssnano": "^2.1.0",
|
"gulp-cssnano": "^2.1.0",
|
||||||
"gulp-filter": "^3.0.0",
|
"gulp-filter": "^3.0.0",
|
||||||
"gulp-flatmap": "^1.0.0",
|
"gulp-flatmap": "^1.0.0",
|
||||||
|
"gulp-image-resize": "^0.10.0",
|
||||||
"gulp-json-editor": "^2.2.1",
|
"gulp-json-editor": "^2.2.1",
|
||||||
"gulp-mocha": "^2.1.3",
|
"gulp-mocha": "^2.1.3",
|
||||||
"gulp-remote-src": "^0.4.0",
|
"gulp-remote-src": "^0.4.0",
|
||||||
@@ -71,8 +73,6 @@
|
|||||||
"gulp-uglify": "^2.0.0",
|
"gulp-uglify": "^2.0.0",
|
||||||
"gulp-util": "^3.0.6",
|
"gulp-util": "^3.0.6",
|
||||||
"gulp-vinyl-zip": "^1.2.2",
|
"gulp-vinyl-zip": "^1.2.2",
|
||||||
"gulp-image-resize": "^0.10.0",
|
|
||||||
"flatpak-bundler": "^0.1.1",
|
|
||||||
"innosetup-compiler": "^5.5.60",
|
"innosetup-compiler": "^5.5.60",
|
||||||
"is": "^3.1.0",
|
"is": "^3.1.0",
|
||||||
"istanbul": "^0.3.17",
|
"istanbul": "^0.3.17",
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
"sinon": "^1.17.2",
|
"sinon": "^1.17.2",
|
||||||
"source-map": "^0.4.4",
|
"source-map": "^0.4.4",
|
||||||
"tslint": "^3.3.0",
|
"tslint": "^3.3.0",
|
||||||
"typescript": "2.0.3",
|
"typescript": "^2.1.4",
|
||||||
"typescript-formatter": "3.1.0",
|
"typescript-formatter": "4.0.1",
|
||||||
"uglify-js": "2.4.8",
|
"uglify-js": "2.4.8",
|
||||||
"underscore": "^1.8.2",
|
"underscore": "^1.8.2",
|
||||||
"vinyl": "^0.4.5",
|
"vinyl": "^0.4.5",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
# If root, ensure that --user-data-dir is specified
|
# If root, ensure that --user-data-dir is specified
|
||||||
ARGS=$@
|
|
||||||
if [ "$(id -u)" = "0" ]; then
|
if [ "$(id -u)" = "0" ]; then
|
||||||
while test $# -gt 0
|
while test $# -gt 0
|
||||||
do
|
do
|
||||||
@@ -34,5 +33,5 @@ fi
|
|||||||
|
|
||||||
ELECTRON="$VSCODE_PATH/@@NAME@@"
|
ELECTRON="$VSCODE_PATH/@@NAME@@"
|
||||||
CLI="$VSCODE_PATH/resources/app/out/cli.js"
|
CLI="$VSCODE_PATH/resources/app/out/cli.js"
|
||||||
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" $ARGS
|
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
|
||||||
exit $?
|
exit $?
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Name=@@NAME_LONG@@
|
Name=@@NAME_LONG@@
|
||||||
Comment=Code Editing. Redefined.
|
Comment=Code Editing. Redefined.
|
||||||
GenericName=Text Editor
|
GenericName=Text Editor
|
||||||
Exec=/usr/share/@@NAME@@/@@NAME@@ %U
|
Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window-if-not-first %U
|
||||||
Icon=@@NAME@@
|
Icon=@@NAME@@
|
||||||
Type=Application
|
Type=Application
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ var nodeCachedDataDir = getNodeCachedDataDir().then(function (value) {
|
|||||||
|
|
||||||
// Load our code once ready
|
// Load our code once ready
|
||||||
app.once('ready', function () {
|
app.once('ready', function () {
|
||||||
|
global.perfAppReady = Date.now();
|
||||||
var nlsConfig = getNLSConfiguration();
|
var nlsConfig = getNLSConfiguration();
|
||||||
process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig);
|
process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig);
|
||||||
|
|
||||||
|
|||||||
@@ -692,7 +692,7 @@ export class Builder implements IDisposable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.on(arg1, fn, listenerToUnbindContainer);
|
return this.on(arg1, fn, listenerToUnbindContainer, useCapture);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -114,14 +114,14 @@ export interface IDomEvent {
|
|||||||
(element: EventHandler, type: string, useCapture?: boolean): _Event<any>;
|
(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 fn = e => emitter.fire(e);
|
||||||
const emitter = new Emitter<any>({
|
const emitter = new Emitter<any>({
|
||||||
onFirstListenerAdd: () => {
|
onFirstListenerAdd: () => {
|
||||||
element.addEventListener(type, fn);
|
element.addEventListener(type, fn, useCapture);
|
||||||
},
|
},
|
||||||
onLastListenerRemove: () => {
|
onLastListenerRemove: () => {
|
||||||
element.removeEventListener(type, fn);
|
element.removeEventListener(type, fn, useCapture);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ function _renderHtml(content: IHTMLContentElement, options: RenderOptions = {}):
|
|||||||
|
|
||||||
const renderer = new marked.Renderer();
|
const renderer = new marked.Renderer();
|
||||||
renderer.image = (href: string, title: string, text: string) => {
|
renderer.image = (href: string, title: string, text: string) => {
|
||||||
let dimensions = [];
|
let dimensions: string[] = [];
|
||||||
if (href) {
|
if (href) {
|
||||||
const splitted = href.split('|').map(s => s.trim());
|
const splitted = href.split('|').map(s => s.trim());
|
||||||
href = splitted[0];
|
href = splitted[0];
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'vs/css!./list';
|
|||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { range } from 'vs/base/common/arrays';
|
import { range } from 'vs/base/common/arrays';
|
||||||
import { IDelegate, IRenderer, IFocusChangeEvent, ISelectionChangeEvent } from './list';
|
import { IDelegate, IRenderer, IFocusChangeEvent, ISelectionChangeEvent } from './list';
|
||||||
import { List } from './listWidget';
|
import { List, IListOptions } from './listWidget';
|
||||||
import { IPagedModel } from 'vs/base/common/paging';
|
import { IPagedModel } from 'vs/base/common/paging';
|
||||||
import Event, { mapEvent } from 'vs/base/common/event';
|
import Event, { mapEvent } from 'vs/base/common/event';
|
||||||
|
|
||||||
@@ -67,10 +67,11 @@ export class PagedList<T> {
|
|||||||
constructor(
|
constructor(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
delegate: IDelegate<number>,
|
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));
|
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>> {
|
get onFocusChange(): Event<IFocusChangeEvent<T>> {
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ export class ListView<T> implements IDisposable {
|
|||||||
return DOM.addDisposableListener(domNode, type, handler, useCapture);
|
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) {
|
if (index < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class Trait<T> implements IDisposable {
|
|||||||
splice(start: number, deleteCount: number, insertCount: number): void {
|
splice(start: number, deleteCount: number, insertCount: number): void {
|
||||||
const diff = insertCount - deleteCount;
|
const diff = insertCount - deleteCount;
|
||||||
const end = start + deleteCount;
|
const end = start + deleteCount;
|
||||||
const indexes = [];
|
const indexes: number[] = [];
|
||||||
|
|
||||||
for (let index of indexes) {
|
for (let index of indexes) {
|
||||||
if (index >= start && index < end) {
|
if (index >= start && index < end) {
|
||||||
@@ -110,13 +110,13 @@ class Trait<T> implements IDisposable {
|
|||||||
|
|
||||||
class FocusTrait<T> extends Trait<T> {
|
class FocusTrait<T> extends Trait<T> {
|
||||||
|
|
||||||
constructor(private getElementId: (number) => string) {
|
constructor(private getElementId: (number: number) => string) {
|
||||||
super('focused');
|
super('focused');
|
||||||
}
|
}
|
||||||
|
|
||||||
renderElement(element: T, index: number, container: HTMLElement): void {
|
renderElement(element: T, index: number, container: HTMLElement): void {
|
||||||
super.renderElement(element, index, container);
|
super.renderElement(element, index, container);
|
||||||
container.setAttribute('role', 'option');
|
container.setAttribute('role', 'treeitem');
|
||||||
container.setAttribute('id', this.getElementId(index));
|
container.setAttribute('id', this.getElementId(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,6 +201,7 @@ class Controller<T> implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IListOptions extends IListViewOptions {
|
export interface IListOptions extends IListViewOptions {
|
||||||
|
ariaLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DefaultOptions: IListOptions = {};
|
const DefaultOptions: IListOptions = {};
|
||||||
@@ -245,13 +246,17 @@ export class List<T> implements IDisposable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.view = new ListView(container, delegate, renderers, options);
|
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.view.domNode.tabIndex = 0;
|
||||||
this.controller = new Controller(this, this.view);
|
this.controller = new Controller(this, this.view);
|
||||||
this.disposables = [this.focus, this.selection, this.view, this.controller];
|
this.disposables = [this.focus, this.selection, this.view, this.controller];
|
||||||
|
|
||||||
this._onDOMFocus = domEvent(this.view.domNode, 'focus');
|
this._onDOMFocus = domEvent(this.view.domNode, 'focus');
|
||||||
this.onFocusChange(this._onFocusChange, this, this.disposables);
|
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 {
|
splice(start: number, deleteCount: number, ...elements: T[]): void {
|
||||||
@@ -418,7 +423,16 @@ export class List<T> implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onFocusChange(): void {
|
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 {
|
dispose(): void {
|
||||||
|
|||||||
@@ -25,22 +25,22 @@
|
|||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical-cursor-container * {
|
.vertical-cursor-container {
|
||||||
cursor: ew-resize;
|
cursor: ew-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal-cursor-container * {
|
.horizontal-cursor-container {
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Custom Mac Cursor */
|
/** Custom Mac Cursor */
|
||||||
|
|
||||||
.monaco-sash.mac.vertical,
|
.monaco-sash.mac.vertical,
|
||||||
.vertical-cursor-container-mac * {
|
.vertical-cursor-container-mac {
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-sash.mac.horizontal,
|
.monaco-sash.mac.horizontal,
|
||||||
.horizontal-cursor-container-mac * {
|
.horizontal-cursor-container-mac {
|
||||||
cursor: row-resize;
|
cursor: row-resize;
|
||||||
}
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
.benchmarktimerbox {
|
|
||||||
z-index: 100;
|
|
||||||
position: absolute;
|
|
||||||
color: black;
|
|
||||||
background: lightblue;
|
|
||||||
top: 100px;
|
|
||||||
right: 20px;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.benchmarktimerbox .inner {
|
|
||||||
width: 600px;
|
|
||||||
height: 300px;
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.benchmarktimerbox .timeFilter {
|
|
||||||
width: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.benchmarktimerbox pre {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timer-event-1 { background: rgba(190, 191, 193, 0.4); color: black; }
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import 'vs/css!./timer';
|
|
||||||
import { TimeKeeper, ITimerEvent, getTimeKeeper } from 'vs/base/common/timer';
|
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|
||||||
import DomUtils = require('vs/base/browser/dom');
|
|
||||||
|
|
||||||
export class TimeKeeperRenderer {
|
|
||||||
|
|
||||||
private listenersToRemove: IDisposable[];
|
|
||||||
private timeKeeper: TimeKeeper;
|
|
||||||
private outerDomNode: HTMLElement;
|
|
||||||
private domNode: HTMLElement;
|
|
||||||
private renderCnt: number;
|
|
||||||
private lastEventIndex: number;
|
|
||||||
|
|
||||||
private textFilter: string;
|
|
||||||
private textFilterDomNode: HTMLInputElement;
|
|
||||||
private timeFilter: number;
|
|
||||||
private timeFilterDomNode: HTMLInputElement;
|
|
||||||
private intervalTokenId: number;
|
|
||||||
|
|
||||||
private renderedEvents: {
|
|
||||||
[key: string]: ITimerEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
private onHide: () => void;
|
|
||||||
|
|
||||||
constructor(onHide: () => void) {
|
|
||||||
this.timeKeeper = getTimeKeeper();
|
|
||||||
this.onHide = onHide;
|
|
||||||
this.lastEventIndex = 0;
|
|
||||||
this.renderedEvents = {};
|
|
||||||
this.renderCnt = 0;
|
|
||||||
this.listenersToRemove = [];
|
|
||||||
this.domNode = this._createDomNode();
|
|
||||||
this.intervalTokenId = window.setInterval(() => this._render(), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy(): void {
|
|
||||||
document.body.removeChild(this.outerDomNode);
|
|
||||||
window.clearInterval(this.intervalTokenId);
|
|
||||||
this.listenersToRemove = dispose(this.listenersToRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _createDomNode(): HTMLElement {
|
|
||||||
this.outerDomNode = document.createElement('div');
|
|
||||||
this.outerDomNode.className = 'benchmarktimerbox';
|
|
||||||
|
|
||||||
// Clear
|
|
||||||
let cancel: HTMLInputElement = <HTMLInputElement>document.createElement('input');
|
|
||||||
cancel.type = 'button';
|
|
||||||
cancel.value = 'Clear';
|
|
||||||
this.listenersToRemove.push(DomUtils.addDisposableListener(cancel, 'click', () => this._onClear()));
|
|
||||||
this.outerDomNode.appendChild(cancel);
|
|
||||||
|
|
||||||
// Text filter
|
|
||||||
this.textFilterDomNode = <HTMLInputElement>document.createElement('input');
|
|
||||||
this.textFilterDomNode.type = 'text';
|
|
||||||
this.textFilterDomNode.className = 'textFilter';
|
|
||||||
this.listenersToRemove.push(DomUtils.addDisposableListener(this.textFilterDomNode, 'keydown', () => this.onTextFilterChange()));
|
|
||||||
this.textFilter = '';
|
|
||||||
this.outerDomNode.appendChild(document.createTextNode('Filter'));
|
|
||||||
this.outerDomNode.appendChild(this.textFilterDomNode);
|
|
||||||
|
|
||||||
// Time filter
|
|
||||||
this.timeFilterDomNode = <HTMLInputElement>document.createElement('input');
|
|
||||||
this.timeFilterDomNode.type = 'text';
|
|
||||||
this.timeFilterDomNode.value = '0';
|
|
||||||
this.timeFilterDomNode.className = 'timeFilter';
|
|
||||||
this.listenersToRemove.push(DomUtils.addDisposableListener(this.timeFilterDomNode, 'keydown', () => this.onTimeFilterChange()));
|
|
||||||
this.timeFilter = 0;
|
|
||||||
this.outerDomNode.appendChild(document.createTextNode('Hide time under'));
|
|
||||||
this.outerDomNode.appendChild(this.timeFilterDomNode);
|
|
||||||
|
|
||||||
let hide: HTMLInputElement = <HTMLInputElement>document.createElement('input');
|
|
||||||
hide.type = 'button';
|
|
||||||
hide.value = 'Close';
|
|
||||||
this.listenersToRemove.push(DomUtils.addDisposableListener(hide, 'click', () => {
|
|
||||||
this.onHide();
|
|
||||||
}));
|
|
||||||
this.outerDomNode.appendChild(hide);
|
|
||||||
|
|
||||||
let heading = document.createElement('pre');
|
|
||||||
heading.appendChild(document.createTextNode(this.renderRow('TOPIC', 'NAME', 'TOOK', 'START', 'END')));
|
|
||||||
this.outerDomNode.appendChild(heading);
|
|
||||||
this.outerDomNode.appendChild(document.createElement('hr'));
|
|
||||||
|
|
||||||
let domNode = document.createElement('div');
|
|
||||||
domNode.className = 'inner';
|
|
||||||
this.outerDomNode.appendChild(domNode);
|
|
||||||
|
|
||||||
document.body.appendChild(this.outerDomNode);
|
|
||||||
|
|
||||||
return domNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private onTextFilterChange(): void {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.refilter();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private onTimeFilterChange(): void {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.refilter();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private matchesTextFilter(event: ITimerEvent): boolean {
|
|
||||||
if (!this.textFilter) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (event.topic.toLowerCase().indexOf(this.textFilter.toLowerCase()) >= 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (event.name.toLowerCase().indexOf(this.textFilter.toLowerCase()) >= 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private matchesTimeFilter(event: ITimerEvent): boolean {
|
|
||||||
if (!this.timeFilter) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (event.timeTaken() >= this.timeFilter) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private shouldShow(event: ITimerEvent): boolean {
|
|
||||||
return this.matchesTextFilter(event) && this.matchesTimeFilter(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private refilter(): void {
|
|
||||||
this.textFilter = this.textFilterDomNode.value;
|
|
||||||
this.timeFilter = parseInt(this.timeFilterDomNode.value, 10);
|
|
||||||
|
|
||||||
let domNodes = Array.prototype.slice.call(this.domNode.children, 0);
|
|
||||||
for (let i = 0; i < domNodes.length; i++) {
|
|
||||||
let eventId = domNodes[i].getAttribute('data-event-id');
|
|
||||||
let event = this.renderedEvents[eventId];
|
|
||||||
|
|
||||||
if (this.shouldShow(event)) {
|
|
||||||
domNodes[i].style.display = 'inherit';
|
|
||||||
} else {
|
|
||||||
domNodes[i].style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onClear(): void {
|
|
||||||
this.lastEventIndex = this.timeKeeper.getCollectedEvents().length;
|
|
||||||
this.renderedEvents = {};
|
|
||||||
this.renderCnt = 0;
|
|
||||||
DomUtils.clearNode(this.domNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private leftPaddedString(size: number, padChar: string, str: string): string {
|
|
||||||
let spaces = this._repeatStr(padChar, Math.max(0, size - str.length));
|
|
||||||
return spaces + str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private rightPaddedString(size: number, padChar: string, str: string): string {
|
|
||||||
let spaces = this._repeatStr(padChar, Math.max(0, size - str.length));
|
|
||||||
return str + spaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderRow(topic: string, name: string, timeTook: string, timeStart: string, timerEnd: string): string {
|
|
||||||
let result = ' ';
|
|
||||||
result += this.rightPaddedString(10, ' ', topic);
|
|
||||||
result += this.rightPaddedString(30, ' ', name);
|
|
||||||
result += ' ' + this.leftPaddedString(15, ' ', timeTook);
|
|
||||||
result += ' ' + this.leftPaddedString(13, ' ', timeStart);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _suffix0(s: string): string {
|
|
||||||
if (s.charAt(s.length - 3) === '.') {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
if (s.charAt(s.length - 2) === '.') {
|
|
||||||
return s + '0';
|
|
||||||
}
|
|
||||||
return s + '.00';
|
|
||||||
}
|
|
||||||
|
|
||||||
private _twoPrecision(a: number): string {
|
|
||||||
return this._suffix0(Math.round(a * 100) / 100 + '');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _absoluteTime(t: number): string {
|
|
||||||
if (t < 1000) {
|
|
||||||
return this._twoPrecision(t) + ' ms';
|
|
||||||
}
|
|
||||||
t /= 1000;
|
|
||||||
if (t < 60) {
|
|
||||||
return this._twoPrecision(t) + ' s';
|
|
||||||
}
|
|
||||||
t /= 60;
|
|
||||||
if (t < 60) {
|
|
||||||
return this._twoPrecision(t) + ' m';
|
|
||||||
}
|
|
||||||
t /= 60;
|
|
||||||
return this._twoPrecision(t) + ' h';
|
|
||||||
}
|
|
||||||
|
|
||||||
private _renderEvent(domNode: HTMLElement, event: ITimerEvent): void {
|
|
||||||
let start = event.startTime.getTime() - TimeKeeper.PARSE_TIME.getTime();
|
|
||||||
|
|
||||||
let result = this.renderRow(
|
|
||||||
event.topic,
|
|
||||||
event.name,
|
|
||||||
this._twoPrecision(event.timeTaken()),
|
|
||||||
this._absoluteTime(start) + '',
|
|
||||||
this._absoluteTime(start + event.timeTaken())
|
|
||||||
);
|
|
||||||
domNode.textContent = '';
|
|
||||||
domNode.appendChild(document.createTextNode(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
private _renderStartTimerEvent(event: ITimerEvent): void {
|
|
||||||
let domNode = document.createElement('pre');
|
|
||||||
this._renderEvent(domNode, event);
|
|
||||||
this.domNode.appendChild(domNode);
|
|
||||||
let idString = event.id.toString();
|
|
||||||
|
|
||||||
domNode.setAttribute('data-event-id', idString);
|
|
||||||
domNode.className = 'timer-event-' + (event.id % 2);
|
|
||||||
this.renderedEvents[idString] = event;
|
|
||||||
|
|
||||||
if (this.shouldShow(this.renderedEvents[idString])) {
|
|
||||||
domNode.style.display = 'inherit';
|
|
||||||
} else {
|
|
||||||
domNode.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderCnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _render(): void {
|
|
||||||
let allEvents = this.timeKeeper.getCollectedEvents(), didSomething = false;
|
|
||||||
|
|
||||||
for (let i = this.lastEventIndex; i < allEvents.length; i++) {
|
|
||||||
let ev = allEvents[i];
|
|
||||||
|
|
||||||
if (!ev.stopTime) {
|
|
||||||
// This event is not yet finished => block
|
|
||||||
this.lastEventIndex = i;
|
|
||||||
if (didSomething) {
|
|
||||||
this.domNode.scrollTop = 100000;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._renderStartTimerEvent(ev);
|
|
||||||
didSomething = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (didSomething) {
|
|
||||||
this.domNode.scrollTop = 100000;
|
|
||||||
}
|
|
||||||
this.lastEventIndex = allEvents.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _repeatStr(str: string, cnt: number): string {
|
|
||||||
let r = '';
|
|
||||||
for (let i = 0; i < cnt; i++) {
|
|
||||||
r += str;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export function equals<T>(one: T[], other: T[], itemEquals: (a: T, b: T) => bool
|
|||||||
return false;
|
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])) {
|
if (!itemEquals(one[i], other[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -177,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 {
|
export function commonPrefixLength<T>(one: T[], other: T[], equals: (a: T, b: T) => boolean = (a, b) => a === b): number {
|
||||||
let result = 0;
|
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++;
|
result++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ export interface ITask<T> {
|
|||||||
* The throttler implements this via the queue() method, by providing it a task
|
* The throttler implements this via the queue() method, by providing it a task
|
||||||
* factory. Following the example:
|
* factory. Following the example:
|
||||||
*
|
*
|
||||||
* var throttler = new Throttler();
|
* const throttler = new Throttler();
|
||||||
* var letters = [];
|
* const letters = [];
|
||||||
*
|
*
|
||||||
* function deliver() {
|
* function deliver() {
|
||||||
* const lettersToDeliver = letters;
|
* 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
|
* to be executed and the waiting period (delay) must be passed in as arguments. Following
|
||||||
* the example:
|
* the example:
|
||||||
*
|
*
|
||||||
* var delayer = new Delayer(WAITING_PERIOD);
|
* const delayer = new Delayer(WAITING_PERIOD);
|
||||||
* var letters = [];
|
* const letters = [];
|
||||||
*
|
*
|
||||||
* function letterReceived(l) {
|
* function letterReceived(l) {
|
||||||
* letters.push(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> {
|
export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t: T) => boolean = t => !!t): TPromise<T> {
|
||||||
promiseFactories = [...promiseFactories.reverse()];
|
promiseFactories = [...promiseFactories.reverse()];
|
||||||
|
|
||||||
const loop = () => {
|
const loop: () => TPromise<T> = () => {
|
||||||
if (promiseFactories.length === 0) {
|
if (promiseFactories.length === 0) {
|
||||||
return TPromise.as(null);
|
return TPromise.as(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ function hsla2rgba(hsla: HSLA): RGBA {
|
|||||||
let s = Math.min(hsla.s, 1);
|
let s = Math.min(hsla.s, 1);
|
||||||
let l = Math.min(hsla.l, 1);
|
let l = Math.min(hsla.l, 1);
|
||||||
let a = hsla.a === void 0 ? hsla.a : 1;
|
let a = hsla.a === void 0 ? hsla.a : 1;
|
||||||
let r, g, b;
|
let r: number, g: number, b: number;
|
||||||
|
|
||||||
if (s === 0) {
|
if (s === 0) {
|
||||||
r = g = b = l; // achromatic
|
r = g = b = l; // achromatic
|
||||||
} else {
|
} else {
|
||||||
let hue2rgb = function hue2rgb(p, q, t) {
|
let hue2rgb = function hue2rgb(p: number, q: number, t: number) {
|
||||||
if (t < 0) {
|
if (t < 0) {
|
||||||
t += 1;
|
t += 1;
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ export class Color {
|
|||||||
* Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
|
* Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
|
||||||
*/
|
*/
|
||||||
public getLuminosity(): number {
|
public getLuminosity(): number {
|
||||||
let luminosityFor = function (color): number {
|
let luminosityFor = function (color: number): number {
|
||||||
let c = color / 255;
|
let c = color / 255;
|
||||||
return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);
|
return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ export function compareByPrefix(one: string, other: string, lookFor: string): nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IScorableResourceAccessor<T> {
|
export interface IScorableResourceAccessor<T> {
|
||||||
getLabel(T): string;
|
getLabel(t: T): string;
|
||||||
getResourcePath(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 {
|
export function compareByScore<T>(elementA: T, elementB: T, accessor: IScorableResourceAccessor<T>, lookFor: string, lookForNormalizedLower: string, scorerCache?: { [key: string]: number }): number {
|
||||||
|
|||||||
@@ -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));
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,7 @@ export function memoize(target: any, key: string, descriptor: any) {
|
|||||||
|
|
||||||
const memoizeKey = `$memoize$${key}`;
|
const memoizeKey = `$memoize$${key}`;
|
||||||
|
|
||||||
descriptor[fnKey] = function (...args) {
|
descriptor[fnKey] = function (...args: any[]) {
|
||||||
if (!this.hasOwnProperty(memoizeKey)) {
|
if (!this.hasOwnProperty(memoizeKey)) {
|
||||||
Object.defineProperty(this, memoizeKey, {
|
Object.defineProperty(this, memoizeKey, {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ globals.Monaco.Diagnostics = {};
|
|||||||
|
|
||||||
var switches = globals.Monaco.Diagnostics;
|
var switches = globals.Monaco.Diagnostics;
|
||||||
var map = {};
|
var map = {};
|
||||||
var data = [];
|
var data: any[] = [];
|
||||||
|
|
||||||
function fifo(array: any[], size: number) {
|
function fifo(array: any[], size: number) {
|
||||||
while (array.length > size) {
|
while (array.length > size) {
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ export class LcsDiff2 {
|
|||||||
// Construct the changes
|
// Construct the changes
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let j = 0;
|
let j = 0;
|
||||||
let xChangeStart, yChangeStart;
|
let xChangeStart: number, yChangeStart: number;
|
||||||
let changes = [];
|
let changes: DiffChange[] = [];
|
||||||
while (i < xLength && j < yLength) {
|
while (i < xLength && j < yLength) {
|
||||||
if (this.resultX[i] && this.resultY[j]) {
|
if (this.resultX[i] && this.resultY[j]) {
|
||||||
// No change
|
// No change
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ export function once<T>(event: Event<T>): Event<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function any<T>(...events: Event<T>[]): Event<T> {
|
export function any<T>(...events: Event<T>[]): Event<T> {
|
||||||
let listeners = [];
|
let listeners: IDisposable[] = [];
|
||||||
|
|
||||||
const emitter = new Emitter<T>({
|
const emitter = new Emitter<T>({
|
||||||
onFirstListenerAdd() {
|
onFirstListenerAdd() {
|
||||||
@@ -297,7 +297,7 @@ export class EventBufferer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bufferEvents(fn: () => void): void {
|
bufferEvents(fn: () => void): void {
|
||||||
const buffer = [];
|
const buffer: Function[] = [];
|
||||||
this.buffers.push(buffer);
|
this.buffers.push(buffer);
|
||||||
fn();
|
fn();
|
||||||
this.buffers.pop();
|
this.buffers.pop();
|
||||||
@@ -334,7 +334,7 @@ class ChainableEvent<T> implements IChainableEvent<T> {
|
|||||||
return new ChainableEvent(filterEvent(this._event, fn));
|
return new ChainableEvent(filterEvent(this._event, fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
on(listener, thisArgs, disposables) {
|
on(listener, thisArgs, disposables: IDisposable[]) {
|
||||||
return this._event(listener, thisArgs, disposables);
|
return this._event(listener, thisArgs, disposables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {
|
function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {
|
||||||
const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis;
|
const { upperPercent, lowerPercent } = analysis;
|
||||||
return lowerPercent === 0 && upperPercent > 0.6;
|
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
|
// 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)
|
// 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) {
|
if (!target || target.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -283,14 +284,14 @@ export function matchesWords(word: string, target: string): IMatch[] {
|
|||||||
let result: IMatch[] = null;
|
let result: IMatch[] = null;
|
||||||
let i = 0;
|
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);
|
i = nextWord(target, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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) {
|
if (i === word.length) {
|
||||||
return [];
|
return [];
|
||||||
} else if (j === target.length) {
|
} else if (j === target.length) {
|
||||||
@@ -298,13 +299,15 @@ function _matchesWords(word: string, target: string, i: number, j: number): IMat
|
|||||||
} else if (word[i] !== target[j].toLowerCase()) {
|
} else if (word[i] !== target[j].toLowerCase()) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
let result = null;
|
let result: IMatch[] = null;
|
||||||
let nextWordIndex = j + 1;
|
let nextWordIndex = j + 1;
|
||||||
result = _matchesWords(word, target, i + 1, j + 1);
|
result = _matchesWords(word, target, i + 1, j + 1, contiguous);
|
||||||
|
if (!contiguous) {
|
||||||
while (!result && (nextWordIndex = nextWord(target, nextWordIndex)) < target.length) {
|
while (!result && (nextWordIndex = nextWord(target, nextWordIndex)) < target.length) {
|
||||||
result = _matchesWords(word, target, i + 1, nextWordIndex);
|
result = _matchesWords(word, target, i + 1, nextWordIndex, contiguous);
|
||||||
nextWordIndex++;
|
nextWordIndex++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result === null ? null : join({ start: j, end: j + 1 }, result);
|
return result === null ? null : join({ start: j, end: j + 1 }, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
* 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.
|
* Read the next token. Returns the tolen code.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { isArray } from './types';
|
|
||||||
|
|
||||||
export const empty: IDisposable = Object.freeze({
|
export const empty: IDisposable = Object.freeze({
|
||||||
dispose() { }
|
dispose() { }
|
||||||
});
|
});
|
||||||
@@ -14,17 +12,24 @@ export interface IDisposable {
|
|||||||
dispose(): void;
|
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[];
|
||||||
export function dispose<T extends IDisposable>(...disposables: T[]): T[] {
|
export function dispose<T extends IDisposable>(first: T | T[], ...rest: T[]): T | T[] {
|
||||||
const first = disposables[0];
|
|
||||||
|
|
||||||
if (isArray(first)) {
|
if (Array.isArray(first)) {
|
||||||
disposables = first as any as T[];
|
first.forEach(d => d && d.dispose());
|
||||||
}
|
|
||||||
|
|
||||||
disposables.forEach(d => d && d.dispose());
|
|
||||||
return [];
|
return [];
|
||||||
|
} else if (rest.length === 0) {
|
||||||
|
if (first) {
|
||||||
|
first.dispose();
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispose(first);
|
||||||
|
dispose(rest);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function combinedDisposable(disposables: IDisposable[]): IDisposable {
|
export function combinedDisposable(disposables: IDisposable[]): IDisposable {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export class LinkedMap<K extends Key, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public keys(): K[] {
|
public keys(): K[] {
|
||||||
var keys: K[] = [];
|
const keys: K[] = [];
|
||||||
for (let key in this.map) {
|
for (let key in this.map) {
|
||||||
keys.push(this.map[key].key);
|
keys.push(this.map[key].key);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ export class LinkedMap<K extends Key, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public values(): T[] {
|
public values(): T[] {
|
||||||
var values: T[] = [];
|
const values: T[] = [];
|
||||||
for (let key in this.map) {
|
for (let key in this.map) {
|
||||||
values.push(this.map[key].value);
|
values.push(this.map[key].value);
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ export class LinkedMap<K extends Key, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public entries(): Entry<K, T>[] {
|
public entries(): Entry<K, T>[] {
|
||||||
var entries: Entry<K, T>[] = [];
|
const entries: Entry<K, T>[] = [];
|
||||||
for (let key in this.map) {
|
for (let key in this.map) {
|
||||||
entries.push(this.map[key]);
|
entries.push(this.map[key]);
|
||||||
}
|
}
|
||||||
@@ -310,7 +310,7 @@ class Node<E> {
|
|||||||
*/
|
*/
|
||||||
export class TrieMap<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 _splitter: (s: string) => string[];
|
||||||
private _root = new Node<E>();
|
private _root = new Node<E>();
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ function guessMimeTypeByPath(path: string, filename: string, associations: IText
|
|||||||
let patternMatch: ITextMimeAssociationItem;
|
let patternMatch: ITextMimeAssociationItem;
|
||||||
let extensionMatch: ITextMimeAssociationItem;
|
let extensionMatch: ITextMimeAssociationItem;
|
||||||
|
|
||||||
for (var i = 0; i < associations.length; i++) {
|
for (let i = 0; i < associations.length; i++) {
|
||||||
let association = associations[i];
|
let association = associations[i];
|
||||||
|
|
||||||
// First exact name match
|
// First exact name match
|
||||||
@@ -243,7 +243,7 @@ export function isUnspecific(mime: string[] | string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function suggestFilename(langId: string, prefix: string): string {
|
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];
|
let association = registeredAssociations[i];
|
||||||
if (association.userConfigured) {
|
if (association.userConfigured) {
|
||||||
continue; // only support registered ones
|
continue; // only support registered ones
|
||||||
|
|||||||
@@ -12,23 +12,23 @@ export namespace Schemas {
|
|||||||
* A schema that is used for models that exist in memory
|
* A schema that is used for models that exist in memory
|
||||||
* only and that have no correspondence on a server or such.
|
* 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
|
* 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
|
* 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 {
|
export interface IXHROptions {
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import { CharCode } from 'vs/base/common/charCode';
|
|||||||
/**
|
/**
|
||||||
* The forward slash path separator.
|
* The forward slash path separator.
|
||||||
*/
|
*/
|
||||||
export var sep = '/';
|
export const sep = '/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The native path separator depending on the OS.
|
* The native path separator depending on the OS.
|
||||||
*/
|
*/
|
||||||
export var nativeSep = isWindows ? '\\' : '/';
|
export const nativeSep = isWindows ? '\\' : '/';
|
||||||
|
|
||||||
export function relative(from: string, to: string): string {
|
export function relative(from: string, to: string): string {
|
||||||
const originalNormalizedFrom = normalize(from);
|
const originalNormalizedFrom = normalize(from);
|
||||||
@@ -50,7 +50,7 @@ export function relative(from: string, to: string): string {
|
|||||||
* @returns the directory name of a path.
|
* @returns the directory name of a path.
|
||||||
*/
|
*/
|
||||||
export function dirname(path: string): string {
|
export function dirname(path: string): string {
|
||||||
var idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
|
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
|
||||||
if (idx === 0) {
|
if (idx === 0) {
|
||||||
return '.';
|
return '.';
|
||||||
} else if (~idx === 0) {
|
} else if (~idx === 0) {
|
||||||
@@ -64,7 +64,7 @@ export function dirname(path: string): string {
|
|||||||
* @returns the base name of a path.
|
* @returns the base name of a path.
|
||||||
*/
|
*/
|
||||||
export function basename(path: string): string {
|
export function basename(path: string): string {
|
||||||
var idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
|
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
|
||||||
if (idx === 0) {
|
if (idx === 0) {
|
||||||
return path;
|
return path;
|
||||||
} else if (~idx === path.length - 1) {
|
} else if (~idx === path.length - 1) {
|
||||||
@@ -79,7 +79,7 @@ export function basename(path: string): string {
|
|||||||
*/
|
*/
|
||||||
export function extname(path: string): string {
|
export function extname(path: string): string {
|
||||||
path = basename(path);
|
path = basename(path);
|
||||||
var idx = ~path.lastIndexOf('.');
|
const idx = ~path.lastIndexOf('.');
|
||||||
return idx ? path.substring(~idx) : '';
|
return idx ? path.substring(~idx) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ let _isRootUser = false;
|
|||||||
let _isNative = false;
|
let _isNative = false;
|
||||||
let _isWeb = false;
|
let _isWeb = false;
|
||||||
let _isQunit = false;
|
let _isQunit = false;
|
||||||
let _locale = undefined;
|
let _locale: string = undefined;
|
||||||
let _language = undefined;
|
let _language: string = undefined;
|
||||||
|
|
||||||
interface NLSConfig {
|
interface NLSConfig {
|
||||||
locale: string;
|
locale: string;
|
||||||
@@ -124,7 +124,7 @@ interface IGlobals {
|
|||||||
clearTimeout(token: TimeoutToken): void;
|
clearTimeout(token: TimeoutToken): void;
|
||||||
|
|
||||||
setInterval(callback: (...args: any[]) => void, delay: number, ...args: any[]): IntervalToken;
|
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);
|
const _globals = <IGlobals>(typeof self === 'object' ? self : global);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import { globals } from 'vs/base/common/platform';
|
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 {
|
export class StopWatch {
|
||||||
|
|
||||||
|
|||||||
@@ -607,8 +607,8 @@ export function safeBtoa(str: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function repeat(s: string, count: number): string {
|
export function repeat(s: string, count: number): string {
|
||||||
var result = '';
|
let result = '';
|
||||||
for (var i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
result += s;
|
result += s;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,293 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import Platform = require('vs/base/common/platform');
|
|
||||||
import errors = require('vs/base/common/errors');
|
|
||||||
import precision = require('vs/base/common/stopwatch');
|
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
|
|
||||||
export var ENABLE_TIMER = false;
|
|
||||||
var msWriteProfilerMark = Platform.globals['msWriteProfilerMark'];
|
|
||||||
|
|
||||||
export enum Topic {
|
|
||||||
EDITOR,
|
|
||||||
LANGUAGES,
|
|
||||||
WORKER,
|
|
||||||
WORKBENCH,
|
|
||||||
STARTUP
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITimerEvent {
|
|
||||||
id: number;
|
|
||||||
topic: string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
data: any;
|
|
||||||
|
|
||||||
startTime: Date;
|
|
||||||
stopTime: Date;
|
|
||||||
|
|
||||||
stop(stopTime?: Date): void;
|
|
||||||
timeTaken(): number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IExistingTimerEvent {
|
|
||||||
topic: string;
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
description?: string;
|
|
||||||
|
|
||||||
startTime: Date;
|
|
||||||
stopTime: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
class NullTimerEvent implements ITimerEvent {
|
|
||||||
public id: number;
|
|
||||||
public topic: string;
|
|
||||||
public name: string;
|
|
||||||
public description: string;
|
|
||||||
public data: any;
|
|
||||||
|
|
||||||
public startTime: Date;
|
|
||||||
public stopTime: Date;
|
|
||||||
|
|
||||||
public stop(): void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
public timeTaken(): number {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimerEvent implements ITimerEvent {
|
|
||||||
public id: number;
|
|
||||||
public topic: string;
|
|
||||||
public name: string;
|
|
||||||
public description: string;
|
|
||||||
public data: any;
|
|
||||||
|
|
||||||
public startTime: Date;
|
|
||||||
public stopTime: Date;
|
|
||||||
|
|
||||||
private timeKeeper: TimeKeeper;
|
|
||||||
private sw: precision.StopWatch;
|
|
||||||
|
|
||||||
constructor(timeKeeper: TimeKeeper, name: string, topic: string, startTime?: Date, description?: string) {
|
|
||||||
this.timeKeeper = timeKeeper;
|
|
||||||
this.name = name;
|
|
||||||
this.description = description;
|
|
||||||
this.topic = topic;
|
|
||||||
this.stopTime = null;
|
|
||||||
|
|
||||||
if (startTime) {
|
|
||||||
this.startTime = startTime;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startTime = new Date();
|
|
||||||
this.sw = precision.StopWatch.create();
|
|
||||||
|
|
||||||
if (msWriteProfilerMark) {
|
|
||||||
var profilerName = ['Monaco', this.topic, this.name, 'start'];
|
|
||||||
msWriteProfilerMark(profilerName.join('|'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public stop(stopTime?: Date): void {
|
|
||||||
|
|
||||||
// already stopped
|
|
||||||
if (this.stopTime !== null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopTime) {
|
|
||||||
this.stopTime = stopTime;
|
|
||||||
this.sw = null;
|
|
||||||
this.timeKeeper._onEventStopped(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stopTime = new Date();
|
|
||||||
if (this.sw) {
|
|
||||||
this.sw.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.timeKeeper._onEventStopped(this);
|
|
||||||
|
|
||||||
if (msWriteProfilerMark) {
|
|
||||||
var profilerName = ['Monaco', this.topic, this.name, 'stop'];
|
|
||||||
msWriteProfilerMark(profilerName.join('|'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public timeTaken(): number {
|
|
||||||
if (this.sw) {
|
|
||||||
return this.sw.elapsed();
|
|
||||||
}
|
|
||||||
if (this.stopTime) {
|
|
||||||
return this.stopTime.getTime() - this.startTime.getTime();
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEventsListener {
|
|
||||||
(events: ITimerEvent[]): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TimeKeeper {
|
|
||||||
/**
|
|
||||||
* After being started for 1 minute, all timers are automatically stopped.
|
|
||||||
*/
|
|
||||||
private static _MAX_TIMER_LENGTH = 60000; // 1 minute
|
|
||||||
/**
|
|
||||||
* Every 2 minutes, a sweep of current started timers is done.
|
|
||||||
*/
|
|
||||||
private static _CLEAN_UP_INTERVAL = 120000; // 2 minutes
|
|
||||||
/**
|
|
||||||
* Collect at most 1000 events.
|
|
||||||
*/
|
|
||||||
private static _EVENT_CACHE_LIMIT = 1000;
|
|
||||||
|
|
||||||
private static EVENT_ID = 1;
|
|
||||||
public static PARSE_TIME = new Date();
|
|
||||||
|
|
||||||
|
|
||||||
private cleaningIntervalId: Platform.IntervalToken;
|
|
||||||
private collectedEvents: ITimerEvent[];
|
|
||||||
private listeners: IEventsListener[];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.cleaningIntervalId = -1;
|
|
||||||
this.collectedEvents = [];
|
|
||||||
this.listeners = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public isEnabled(): boolean {
|
|
||||||
return ENABLE_TIMER;
|
|
||||||
}
|
|
||||||
|
|
||||||
public start(topic: Topic | string, name: string, start?: Date, description?: string): ITimerEvent {
|
|
||||||
if (!this.isEnabled()) {
|
|
||||||
return nullEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
var strTopic: string;
|
|
||||||
|
|
||||||
if (typeof topic === 'string') {
|
|
||||||
strTopic = topic;
|
|
||||||
} else if (topic === Topic.EDITOR) {
|
|
||||||
strTopic = 'Editor';
|
|
||||||
} else if (topic === Topic.LANGUAGES) {
|
|
||||||
strTopic = 'Languages';
|
|
||||||
} else if (topic === Topic.WORKER) {
|
|
||||||
strTopic = 'Worker';
|
|
||||||
} else if (topic === Topic.WORKBENCH) {
|
|
||||||
strTopic = 'Workbench';
|
|
||||||
} else if (topic === Topic.STARTUP) {
|
|
||||||
strTopic = 'Startup';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initAutoCleaning();
|
|
||||||
var event = new TimerEvent(this, name, strTopic, start, description);
|
|
||||||
this.addEvent(event);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose(): void {
|
|
||||||
if (this.cleaningIntervalId !== -1) {
|
|
||||||
Platform.clearInterval(this.cleaningIntervalId);
|
|
||||||
this.cleaningIntervalId = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public addListener(listener: IEventsListener): IDisposable {
|
|
||||||
this.listeners.push(listener);
|
|
||||||
return {
|
|
||||||
dispose: () => {
|
|
||||||
for (var i = 0; i < this.listeners.length; i++) {
|
|
||||||
if (this.listeners[i] === listener) {
|
|
||||||
this.listeners.splice(i, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private addEvent(event: ITimerEvent): void {
|
|
||||||
event.id = TimeKeeper.EVENT_ID;
|
|
||||||
TimeKeeper.EVENT_ID++;
|
|
||||||
this.collectedEvents.push(event);
|
|
||||||
// expire items from the front of the cache
|
|
||||||
if (this.collectedEvents.length > TimeKeeper._EVENT_CACHE_LIMIT) {
|
|
||||||
this.collectedEvents.shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private initAutoCleaning(): void {
|
|
||||||
if (this.cleaningIntervalId === -1) {
|
|
||||||
this.cleaningIntervalId = Platform.setInterval(() => {
|
|
||||||
var now = Date.now();
|
|
||||||
this.collectedEvents.forEach((event) => {
|
|
||||||
if (!event.stopTime && (now - event.startTime.getTime()) >= TimeKeeper._MAX_TIMER_LENGTH) {
|
|
||||||
event.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, TimeKeeper._CLEAN_UP_INTERVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCollectedEvents(): ITimerEvent[] {
|
|
||||||
return this.collectedEvents.slice(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearCollectedEvents(): void {
|
|
||||||
this.collectedEvents = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
_onEventStopped(event: ITimerEvent): void {
|
|
||||||
var emitEvents = [event];
|
|
||||||
|
|
||||||
var listeners = this.listeners.slice(0);
|
|
||||||
for (var i = 0; i < listeners.length; i++) {
|
|
||||||
try {
|
|
||||||
listeners[i](emitEvents);
|
|
||||||
} catch (e) {
|
|
||||||
errors.onUnexpectedError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setInitialCollectedEvents(events: IExistingTimerEvent[], startTime?: Date): void {
|
|
||||||
if (!this.isEnabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startTime) {
|
|
||||||
TimeKeeper.PARSE_TIME = startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.forEach((event) => {
|
|
||||||
var e = new TimerEvent(this, event.name, event.topic, event.startTime, event.description);
|
|
||||||
e.stop(event.stopTime);
|
|
||||||
this.addEvent(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var timeKeeper = new TimeKeeper();
|
|
||||||
export var nullEvent: ITimerEvent = new NullTimerEvent();
|
|
||||||
|
|
||||||
export function start(topic: Topic | string, name: string, start?: Date, description?: string): ITimerEvent {
|
|
||||||
return timeKeeper.start(topic, name, start, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTimeKeeper(): TimeKeeper {
|
|
||||||
return timeKeeper;
|
|
||||||
}
|
|
||||||
@@ -106,7 +106,7 @@ function read(zipPath: string, filePath: string): TPromise<Readable> {
|
|||||||
export function buffer(zipPath: string, filePath: string): TPromise<Buffer> {
|
export function buffer(zipPath: string, filePath: string): TPromise<Buffer> {
|
||||||
return read(zipPath, filePath).then(stream => {
|
return read(zipPath, filePath).then(stream => {
|
||||||
return new TPromise<Buffer>((c, e) => {
|
return new TPromise<Buffer>((c, e) => {
|
||||||
const buffers = [];
|
const buffers: Buffer[] = [];
|
||||||
stream.once('error', e);
|
stream.once('error', e);
|
||||||
stream.on('data', b => buffers.push(b));
|
stream.on('data', b => buffers.push(b));
|
||||||
stream.on('end', () => c(Buffer.concat(buffers)));
|
stream.on('end', () => c(Buffer.concat(buffers)));
|
||||||
|
|||||||
@@ -689,15 +689,15 @@ export class QuickOpenModel implements
|
|||||||
return this._entries;
|
return this._entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
getId(entry: QuickOpenEntry): string {
|
public getId(entry: QuickOpenEntry): string {
|
||||||
return entry.getId();
|
return entry.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
getLabel(entry: QuickOpenEntry): string {
|
public getLabel(entry: QuickOpenEntry): string {
|
||||||
return entry.getLabel();
|
return entry.getLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
getAriaLabel(entry: QuickOpenEntry): string {
|
public getAriaLabel(entry: QuickOpenEntry): string {
|
||||||
const ariaLabel = entry.getAriaLabel();
|
const ariaLabel = entry.getAriaLabel();
|
||||||
if (ariaLabel) {
|
if (ariaLabel) {
|
||||||
return nls.localize('quickOpenAriaLabelEntry', "{0}, picker", entry.getAriaLabel());
|
return nls.localize('quickOpenAriaLabelEntry', "{0}, picker", entry.getAriaLabel());
|
||||||
@@ -706,11 +706,11 @@ export class QuickOpenModel implements
|
|||||||
return nls.localize('quickOpenAriaLabel', "picker");
|
return nls.localize('quickOpenAriaLabel', "picker");
|
||||||
}
|
}
|
||||||
|
|
||||||
isVisible(entry: QuickOpenEntry): boolean {
|
public isVisible(entry: QuickOpenEntry): boolean {
|
||||||
return !entry.isHidden();
|
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);
|
return entry.run(mode, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ export interface ITree extends Events.IEventEmitter {
|
|||||||
* Returns a navigator which allows to discover the visible and
|
* Returns a navigator which allows to discover the visible and
|
||||||
* expanded elements in the tree.
|
* expanded elements in the tree.
|
||||||
*/
|
*/
|
||||||
getNavigator(): INavigator<any>;
|
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes the tree
|
* Disposes the tree
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ export class Tree extends Events.EventEmitter implements _.ITree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public collapse(element: any, recursive: boolean = false): WinJS.Promise {
|
public collapse(element: any, recursive: boolean = false): WinJS.Promise {
|
||||||
return this.model.collapse(element);
|
return this.model.collapse(element, recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
public collapseAll(elements: any[] = null, recursive: boolean = false): WinJS.Promise {
|
public collapseAll(elements: any[] = null, recursive: boolean = false): WinJS.Promise {
|
||||||
@@ -318,8 +318,8 @@ export class Tree extends Events.EventEmitter implements _.ITree {
|
|||||||
return this.model.hasTrait(trait, element);
|
return this.model.hasTrait(trait, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
getNavigator(): INavigator<any> {
|
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> {
|
||||||
return new MappedNavigator(this.model.getNavigator(), i => i && i.getElement());
|
return new MappedNavigator(this.model.getNavigator(fromElement, subTreeOnly), i => i && i.getElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
|||||||
@@ -186,5 +186,8 @@ suite('Filters', () => {
|
|||||||
filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 3 }, { start: 4, end: 7 }]);
|
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 }]);
|
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 }]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,18 +13,21 @@ import URI from 'vs/base/common/uri';
|
|||||||
|
|
||||||
export class DeferredTPromise<T> extends TPromise<T> {
|
export class DeferredTPromise<T> extends TPromise<T> {
|
||||||
|
|
||||||
public canceled = false;
|
public canceled: boolean;
|
||||||
|
|
||||||
private completeCallback: TValueCallback<T>;
|
private completeCallback: TValueCallback<T>;
|
||||||
private errorCallback: (err: any) => void;
|
private errorCallback: (err: any) => void;
|
||||||
private progressCallback: ProgressCallback;
|
private progressCallback: ProgressCallback;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
let captured: any;
|
||||||
super((c, e, p) => {
|
super((c, e, p) => {
|
||||||
this.completeCallback = c;
|
captured = { c, e, p };
|
||||||
this.errorCallback = e;
|
|
||||||
this.progressCallback = p;
|
|
||||||
}, () => this.oncancel());
|
}, () => this.oncancel());
|
||||||
|
this.canceled = false;
|
||||||
|
this.completeCallback = captured.c;
|
||||||
|
this.errorCallback = captured.e;
|
||||||
|
this.progressCallback = captured.p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public complete(value: T) {
|
public complete(value: T) {
|
||||||
@@ -51,7 +54,13 @@ export class DeferredPPromise<C, P> extends PPromise<C, P> {
|
|||||||
private progressCallback: TProgressCallback<P>;
|
private progressCallback: TProgressCallback<P>;
|
||||||
|
|
||||||
constructor(init: (complete: TValueCallback<C>, error: (err: any) => void, progress: TProgressCallback<P>) => void = (c, e, p) => { }, oncancel?: any) {
|
constructor(init: (complete: TValueCallback<C>, error: (err: any) => void, progress: TProgressCallback<P>) => void = (c, e, p) => { }, oncancel?: any) {
|
||||||
super((c, e, p) => { this.completeCallback = c; this.errorCallback = e; this.progressCallback = p; }, oncancel ? oncancel : () => this.oncancel);
|
let captured: any;
|
||||||
|
super((c, e, p) => {
|
||||||
|
captured = { c, e, p };
|
||||||
|
}, oncancel ? oncancel : () => this.oncancel);
|
||||||
|
this.completeCallback = captured.c;
|
||||||
|
this.errorCallback = captured.e;
|
||||||
|
this.progressCallback = captured.p;
|
||||||
}
|
}
|
||||||
|
|
||||||
private oncancel(): void {
|
private oncancel(): void {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'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 { VSCodeWindow } from 'vs/code/electron-main/window';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
@@ -82,6 +82,7 @@ export class LaunchService implements ILaunchService {
|
|||||||
|
|
||||||
const openUrlArg = args['open-url'] || [];
|
const openUrlArg = args['open-url'] || [];
|
||||||
const openUrl = typeof openUrlArg === 'string' ? [openUrlArg] : openUrlArg;
|
const openUrl = typeof openUrlArg === 'string' ? [openUrlArg] : openUrlArg;
|
||||||
|
const context = !!userEnv['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.OTHER;
|
||||||
|
|
||||||
if (openUrl.length > 0) {
|
if (openUrl.length > 0) {
|
||||||
openUrl.forEach(url => this.urlService.open(url));
|
openUrl.forEach(url => this.urlService.open(url));
|
||||||
@@ -91,17 +92,19 @@ export class LaunchService implements ILaunchService {
|
|||||||
// Otherwise handle in windows service
|
// Otherwise handle in windows service
|
||||||
let usedWindows: VSCodeWindow[];
|
let usedWindows: VSCodeWindow[];
|
||||||
if (!!args.extensionDevelopmentPath) {
|
if (!!args.extensionDevelopmentPath) {
|
||||||
this.windowsService.openExtensionDevelopmentHostWindow({ cli: args, userEnv });
|
this.windowsService.openExtensionDevelopmentHostWindow({ context, cli: args, userEnv });
|
||||||
} else if (args._.length === 0 && args['new-window']) {
|
} else if (args._.length === 0 && args['new-window'] || args['new-window-if-not-first']) {
|
||||||
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) {
|
} else if (args._.length === 0) {
|
||||||
usedWindows = [this.windowsService.focusLastActive(args)];
|
usedWindows = [this.windowsService.focusLastActive(args, context)];
|
||||||
} else {
|
} else {
|
||||||
usedWindows = this.windowsService.open({
|
usedWindows = this.windowsService.open({
|
||||||
|
context,
|
||||||
cli: args,
|
cli: args,
|
||||||
userEnv,
|
userEnv,
|
||||||
forceNewWindow: args.wait || args['new-window'],
|
forceNewWindow: args.wait || args['new-window'] || args['new-window-if-not-first'],
|
||||||
preferNewWindow: !args['reuse-window'],
|
preferNewWindow: !args['reuse-window'],
|
||||||
|
forceReuseWindow: args['reuse-window'],
|
||||||
diffMode: args.diff
|
diffMode: args.diff
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
|
|||||||
import { parseMainProcessArgv } from 'vs/platform/environment/node/argv';
|
import { parseMainProcessArgv } from 'vs/platform/environment/node/argv';
|
||||||
import { mkdirp } from 'vs/base/node/pfs';
|
import { mkdirp } from 'vs/base/node/pfs';
|
||||||
import { validatePaths } from 'vs/code/electron-main/paths';
|
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 { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc';
|
import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc';
|
||||||
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
|
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
|
||||||
@@ -251,12 +251,13 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
|
|||||||
windowsMainService.ready(userEnv);
|
windowsMainService.ready(userEnv);
|
||||||
|
|
||||||
// Open our first window
|
// Open our first window
|
||||||
|
const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.OTHER;
|
||||||
if (environmentService.args['new-window'] && environmentService.args._.length === 0) {
|
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)) {
|
} 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 {
|
} 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'] || environmentService.args['new-window-if-not-first'], diffMode: environmentService.args.diff, initialStartup: true }); // default: read paths from cli
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install Menu
|
// Install Menu
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as platform from 'vs/base/common/platform';
|
|||||||
import * as arrays from 'vs/base/common/arrays';
|
import * as arrays from 'vs/base/common/arrays';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem } from 'electron';
|
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 { VSCodeWindow } from 'vs/code/electron-main/window';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IStorageService } from 'vs/code/electron-main/storage';
|
import { IStorageService } from 'vs/code/electron-main/storage';
|
||||||
@@ -315,7 +315,7 @@ export class VSCodeMenu {
|
|||||||
this.appMenuInstalled = true;
|
this.appMenuInstalled = true;
|
||||||
|
|
||||||
const dockMenu = new Menu();
|
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);
|
app.dock.setMenu(dockMenu);
|
||||||
}
|
}
|
||||||
@@ -351,19 +351,19 @@ export class VSCodeMenu {
|
|||||||
|
|
||||||
let newFile: Electron.MenuItem;
|
let newFile: Electron.MenuItem;
|
||||||
if (hasNoWindows) {
|
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 {
|
} else {
|
||||||
newFile = this.createMenuItem(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File"), 'workbench.action.files.newUntitledFile');
|
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 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: () => this.windowsService.openFolderPicker() }));
|
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;
|
let openFile: Electron.MenuItem;
|
||||||
if (hasNoWindows) {
|
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 {
|
} 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();
|
const openRecentMenu = new Menu();
|
||||||
@@ -379,7 +379,7 @@ export class VSCodeMenu {
|
|||||||
|
|
||||||
const preferences = this.getPreferencesMenu();
|
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 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 }));
|
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 {
|
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, {
|
return new MenuItem(this.likeAction(actionId, {
|
||||||
label: unMnemonicLabel(path), click: (menuItem, win, event) => {
|
label: unMnemonicLabel(label), click: (menuItem, win, event) => {
|
||||||
const openInNewWindow = event && ((!platform.isMacintosh && event.ctrlKey) || (platform.isMacintosh && event.metaKey));
|
const openInNewWindow = this.isOptionClick(event);
|
||||||
const success = !!this.windowsService.open({ cli: this.environmentService.args, pathsToOpen: [path], forceNewWindow: openInNewWindow });
|
const success = !!this.windowsService.open({ context: OpenContext.MENU, cli: this.environmentService.args, pathsToOpen: [path], forceNewWindow: openInNewWindow });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.windowsService.removeFromRecentPathsList(path);
|
this.windowsService.removeFromRecentPathsList(path);
|
||||||
}
|
}
|
||||||
@@ -479,6 +484,10 @@ export class VSCodeMenu {
|
|||||||
}, false));
|
}, 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 {
|
private createRoleMenuItem(label: string, actionId: string, role: Electron.MenuItemRole): Electron.MenuItem {
|
||||||
const options: Electron.MenuItemOptions = {
|
const options: Electron.MenuItemOptions = {
|
||||||
label: mnemonicLabel(label),
|
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(label: string, click: () => void, enabled?: boolean, checked?: boolean): Electron.MenuItem;
|
||||||
private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): Electron.MenuItem {
|
private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): Electron.MenuItem {
|
||||||
const label = mnemonicLabel(arg1);
|
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 enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsService.getWindowCount() > 0;
|
||||||
const checked = typeof arg4 === 'boolean' ? arg4 : false;
|
const checked = typeof arg4 === 'boolean' ? arg4 : false;
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ export interface IWindowConfiguration extends ParsedArgs {
|
|||||||
isInitialStartup?: boolean;
|
isInitialStartup?: boolean;
|
||||||
|
|
||||||
perfStartTime?: number;
|
perfStartTime?: number;
|
||||||
|
perfAppReady?: number;
|
||||||
perfWindowLoadTime?: number;
|
perfWindowLoadTime?: number;
|
||||||
|
|
||||||
workspacePath?: string;
|
workspacePath?: string;
|
||||||
@@ -205,21 +206,6 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||||||
this._win = new BrowserWindow(options);
|
this._win = new BrowserWindow(options);
|
||||||
this._id = this._win.id;
|
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) {
|
if (isFullscreenOrMaximized) {
|
||||||
this.win.maximize();
|
this.win.maximize();
|
||||||
|
|
||||||
@@ -238,9 +224,28 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||||||
this.setMenuBarVisibility(false); // respect configured menu bar visibility
|
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();
|
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 {
|
public hasHiddenTitleBarStyle(): boolean {
|
||||||
return this.hiddenTitleBarStyle;
|
return this.hiddenTitleBarStyle;
|
||||||
}
|
}
|
||||||
@@ -478,11 +483,12 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||||||
windowConfiguration.fullscreen = this._win.isFullScreen();
|
windowConfiguration.fullscreen = this._win.isFullScreen();
|
||||||
|
|
||||||
// Set Accessibility Config
|
// Set Accessibility Config
|
||||||
windowConfiguration.highContrast = platform.isWindows && systemPreferences.isInvertedColorScheme();
|
windowConfiguration.highContrast = platform.isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast);
|
||||||
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
|
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
|
||||||
|
|
||||||
// Perf Counters
|
// Perf Counters
|
||||||
windowConfiguration.perfStartTime = global.perfStartTime;
|
windowConfiguration.perfStartTime = global.perfStartTime;
|
||||||
|
windowConfiguration.perfAppReady = global.perfAppReady;
|
||||||
windowConfiguration.perfWindowLoadTime = Date.now();
|
windowConfiguration.perfWindowLoadTime = Date.now();
|
||||||
|
|
||||||
// Config (combination of process.argv and window configuration)
|
// Config (combination of process.argv and window configuration)
|
||||||
|
|||||||
@@ -34,12 +34,32 @@ enum WindowError {
|
|||||||
CRASHED
|
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 {
|
export interface IOpenConfiguration {
|
||||||
|
context: OpenContext;
|
||||||
cli: ParsedArgs;
|
cli: ParsedArgs;
|
||||||
userEnv?: platform.IProcessEnvironment;
|
userEnv?: platform.IProcessEnvironment;
|
||||||
pathsToOpen?: string[];
|
pathsToOpen?: string[];
|
||||||
preferNewWindow?: boolean;
|
preferNewWindow?: boolean;
|
||||||
forceNewWindow?: boolean;
|
forceNewWindow?: boolean;
|
||||||
|
forceReuseWindow?: boolean;
|
||||||
forceEmpty?: boolean;
|
forceEmpty?: boolean;
|
||||||
windowToUse?: VSCodeWindow;
|
windowToUse?: VSCodeWindow;
|
||||||
diffMode?: boolean;
|
diffMode?: boolean;
|
||||||
@@ -96,10 +116,10 @@ export interface IWindowsMainService {
|
|||||||
openFilePicker(forceNewWindow?: boolean, path?: string, window?: VSCodeWindow): void;
|
openFilePicker(forceNewWindow?: boolean, path?: string, window?: VSCodeWindow): void;
|
||||||
openFolderPicker(forceNewWindow?: boolean, window?: VSCodeWindow): void;
|
openFolderPicker(forceNewWindow?: boolean, window?: VSCodeWindow): void;
|
||||||
openAccessibilityOptions(): void;
|
openAccessibilityOptions(): void;
|
||||||
focusLastActive(cli: ParsedArgs): VSCodeWindow;
|
focusLastActive(cli: ParsedArgs, context: OpenContext): VSCodeWindow;
|
||||||
getLastActiveWindow(): VSCodeWindow;
|
getLastActiveWindow(): VSCodeWindow;
|
||||||
findWindow(workspacePath: string, filePath?: string, extensionDevelopmentPath?: string): VSCodeWindow;
|
findWindow(workspacePath: string, filePath?: string, extensionDevelopmentPath?: string): VSCodeWindow;
|
||||||
openNewWindow(): void;
|
openNewWindow(context: OpenContext): void;
|
||||||
sendToFocused(channel: string, ...args: any[]): void;
|
sendToFocused(channel: string, ...args: any[]): void;
|
||||||
sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void;
|
sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void;
|
||||||
getFocusedWindow(): VSCodeWindow;
|
getFocusedWindow(): VSCodeWindow;
|
||||||
@@ -166,7 +186,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
|
|
||||||
// Mac only event: open new window when we get activated
|
// Mac only event: open new window when we get activated
|
||||||
if (!hasVisibleWindows) {
|
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!
|
// Handle paths delayed in case more are coming!
|
||||||
runningTimeout = setTimeout(() => {
|
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 = [];
|
macOpenFiles = [];
|
||||||
runningTimeout = null;
|
runningTimeout = null;
|
||||||
}, 100);
|
}, 100);
|
||||||
@@ -272,6 +297,8 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public open(openConfig: IOpenConfiguration): VSCodeWindow[] {
|
public open(openConfig: IOpenConfiguration): VSCodeWindow[] {
|
||||||
|
const windowConfig = this.configurationService.getConfiguration<IWindowSettings>('window');
|
||||||
|
|
||||||
let iPathsToOpen: IPath[];
|
let iPathsToOpen: IPath[];
|
||||||
const usedWindows: VSCodeWindow[] = [];
|
const usedWindows: VSCodeWindow[] = [];
|
||||||
|
|
||||||
@@ -345,22 +372,26 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
filesToOpen = candidates;
|
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
|
// 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)) {
|
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;
|
let openFilesInNewWindow: boolean;
|
||||||
if (openConfig.forceNewWindow) {
|
if (openConfig.forceNewWindow || openConfig.forceReuseWindow) {
|
||||||
openFilesInNewWindow = true;
|
openFilesInNewWindow = openConfig.forceNewWindow && !openConfig.forceReuseWindow;
|
||||||
} else {
|
} else {
|
||||||
openFilesInNewWindow = openConfig.preferNewWindow;
|
if (openConfig.context === OpenContext.DOCK) {
|
||||||
if (openFilesInNewWindow && !openConfig.cli.extensionDevelopmentPath) { // can be overriden via settings (not for PDE though!)
|
openFilesInNewWindow = true; // only on macOS do we allow to open files in a new window if this is triggered via DOCK context
|
||||||
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.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();
|
const lastActiveWindow = this.getLastActiveWindow();
|
||||||
if (!openFilesInNewWindow && lastActiveWindow) {
|
if (!openFilesInNewWindow && lastActiveWindow) {
|
||||||
lastActiveWindow.focus();
|
lastActiveWindow.focus();
|
||||||
|
const files = { filesToOpen, filesToCreate, filesToDiff }; // copy to object because they get reset shortly after
|
||||||
lastActiveWindow.ready().then(readyWindow => {
|
lastActiveWindow.ready().then(readyWindow => {
|
||||||
readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff });
|
readyWindow.send('vscode:openFiles', files);
|
||||||
});
|
});
|
||||||
|
|
||||||
usedWindows.push(lastActiveWindow);
|
usedWindows.push(lastActiveWindow);
|
||||||
@@ -381,7 +413,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
const browserWindow = this.openInBrowserWindow(configuration, true /* new window */);
|
const browserWindow = this.openInBrowserWindow(configuration, true /* new window */);
|
||||||
usedWindows.push(browserWindow);
|
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
|
// Reset these because we handled them
|
||||||
@@ -399,8 +431,9 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
if (windowsOnWorkspacePath.length > 0) {
|
if (windowsOnWorkspacePath.length > 0) {
|
||||||
const browserWindow = windowsOnWorkspacePath[0];
|
const browserWindow = windowsOnWorkspacePath[0];
|
||||||
browserWindow.focus(); // just focus one of them
|
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 => {
|
browserWindow.ready().then(readyWindow => {
|
||||||
readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff });
|
readyWindow.send('vscode:openFiles', files);
|
||||||
});
|
});
|
||||||
|
|
||||||
usedWindows.push(browserWindow);
|
usedWindows.push(browserWindow);
|
||||||
@@ -410,7 +443,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
filesToCreate = [];
|
filesToCreate = [];
|
||||||
filesToDiff = [];
|
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
|
// Open remaining ones
|
||||||
@@ -420,7 +453,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const configuration = this.toConfiguration(openConfig, folderToOpen, filesToOpen, filesToCreate, filesToDiff);
|
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);
|
usedWindows.push(browserWindow);
|
||||||
|
|
||||||
// Reset these because we handled them
|
// Reset these because we handled them
|
||||||
@@ -428,7 +461,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
filesToCreate = [];
|
filesToCreate = [];
|
||||||
filesToDiff = [];
|
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);
|
const browserWindow = this.openInBrowserWindow(configuration, true /* new window */, null, emptyWorkspaceBackupFolder);
|
||||||
usedWindows.push(browserWindow);
|
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) {
|
else if (emptyToOpen.length > 0) {
|
||||||
emptyToOpen.forEach(() => {
|
emptyToOpen.forEach(() => {
|
||||||
const configuration = this.toConfiguration(openConfig);
|
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);
|
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
|
// 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 {
|
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 {
|
private doPickAndOpen(options: INativeOpenDialogOptions): void {
|
||||||
this.getFileOrFolderPaths(options, (paths: string[]) => {
|
this.getFileOrFolderPaths(options, (paths: string[]) => {
|
||||||
if (paths && paths.length) {
|
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();
|
const lastActive = this.getLastActiveWindow();
|
||||||
if (lastActive) {
|
if (lastActive) {
|
||||||
lastActive.focus();
|
lastActive.focus();
|
||||||
@@ -932,7 +965,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
|
|
||||||
// No window - open new one
|
// No window - open new one
|
||||||
this.windowsState.openedFolders = []; // make sure we do not open too much
|
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];
|
return res && res[0];
|
||||||
}
|
}
|
||||||
@@ -994,8 +1027,8 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public openNewWindow(): void {
|
public openNewWindow(context: OpenContext): void {
|
||||||
this.open({ cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true });
|
this.open({ context, cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendToFocused(channel: string, ...args: any[]): void {
|
public sendToFocused(channel: string, ...args: any[]): void {
|
||||||
|
|||||||
@@ -41,41 +41,6 @@ class CSSBasedConfigurationCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CharWidthReader {
|
|
||||||
|
|
||||||
private _chr: string;
|
|
||||||
private _width: number;
|
|
||||||
|
|
||||||
public get width(): number { return this._width; }
|
|
||||||
|
|
||||||
constructor(chr: string) {
|
|
||||||
this._chr = chr;
|
|
||||||
this._width = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(out: HTMLSpanElement): void {
|
|
||||||
if (this._chr === ' ') {
|
|
||||||
let htmlString = ' ';
|
|
||||||
// Repeat character 256 (2^8) times
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
htmlString += htmlString;
|
|
||||||
}
|
|
||||||
out.innerHTML = htmlString;
|
|
||||||
} else {
|
|
||||||
let testString = this._chr;
|
|
||||||
// Repeat character 256 (2^8) times
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
testString += testString;
|
|
||||||
}
|
|
||||||
out.textContent = testString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public read(out: HTMLSpanElement): void {
|
|
||||||
this._width = out.offsetWidth / 256;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CSSBasedConfiguration extends Disposable {
|
class CSSBasedConfiguration extends Disposable {
|
||||||
|
|
||||||
public static INSTANCE = new CSSBasedConfiguration();
|
public static INSTANCE = new CSSBasedConfiguration();
|
||||||
@@ -154,59 +119,15 @@ class CSSBasedConfiguration extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _testElementId(index: number): string {
|
|
||||||
return 'editorSizeProvider' + index;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _createTestElements(bareFontInfo: BareFontInfo, readers: CharWidthReader[]): HTMLElement {
|
|
||||||
let container = document.createElement('div');
|
|
||||||
Configuration.applyFontInfoSlow(container, bareFontInfo);
|
|
||||||
container.style.position = 'absolute';
|
|
||||||
container.style.top = '-50000px';
|
|
||||||
container.style.width = '50000px';
|
|
||||||
|
|
||||||
for (let i = 0, len = readers.length; i < len; i++) {
|
|
||||||
container.appendChild(document.createElement('br'));
|
|
||||||
|
|
||||||
let testElement = document.createElement('span');
|
|
||||||
testElement.id = this._testElementId(i);
|
|
||||||
readers[i].render(testElement);
|
|
||||||
|
|
||||||
container.appendChild(testElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
container.appendChild(document.createElement('br'));
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _readFromTestElements(readers: CharWidthReader[]): void {
|
|
||||||
for (let i = 0, len = readers.length; i < len; i++) {
|
|
||||||
readers[i].read(document.getElementById(this._testElementId(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _runReaders(bareFontInfo: BareFontInfo, readers: CharWidthReader[]): void {
|
|
||||||
// Create a test container with all these test elements
|
|
||||||
let testContainer = this._createTestElements(bareFontInfo, readers);
|
|
||||||
|
|
||||||
// Add the container to the DOM
|
|
||||||
document.body.appendChild(testContainer);
|
|
||||||
|
|
||||||
// Read various properties
|
|
||||||
this._readFromTestElements(readers);
|
|
||||||
|
|
||||||
// Remove the container from the DOM
|
|
||||||
document.body.removeChild(testContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _actualReadConfiguration(bareFontInfo: BareFontInfo): FontInfo {
|
private static _actualReadConfiguration(bareFontInfo: BareFontInfo): FontInfo {
|
||||||
let typicalHalfwidthCharacter = new CharWidthReader('n');
|
let canvasElem = <HTMLCanvasElement>document.createElement('canvas');
|
||||||
let typicalFullwidthCharacter = new CharWidthReader('\uff4d');
|
let context = canvasElem.getContext('2d');
|
||||||
let space = new CharWidthReader(' ');
|
context.font = `normal normal normal normal ${bareFontInfo.fontSize}px / ${bareFontInfo.lineHeight}px ${bareFontInfo.fontFamily}`;
|
||||||
let digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].map(chr => new CharWidthReader(chr));
|
|
||||||
|
|
||||||
this._runReaders(bareFontInfo, digits.concat([typicalHalfwidthCharacter, typicalFullwidthCharacter, space]));
|
let typicalHalfwidthCharacter = context.measureText('n');
|
||||||
|
let typicalFullwidthCharacter = context.measureText('\uff4d');
|
||||||
|
let space = context.measureText(' ');
|
||||||
|
let digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].map(chr => context.measureText(chr));
|
||||||
|
|
||||||
let maxDigitWidth = 0;
|
let maxDigitWidth = 0;
|
||||||
for (let i = 0, len = digits.length; i < len; i++) {
|
for (let i = 0, len = digits.length; i < len; i++) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { EmitterEvent, IEventEmitter } from 'vs/base/common/eventEmitter';
|
import { EmitterEvent, IEventEmitter } from 'vs/base/common/eventEmitter';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import * as timer from 'vs/base/common/timer';
|
|
||||||
import * as browser from 'vs/base/browser/browser';
|
import * as browser from 'vs/base/browser/browser';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { StyleMutator } from 'vs/base/browser/styleMutator';
|
import { StyleMutator } from 'vs/base/browser/styleMutator';
|
||||||
@@ -899,14 +898,12 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
|
|||||||
if (!dom.isInDOM(this.domNode)) {
|
if (!dom.isInDOM(this.domNode)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let t = timer.start(timer.Topic.EDITOR, 'View.render');
|
|
||||||
|
|
||||||
let viewPartsToRender = this._getViewPartsToRender();
|
let viewPartsToRender = this._getViewPartsToRender();
|
||||||
|
|
||||||
if (!this.viewLines.shouldRender() && viewPartsToRender.length === 0) {
|
if (!this.viewLines.shouldRender() && viewPartsToRender.length === 0) {
|
||||||
// Nothing to render
|
// Nothing to render
|
||||||
this.keyboardHandler.writeToTextArea();
|
this.keyboardHandler.writeToTextArea();
|
||||||
t.stop();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,8 +937,6 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
|
|||||||
|
|
||||||
// Render the scrollbar
|
// Render the scrollbar
|
||||||
this.layoutProvider.renderScrollbar();
|
this.layoutProvider.renderScrollbar();
|
||||||
|
|
||||||
t.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setHasFocus(newHasFocus: boolean): void {
|
private _setHasFocus(newHasFocus: boolean): void {
|
||||||
|
|||||||
@@ -598,50 +598,8 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
|
|||||||
protected abstract readConfiguration(styling: editorCommon.BareFontInfo): editorCommon.FontInfo;
|
protected abstract readConfiguration(styling: editorCommon.BareFontInfo): editorCommon.FontInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const configurationRegistry = <IConfigurationRegistry>Registry.as(Extensions.Configuration);
|
||||||
* Helper to update Monaco Editor Settings from configurations service.
|
const editorConfiguration: IConfigurationNode = {
|
||||||
*/
|
|
||||||
export class EditorConfiguration {
|
|
||||||
public static EDITOR_SECTION = 'editor';
|
|
||||||
public static DIFF_EDITOR_SECTION = 'diffEditor';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask the provided configuration service to apply its configuration to the provided editor.
|
|
||||||
*/
|
|
||||||
public static apply(config: any, editor: editorCommon.IEditor): void {
|
|
||||||
if (!config) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Editor Settings (Code Editor, Diff, Terminal)
|
|
||||||
if (editor && typeof editor.updateOptions === 'function') {
|
|
||||||
let type = editor.getEditorType();
|
|
||||||
if (type !== editorCommon.EditorType.ICodeEditor && type !== editorCommon.EditorType.IDiffEditor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let editorConfig = config[EditorConfiguration.EDITOR_SECTION];
|
|
||||||
if (type === editorCommon.EditorType.IDiffEditor) {
|
|
||||||
let diffEditorConfig = config[EditorConfiguration.DIFF_EDITOR_SECTION];
|
|
||||||
if (diffEditorConfig) {
|
|
||||||
if (!editorConfig) {
|
|
||||||
editorConfig = diffEditorConfig;
|
|
||||||
} else {
|
|
||||||
editorConfig = objects.mixin(editorConfig, diffEditorConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editorConfig) {
|
|
||||||
delete editorConfig.readOnly; // Prevent someone from making editor readonly
|
|
||||||
editor.updateOptions(editorConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let configurationRegistry = <IConfigurationRegistry>Registry.as(Extensions.Configuration);
|
|
||||||
let editorConfiguration: IConfigurationNode = {
|
|
||||||
'id': 'editor',
|
'id': 'editor',
|
||||||
'order': 5,
|
'order': 5,
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import * as nls from 'vs/nls';
|
|||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||||
import * as timer from 'vs/base/common/timer';
|
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
@@ -294,7 +293,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
|
|||||||
|
|
||||||
this._withModelTokensChangedEventBuilder((eventBuilder) => {
|
this._withModelTokensChangedEventBuilder((eventBuilder) => {
|
||||||
|
|
||||||
var t1 = timer.start(timer.Topic.EDITOR, 'backgroundTokenization');
|
|
||||||
toLineNumber = Math.min(this._lines.length, toLineNumber);
|
toLineNumber = Math.min(this._lines.length, toLineNumber);
|
||||||
|
|
||||||
var MAX_ALLOWED_TIME = 20,
|
var MAX_ALLOWED_TIME = 20,
|
||||||
@@ -342,8 +340,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
|
|||||||
if (this._invalidLineStartIndex < this._lines.length) {
|
if (this._invalidLineStartIndex < this._lines.length) {
|
||||||
this._beginBackgroundTokenization();
|
this._beginBackgroundTokenization();
|
||||||
}
|
}
|
||||||
|
|
||||||
t1.stop();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ const enum CharacterClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const classifier = (function () {
|
const classifier = (function () {
|
||||||
let result = new CharacterClassifier(CharacterClass.None);
|
let result = new CharacterClassifier<CharacterClass>(CharacterClass.None);
|
||||||
|
|
||||||
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
|
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
|
||||||
for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {
|
for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ChangeRecorder {
|
|||||||
|
|
||||||
private _fileService: IFileService;
|
private _fileService: IFileService;
|
||||||
|
|
||||||
constructor(fileService: IFileService) {
|
constructor(fileService?: IFileService) {
|
||||||
this._fileService = fileService;
|
this._fileService = fileService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,9 @@ class ChangeRecorder {
|
|||||||
|
|
||||||
const changes: IStringDictionary<IFileChange[]> = Object.create(null);
|
const changes: IStringDictionary<IFileChange[]> = Object.create(null);
|
||||||
|
|
||||||
const stop = this._fileService.onFileChanges((event) => {
|
let stop: IDisposable;
|
||||||
|
if (this._fileService) {
|
||||||
|
stop = this._fileService.onFileChanges((event) => {
|
||||||
event.changes.forEach(change => {
|
event.changes.forEach(change => {
|
||||||
|
|
||||||
const key = String(change.resource);
|
const key = String(change.resource);
|
||||||
@@ -55,9 +57,10 @@ class ChangeRecorder {
|
|||||||
array.push(change);
|
array.push(change);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stop: () => { stop.dispose(); },
|
stop: () => { return stop && stop.dispose(); },
|
||||||
hasChanged: (resource: URI) => !!changes[resource.toString()],
|
hasChanged: (resource: URI) => !!changes[resource.toString()],
|
||||||
allChanges: () => flatten(values(changes))
|
allChanges: () => flatten(values(changes))
|
||||||
};
|
};
|
||||||
@@ -273,14 +276,14 @@ export interface BulkEdit {
|
|||||||
finish(): TPromise<ISelection>;
|
finish(): TPromise<ISelection>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bulkEdit(fileService: IFileService, textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor, edits: IResourceEdit[], progress: IProgressRunner = null): TPromise<any> {
|
export function bulkEdit(textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor, edits: IResourceEdit[], fileService?: IFileService, progress: IProgressRunner = null): TPromise<any> {
|
||||||
let bulk = createBulkEdit(fileService, textModelResolverService, editor);
|
let bulk = createBulkEdit(textModelResolverService, editor, fileService);
|
||||||
bulk.add(edits);
|
bulk.add(edits);
|
||||||
bulk.progress(progress);
|
bulk.progress(progress);
|
||||||
return bulk.finish();
|
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 all: IResourceEdit[] = [];
|
||||||
let recording = new ChangeRecorder(fileService).start();
|
let recording = new ChangeRecorder(fileService).start();
|
||||||
|
|||||||
@@ -11,12 +11,11 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
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 { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
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 { ICommonCodeEditor, IEditorContribution, MouseTargetType, EditorContextKeys, IScrollEvent } from 'vs/editor/common/editorCommon';
|
||||||
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||||
import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||||
@@ -125,9 +124,17 @@ export class ContextMenuController implements IEditorContribution {
|
|||||||
|
|
||||||
private _getMenuActions(): IAction[] {
|
private _getMenuActions(): IAction[] {
|
||||||
const result: 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();
|
contextMenu.dispose();
|
||||||
|
|
||||||
|
for (let group of groups) {
|
||||||
|
const [, actions] = group;
|
||||||
|
result.push(...actions);
|
||||||
|
result.push(new Separator());
|
||||||
|
}
|
||||||
|
result.pop(); // remove last separator
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,10 +105,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget.no-results .matchesCount {
|
.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 {
|
.monaco-editor .find-widget .matchesCount {
|
||||||
|
|||||||
@@ -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_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_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_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;
|
let MAX_MATCHES_COUNT_WIDTH = 69;
|
||||||
const WIDGET_FIXED_WIDTH = 411 - 69;
|
const WIDGET_FIXED_WIDTH = 411 - 69;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class DefinitionAction extends EditorAction {
|
|||||||
let result: Location[] = [];
|
let result: Location[] = [];
|
||||||
for (let i = 0; i < references.length; i++) {
|
for (let i = 0; i < references.length; i++) {
|
||||||
let reference = references[i];
|
let reference = references[i];
|
||||||
if (!reference) {
|
if (!reference || !reference.range) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let {uri, range} = reference;
|
let {uri, range} = reference;
|
||||||
@@ -110,7 +110,7 @@ export class DefinitionAction extends EditorAction {
|
|||||||
} else {
|
} else {
|
||||||
let next = model.nearestReference(editor.getModel().uri, editor.getPosition());
|
let next = model.nearestReference(editor.getModel().uri, editor.getPosition());
|
||||||
this._openReference(editorService, next, this._configuration.openToSide).then(editor => {
|
this._openReference(editorService, next, this._configuration.openToSide).then(editor => {
|
||||||
if (model.references.length > 1) {
|
if (editor && model.references.length > 1) {
|
||||||
this._openInPeek(editorService, editor, model);
|
this._openInPeek(editorService, editor, model);
|
||||||
} else {
|
} else {
|
||||||
model.dispose();
|
model.dispose();
|
||||||
@@ -128,7 +128,7 @@ export class DefinitionAction extends EditorAction {
|
|||||||
revealIfVisible: !sideBySide
|
revealIfVisible: !sideBySide
|
||||||
}
|
}
|
||||||
}, sideBySide).then(editor => {
|
}, sideBySide).then(editor => {
|
||||||
return <editorCommon.IEditor>editor.getControl();
|
return editor && <editorCommon.IEditor>editor.getControl();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .lightbulb-glyph:hover {
|
.monaco-editor .lightbulb-glyph:hover {
|
||||||
@@ -16,12 +18,18 @@
|
|||||||
|
|
||||||
.monaco-editor.vs .lightbulb-glyph {
|
.monaco-editor.vs .lightbulb-glyph {
|
||||||
background: url('lightbulb.svg') center center no-repeat;
|
background: url('lightbulb.svg') center center no-repeat;
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor.vs-dark .lightbulb-glyph, .monaco-editor.hc-black .lightbulb-glyph {
|
.monaco-editor.vs .lightbulb-glyph[data-severity="high"]{
|
||||||
background: url('lightbulb-dark.svg') center center no-repeat;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,10 @@
|
|||||||
import 'vs/css!./lightBulbWidget';
|
import 'vs/css!./lightBulbWidget';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import Event, { Emitter, any } from 'vs/base/common/event';
|
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 * as dom from 'vs/base/browser/dom';
|
||||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
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 {
|
export class LightBulbWidget implements IOverlayWidget, IDisposable {
|
||||||
@@ -86,7 +87,7 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable {
|
|||||||
const modelNow = this._model;
|
const modelNow = this._model;
|
||||||
e.fixes.done(fixes => {
|
e.fixes.done(fixes => {
|
||||||
if (modelNow === this._model && fixes && fixes.length > 0) {
|
if (modelNow === this._model && fixes && fixes.length > 0) {
|
||||||
this.show(e.range.startLineNumber);
|
this.show(e);
|
||||||
} else {
|
} else {
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,8 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable {
|
|||||||
return this._model;
|
return this._model;
|
||||||
}
|
}
|
||||||
|
|
||||||
show(line: number): void {
|
show(e: QuickFixComputeEvent): void {
|
||||||
|
const line = e.range.startLineNumber;
|
||||||
if (!this._hasSpaceInGlyphMargin(line)) {
|
if (!this._hasSpaceInGlyphMargin(line)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -107,6 +109,7 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable {
|
|||||||
this._line = line;
|
this._line = line;
|
||||||
this._visible = true;
|
this._visible = true;
|
||||||
this._layout();
|
this._layout();
|
||||||
|
this._domNode.dataset['severity'] = e.severity >= Severity.Warning ? 'high' : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import { ICommonCodeEditor, EditorContextKeys, ModeContextKeys, IEditorContribut
|
|||||||
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||||
import { QuickFixContextMenu } from './quickFixWidget';
|
import { QuickFixContextMenu } from 'vs/editor/contrib/quickFix/browser/quickFixWidget';
|
||||||
import { LightBulbWidget } from './lightBulbWidget';
|
import { LightBulbWidget } from 'vs/editor/contrib/quickFix/browser/lightBulbWidget';
|
||||||
import { QuickFixModel, QuickFixComputeEvent } from './quickFixModel';
|
import { QuickFixModel, QuickFixComputeEvent } from 'vs/editor/contrib/quickFix/common/quickFixModel';
|
||||||
|
|
||||||
@editorContribution
|
@editorContribution
|
||||||
export class QuickFixController implements IEditorContribution {
|
export class QuickFixController implements IEditorContribution {
|
||||||
@@ -88,7 +88,7 @@ export class QuickFixController implements IEditorContribution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public triggerFromEditorSelection(): void {
|
public triggerFromEditorSelection(): void {
|
||||||
this._model.triggerManual(this._editor.getSelection());
|
this._model.triggerManual();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateLightBulbTitle(): void {
|
private _updateLightBulbTitle(): void {
|
||||||
|
|||||||
+66
-47
@@ -6,21 +6,21 @@
|
|||||||
|
|
||||||
import * as arrays from 'vs/base/common/arrays';
|
import * as arrays from 'vs/base/common/arrays';
|
||||||
import Event, { Emitter } from 'vs/base/common/event';
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
import Severity from 'vs/base/common/severity';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IMarker, IMarkerService } from 'vs/platform/markers/common/markers';
|
import { IMarker, IMarkerService } from 'vs/platform/markers/common/markers';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
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 { ICommonCodeEditor, IPosition, IRange } from 'vs/editor/common/editorCommon';
|
||||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|
||||||
import { CodeActionProviderRegistry, CodeAction } from 'vs/editor/common/modes';
|
import { CodeActionProviderRegistry, CodeAction } from 'vs/editor/common/modes';
|
||||||
import { getCodeActions } from '../common/quickFix';
|
import { getCodeActions } from '../common/quickFix';
|
||||||
|
|
||||||
|
|
||||||
class QuickFixOracle {
|
export class QuickFixOracle {
|
||||||
|
|
||||||
private _disposables: IDisposable[] = [];
|
private _disposables: IDisposable[] = [];
|
||||||
|
private _currentRange: IRange;
|
||||||
|
|
||||||
constructor(private _editor: ICommonCodeEditor, private _markerService: IMarkerService, private _signalChange: (e: QuickFixComputeEvent) => any) {
|
constructor(private _editor: ICommonCodeEditor, private _markerService: IMarkerService, private _signalChange: (e: QuickFixComputeEvent) => any) {
|
||||||
|
|
||||||
@@ -34,29 +34,57 @@ class QuickFixOracle {
|
|||||||
this._disposables = dispose(this._disposables);
|
this._disposables = dispose(this._disposables);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onMarkerChanges(resources: URI[]): void {
|
trigger(): void {
|
||||||
const {uri} = this._editor.getModel();
|
let {range, severity} = this._rangeAtPosition();
|
||||||
let affectedBy = false;
|
if (!range) {
|
||||||
for (const resource of resources) {
|
range = this._editor.getSelection();
|
||||||
if (resource.toString() === uri.toString()) {
|
|
||||||
affectedBy = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (affectedBy) {
|
|
||||||
this._onCursorChange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onCursorChange(): void {
|
|
||||||
const range = this._markerAtPosition() || this._wordAtPosition();
|
|
||||||
|
|
||||||
this._signalChange({
|
this._signalChange({
|
||||||
type: 'auto',
|
type: 'manual',
|
||||||
|
severity,
|
||||||
range,
|
range,
|
||||||
position: this._editor.getPosition(),
|
position: this._editor.getPosition(),
|
||||||
fixes: range && getCodeActions(this._editor.getModel(), this._editor.getModel().validateRange(range))
|
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 {
|
private _markerAtPosition(): IMarker {
|
||||||
@@ -76,26 +104,23 @@ class QuickFixOracle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _wordAtPosition(): IRange {
|
private _wordAtPosition(): IRange {
|
||||||
return;
|
const {positionLineNumber, positionColumn} = this._editor.getSelection();
|
||||||
// todo@joh - enable once we decide to eagerly show the
|
const model = this._editor.getModel();
|
||||||
// light bulb as the cursor moves
|
const info = model.getWordAtPosition({ lineNumber: positionLineNumber, column: positionColumn });
|
||||||
// const {positionLineNumber, positionColumn} = this._editor.getSelection();
|
if (info) {
|
||||||
// const model = this._editor.getModel();
|
return {
|
||||||
|
startLineNumber: positionLineNumber,
|
||||||
// const info = model.getWordAtPosition({ lineNumber: positionLineNumber, column: positionColumn });
|
startColumn: info.startColumn,
|
||||||
// if (info) {
|
endLineNumber: positionLineNumber,
|
||||||
// return {
|
endColumn: info.endColumn
|
||||||
// startLineNumber: positionLineNumber,
|
};
|
||||||
// startColumn: info.startColumn,
|
}
|
||||||
// endLineNumber: positionLineNumber,
|
|
||||||
// endColumn: info.endColumn
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QuickFixComputeEvent {
|
export interface QuickFixComputeEvent {
|
||||||
type: 'auto' | 'manual';
|
type: 'auto' | 'manual';
|
||||||
|
severity: Severity;
|
||||||
range: IRange;
|
range: IRange;
|
||||||
position: IPosition;
|
position: IPosition;
|
||||||
fixes: TPromise<CodeAction[]>;
|
fixes: TPromise<CodeAction[]>;
|
||||||
@@ -109,7 +134,7 @@ export class QuickFixModel {
|
|||||||
private _onDidChangeFixes = new Emitter<QuickFixComputeEvent>();
|
private _onDidChangeFixes = new Emitter<QuickFixComputeEvent>();
|
||||||
private _disposables: IDisposable[] = [];
|
private _disposables: IDisposable[] = [];
|
||||||
|
|
||||||
constructor(editor: ICodeEditor, markerService: IMarkerService) {
|
constructor(editor: ICommonCodeEditor, markerService: IMarkerService) {
|
||||||
this._editor = editor;
|
this._editor = editor;
|
||||||
this._markerService = markerService;
|
this._markerService = markerService;
|
||||||
|
|
||||||
@@ -132,7 +157,8 @@ export class QuickFixModel {
|
|||||||
private _update(): void {
|
private _update(): void {
|
||||||
|
|
||||||
if (this._quickFixOracle) {
|
if (this._quickFixOracle) {
|
||||||
dispose(this._quickFixOracle);
|
this._quickFixOracle.dispose();
|
||||||
|
this._quickFixOracle = undefined;
|
||||||
this._onDidChangeFixes.fire(undefined);
|
this._onDidChangeFixes.fire(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,16 +170,9 @@ export class QuickFixModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerManual(selection: Selection): void {
|
triggerManual(): void {
|
||||||
const model = this._editor.getModel();
|
if (this._quickFixOracle) {
|
||||||
if (model) {
|
this._quickFixOracle.trigger();
|
||||||
const fixes = getCodeActions(model, selection);
|
|
||||||
this._onDidChangeFixes.fire({
|
|
||||||
type: 'manual',
|
|
||||||
range: selection,
|
|
||||||
position: { lineNumber: selection.positionLineNumber, column: selection.positionColumn },
|
|
||||||
fixes
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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 } from 'vs/editor/common/modes';
|
||||||
|
|
||||||
|
|
||||||
|
suite('QuickFix', () => {
|
||||||
|
|
||||||
|
let uri = URI.parse('fake:path');
|
||||||
|
let model = Model.createFromString('foobar foo bar\nfarboo far boo', undefined, 'foo-lang', uri);
|
||||||
|
let markerService: MarkerService;
|
||||||
|
let editor: ICommonCodeEditor;
|
||||||
|
|
||||||
|
let reg = CodeActionProviderRegistry.register('foo-lang', {
|
||||||
|
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('foo-lang', {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -22,6 +22,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||||||
import { rename } from '../common/rename';
|
import { rename } from '../common/rename';
|
||||||
import RenameInputField from './renameInputField';
|
import RenameInputField from './renameInputField';
|
||||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||||
|
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
// --- register actions and commands
|
// --- register actions and commands
|
||||||
|
|
||||||
@@ -42,10 +43,10 @@ class RenameController implements IEditorContribution {
|
|||||||
constructor(
|
constructor(
|
||||||
private editor: ICodeEditor,
|
private editor: ICodeEditor,
|
||||||
@IMessageService private _messageService: IMessageService,
|
@IMessageService private _messageService: IMessageService,
|
||||||
@IFileService private _fileService: IFileService,
|
|
||||||
@ITextModelResolverService private _textModelResolverService: ITextModelResolverService,
|
@ITextModelResolverService private _textModelResolverService: ITextModelResolverService,
|
||||||
@IProgressService private _progressService: IProgressService,
|
@IProgressService private _progressService: IProgressService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
|
@optional(IFileService) private _fileService: IFileService
|
||||||
) {
|
) {
|
||||||
this._renameInputField = new RenameInputField(editor);
|
this._renameInputField = new RenameInputField(editor);
|
||||||
this._renameInputVisible = CONTEXT_RENAME_INPUT_VISIBLE.bindTo(contextKeyService);
|
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
|
// start recording of file changes so that we can figure out if a file that
|
||||||
// is to be renamed conflicts with another (concurrent) modification
|
// 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 => {
|
return rename(this.editor.getModel(), this.editor.getPosition(), newName).then(result => {
|
||||||
if (result.rejectReason) {
|
if (result.rejectReason) {
|
||||||
|
|||||||
@@ -122,15 +122,15 @@ export class CodeSnippet implements ICodeSnippet {
|
|||||||
|
|
||||||
for (let {startLineNumber, startColumn, endLineNumber, endColumn} of originalPlaceHolder.occurences) {
|
for (let {startLineNumber, startColumn, endLineNumber, endColumn} of originalPlaceHolder.occurences) {
|
||||||
|
|
||||||
if (startColumn > 1) {
|
if (startColumn > 1 || startLineNumber === 1) {
|
||||||
// placeholders that aren't at the beginning of the snippet line
|
// placeholders that aren't at the beginning of new snippet lines
|
||||||
// will be moved by how many characters the indentation has been
|
// will be moved by how many characters the indentation has been
|
||||||
// adjusted
|
// adjusted
|
||||||
startColumn = startColumn + deltaColumns[startLineNumber];
|
startColumn = startColumn + deltaColumns[startLineNumber];
|
||||||
endColumn = endColumn + deltaColumns[endLineNumber];
|
endColumn = endColumn + deltaColumns[endLineNumber];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// placeholders at the beginning of the snippet line
|
// placeholders at the beginning of new snippet lines
|
||||||
// will be indented by the reference indentation
|
// will be indented by the reference indentation
|
||||||
startColumn += referenceIndentation.length;
|
startColumn += referenceIndentation.length;
|
||||||
endColumn += referenceIndentation.length;
|
endColumn += referenceIndentation.length;
|
||||||
@@ -140,7 +140,7 @@ export class CodeSnippet implements ICodeSnippet {
|
|||||||
startLineNumber: startLineNumber + deltaLine,
|
startLineNumber: startLineNumber + deltaLine,
|
||||||
startColumn,
|
startColumn,
|
||||||
endLineNumber: endLineNumber + deltaLine,
|
endLineNumber: endLineNumber + deltaLine,
|
||||||
endColumn
|
endColumn,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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([
|
let snippet = CodeSnippet.fromTextmate([
|
||||||
'afterEach((done) => {',
|
'afterEach((done) => {',
|
||||||
@@ -242,6 +242,7 @@ suite('Editor Contrib - Snippets', () => {
|
|||||||
assert.equal(boundSnippet.lines[1], ' test');
|
assert.equal(boundSnippet.lines[1], ' test');
|
||||||
assert.equal(boundSnippet.placeHolders.length, 3);
|
assert.equal(boundSnippet.placeHolders.length, 3);
|
||||||
assert.equal(boundSnippet.finishPlaceHolderIndex, 2);
|
assert.equal(boundSnippet.finishPlaceHolderIndex, 2);
|
||||||
|
|
||||||
let [first, second] = boundSnippet.placeHolders;
|
let [first, second] = boundSnippet.placeHolders;
|
||||||
assert.equal(first.occurences.length, 1);
|
assert.equal(first.occurences.length, 1);
|
||||||
assert.equal(first.occurences[0].startColumn, 1);
|
assert.equal(first.occurences[0].startColumn, 1);
|
||||||
@@ -249,6 +250,49 @@ suite('Editor Contrib - Snippets', () => {
|
|||||||
assert.equal(second.occurences[0].startColumn, 7);
|
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', () => {
|
test('variables, simple', () => {
|
||||||
|
|
||||||
const resolver: ISnippetVariableResolver = {
|
const resolver: ISnippetVariableResolver = {
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
|||||||
import { forEach } from 'vs/base/common/collections';
|
import { forEach } from 'vs/base/common/collections';
|
||||||
import Event, { Emitter } from 'vs/base/common/event';
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { startsWith } from 'vs/base/common/strings';
|
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
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 { ISuggestSupport, SuggestRegistry } from 'vs/editor/common/modes';
|
||||||
import { provideSuggestionItems, getSuggestionComparator, ISuggestionItem } from './suggest';
|
import { provideSuggestionItems, getSuggestionComparator, ISuggestionItem } from './suggest';
|
||||||
import { CompletionModel } from './completionModel';
|
import { CompletionModel } from './completionModel';
|
||||||
@@ -30,104 +29,51 @@ export interface ISuggestEvent {
|
|||||||
auto: boolean;
|
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 lineNumber: number;
|
||||||
readonly column: number;
|
readonly column: number;
|
||||||
readonly isInEditableRange: boolean;
|
readonly leadingLineContent: string;
|
||||||
|
readonly leadingWord: IWordAtPosition;
|
||||||
readonly lineContentBefore: string;
|
readonly auto;
|
||||||
|
|
||||||
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 = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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.lineNumber = position.lineNumber;
|
||||||
this.column = position.column;
|
this.column = position.column;
|
||||||
this.lineContentBefore = lineContent.substr(0, position.column - 1);
|
this.auto = auto;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +93,7 @@ export class SuggestModel implements IDisposable {
|
|||||||
private state: State;
|
private state: State;
|
||||||
|
|
||||||
private requestPromise: TPromise<void>;
|
private requestPromise: TPromise<void>;
|
||||||
private context: Context;
|
private context: LineContext;
|
||||||
|
|
||||||
private completionModel: CompletionModel;
|
private completionModel: CompletionModel;
|
||||||
|
|
||||||
@@ -274,12 +220,11 @@ export class SuggestModel implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onCursorChange(e: ICursorSelectionChangedEvent): void {
|
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();
|
this.cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -288,32 +233,28 @@ export class SuggestModel implements IDisposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isInactive = this.state === State.Idle;
|
|
||||||
|
|
||||||
if (isInactive && !this.editor.getConfiguration().contribInfo.quickSuggestions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const model = this.editor.getModel();
|
const model = this.editor.getModel();
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = new Context(model, this.editor.getPosition(), false);
|
if (this.state === State.Idle) {
|
||||||
|
|
||||||
if (isInactive) {
|
if (this.editor.getConfiguration().contribInfo.quickSuggestions) {
|
||||||
// trigger was not called or it was canceled
|
// trigger 24x7 IntelliSense when idle and enabled
|
||||||
this.cancel();
|
this.cancel();
|
||||||
|
if (LineContext.shouldAutoTrigger(this.editor)) {
|
||||||
if (ctx.shouldAutoTrigger()) {
|
|
||||||
this.triggerAutoSuggestPromise = TPromise.timeout(this.quickSuggestDelay);
|
this.triggerAutoSuggestPromise = TPromise.timeout(this.quickSuggestDelay);
|
||||||
this.triggerAutoSuggestPromise.then(() => {
|
this.triggerAutoSuggestPromise.then(() => {
|
||||||
this.triggerAutoSuggestPromise = null;
|
this.triggerAutoSuggestPromise = null;
|
||||||
this.trigger(true);
|
this.trigger(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// refine active suggestion
|
||||||
|
const ctx = new LineContext(model, this.editor.getPosition(), this.state === State.Auto);
|
||||||
this.onNewContext(ctx);
|
this.onNewContext(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,9 +267,9 @@ export class SuggestModel implements IDisposable {
|
|||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,9 +300,9 @@ export class SuggestModel implements IDisposable {
|
|||||||
items = items.concat(existingItems).sort(cmpFn);
|
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, {
|
this.completionModel = new CompletionModel(items, this.context.column, {
|
||||||
leadingLineContent: ctx.lineContentBefore,
|
leadingLineContent: ctx.leadingLineContent,
|
||||||
characterCountDelta: this.context ? ctx.column - this.context.column : 0
|
characterCountDelta: this.context ? ctx.column - this.context.column : 0
|
||||||
});
|
});
|
||||||
this.onNewContext(ctx);
|
this.onNewContext(ctx);
|
||||||
@@ -369,42 +310,66 @@ export class SuggestModel implements IDisposable {
|
|||||||
}).then(null, onUnexpectedError);
|
}).then(null, onUnexpectedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onNewContext(ctx: Context): void {
|
private onNewContext(ctx: LineContext): void {
|
||||||
if (this.context && this.context.isDifferentContext(ctx)) {
|
|
||||||
if (this.context.shouldRetrigger(ctx)) {
|
|
||||||
this.trigger(this.state === State.Auto, true);
|
|
||||||
} else {
|
|
||||||
this.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (this.completionModel) {
|
if (!this.context) {
|
||||||
|
// happens when 24x7 IntelliSense is enabled and still in its delay
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto = this.state === State.Auto;
|
if (ctx.lineNumber !== this.context.lineNumber) {
|
||||||
const oldLineContext = this.completionModel.lineContext;
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.completionModel) {
|
||||||
|
// happens when IntelliSense is not yet computed
|
||||||
|
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);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// typed -> moved cursor RIGHT -> update UI
|
||||||
|
let oldLineContext = this.completionModel.lineContext;
|
||||||
let isFrozen = false;
|
let isFrozen = false;
|
||||||
|
|
||||||
this.completionModel.lineContext = {
|
this.completionModel.lineContext = {
|
||||||
leadingLineContent: ctx.lineContentBefore,
|
leadingLineContent: ctx.leadingLineContent,
|
||||||
characterCountDelta: this.context ? ctx.column - this.context.column : 0
|
characterCountDelta: ctx.column - this.context.column
|
||||||
};
|
};
|
||||||
|
|
||||||
// when explicitly request when the next context goes
|
if (this.completionModel.items.length === 0) {
|
||||||
// from 'results' to 'no results' freeze
|
|
||||||
if (!auto && 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;
|
this.completionModel.lineContext = oldLineContext;
|
||||||
isFrozen = this.completionModel.items.length > 0;
|
isFrozen = this.completionModel.items.length > 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._onDidSuggest.fire({
|
this._onDidSuggest.fire({
|
||||||
completionModel: this.completionModel,
|
completionModel: this.completionModel,
|
||||||
|
auto: this.context.auto,
|
||||||
isFrozen,
|
isFrozen,
|
||||||
auto
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
|||||||
import { Model } from 'vs/editor/common/model/model';
|
import { Model } from 'vs/editor/common/model/model';
|
||||||
import { ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon';
|
import { ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon';
|
||||||
import { ISuggestSupport, ISuggestResult, SuggestRegistry } from 'vs/editor/common/modes';
|
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 { MockCodeEditor, MockScopeLocation } from 'vs/editor/test/common/mocks/mockCodeEditor';
|
||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||||
@@ -49,8 +49,10 @@ suite('SuggestModel - Context', function () {
|
|||||||
|
|
||||||
function assertAutoTrigger(offset: number, expected: boolean): void {
|
function assertAutoTrigger(offset: number, expected: boolean): void {
|
||||||
const pos = model.getPositionAt(offset);
|
const pos = model.getPositionAt(offset);
|
||||||
const ctx = new Context(model, pos, false);
|
const editor = createMockEditor(model);
|
||||||
assert.equal(ctx.shouldAutoTrigger(), expected);
|
editor.setPosition(pos);
|
||||||
|
assert.equal(LineContext.shouldAutoTrigger(editor), expected);
|
||||||
|
editor.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
assertAutoTrigger(3, true); // end of word, Das|
|
assertAutoTrigger(3, true); // end of word, Das|
|
||||||
@@ -59,28 +61,6 @@ suite('SuggestModel - Context', function () {
|
|||||||
assertAutoTrigger(55, false); // number, 1861|
|
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 () {
|
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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -17,7 +17,7 @@ import { domEvent } from 'vs/base/browser/event';
|
|||||||
import { Emitter } from 'vs/base/common/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);
|
const groups = menu.getActions(context);
|
||||||
if (groups.length === 0) {
|
if (groups.length === 0) {
|
||||||
return;
|
return;
|
||||||
@@ -25,11 +25,6 @@ export function fillInActions(menu: IMenu, context: any, target: IAction[] | { p
|
|||||||
|
|
||||||
for (let tuple of groups) {
|
for (let tuple of groups) {
|
||||||
let [group, actions] = tuple;
|
let [group, actions] = tuple;
|
||||||
|
|
||||||
if (!ignoreAltKey && _altKey.value) {
|
|
||||||
swapWithAltActionsIfPossible(actions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group === 'navigation') {
|
if (group === 'navigation') {
|
||||||
|
|
||||||
const head = Array.isArray<IAction>(target) ? target : target.primary;
|
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 {
|
export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService): ActionItem {
|
||||||
if (action instanceof MenuItemAction) {
|
if (action instanceof MenuItemAction) {
|
||||||
@@ -86,8 +74,6 @@ const _altKey = new class extends Emitter<boolean> {
|
|||||||
|
|
||||||
private _subscriptions: IDisposable[] = [];
|
private _subscriptions: IDisposable[] = [];
|
||||||
|
|
||||||
private _value = false;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -97,15 +83,6 @@ const _altKey = new class extends Emitter<boolean> {
|
|||||||
this._subscriptions.push(domEvent(document.body, 'blur')(e => this.fire(false)));
|
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() {
|
dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
this._subscriptions = dispose(this._subscriptions);
|
this._subscriptions = dispose(this._subscriptions);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function getConfigurationValue<T>(config: any, settingPath: string, defau
|
|||||||
let current = config;
|
let current = config;
|
||||||
for (let i = 0; i < path.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
current = current[path[i]];
|
current = current[path[i]];
|
||||||
if (typeof current === 'undefined') {
|
if (typeof current === 'undefined' || current === null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
|||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import Event from 'vs/base/common/event';
|
import Event from 'vs/base/common/event';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||||
|
|
||||||
export const IEditorService = createDecorator<IEditorService>('editorService');
|
export const IEditorService = createDecorator<IEditorService>('editorService');
|
||||||
|
|
||||||
@@ -238,6 +239,11 @@ export interface ITextEditorOptions extends IEditorOptions {
|
|||||||
endColumn?: number;
|
endColumn?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text editor view state.
|
||||||
|
*/
|
||||||
|
viewState?: IEditorViewState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.
|
* Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export interface ParsedArgs {
|
|||||||
diff?: boolean;
|
diff?: boolean;
|
||||||
goto?: boolean;
|
goto?: boolean;
|
||||||
'new-window'?: boolean;
|
'new-window'?: boolean;
|
||||||
|
'new-window-if-not-first'?: boolean;
|
||||||
'reuse-window'?: boolean;
|
'reuse-window'?: boolean;
|
||||||
locale?: string;
|
locale?: string;
|
||||||
'user-data-dir'?: string;
|
'user-data-dir'?: string;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const options: minimist.Opts = {
|
|||||||
'diff',
|
'diff',
|
||||||
'goto',
|
'goto',
|
||||||
'new-window',
|
'new-window',
|
||||||
|
'new-window-if-not-first',
|
||||||
'reuse-window',
|
'reuse-window',
|
||||||
'performance',
|
'performance',
|
||||||
'verbose',
|
'verbose',
|
||||||
@@ -148,7 +149,7 @@ export function formatOptions(options: { [name: string]: string; }, columns: num
|
|||||||
}
|
}
|
||||||
|
|
||||||
function wrapText(text: string, columns: number): string[] {
|
function wrapText(text: string, columns: number): string[] {
|
||||||
let lines = [];
|
let lines: string[] = [];
|
||||||
while (text.length) {
|
while (text.length) {
|
||||||
let index = text.length < columns ? text.length : text.lastIndexOf(' ', columns);
|
let index = text.length < columns ? text.length : text.lastIndexOf(' ', columns);
|
||||||
let line = text.slice(0, index).trim();
|
let line = text.slice(0, index).trim();
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ export class FileChangesEvent extends events.Event {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._changes.some((change) => {
|
return this._changes.some(change => {
|
||||||
if (change.type !== type) {
|
if (change.type !== type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -280,11 +280,11 @@ export class FileChangesEvent extends events.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getOfType(type: FileChangeType): IFileChange[] {
|
private getOfType(type: FileChangeType): IFileChange[] {
|
||||||
return this._changes.filter((change) => change.type === type);
|
return this._changes.filter(change => change.type === type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasType(type: FileChangeType): boolean {
|
private hasType(type: FileChangeType): boolean {
|
||||||
return this._changes.some((change) => {
|
return this._changes.some(change => {
|
||||||
return change.type === type;
|
return change.type === type;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,13 +123,15 @@ export class InstantiationService implements IInstantiationService {
|
|||||||
|
|
||||||
// arguments defined by service decorators
|
// arguments defined by service decorators
|
||||||
let serviceDependencies = _util.getServiceDependencies(desc.ctor).sort((a, b) => a.index - b.index);
|
let serviceDependencies = _util.getServiceDependencies(desc.ctor).sort((a, b) => a.index - b.index);
|
||||||
let serviceArgs = serviceDependencies.map(dependency => {
|
let serviceArgs: any[] = [];
|
||||||
|
for (const dependency of serviceDependencies) {
|
||||||
let service = this._getOrCreateServiceInstance(dependency.id);
|
let service = this._getOrCreateServiceInstance(dependency.id);
|
||||||
if (!service && this._strict && !dependency.optional) {
|
if (!service && this._strict && !dependency.optional) {
|
||||||
throw new Error(`[createInstance] ${desc.ctor.name} depends on UNKNOWN service ${dependency.id}.`);
|
throw new Error(`[createInstance] ${desc.ctor.name} depends on UNKNOWN service ${dependency.id}.`);
|
||||||
}
|
}
|
||||||
return service;
|
serviceArgs.push(service);
|
||||||
});
|
}
|
||||||
|
|
||||||
let firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : staticArgs.length;
|
let firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : staticArgs.length;
|
||||||
|
|
||||||
// check for argument mismatches, adjust static args if needed
|
// check for argument mismatches, adjust static args if needed
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export interface ICommandAndKeybindingRule extends IKeybindingRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IKeybindingsRegistry {
|
export interface IKeybindingsRegistry {
|
||||||
registerKeybindingRule(rule: IKeybindingRule);
|
registerKeybindingRule(rule: IKeybindingRule): void;
|
||||||
registerCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): void;
|
registerCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): void;
|
||||||
getDefaultKeybindings(): IKeybindingItem[];
|
getDefaultKeybindings(): IKeybindingItem[];
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface IWindowsService {
|
|||||||
openDevTools(windowId: number): TPromise<void>;
|
openDevTools(windowId: number): TPromise<void>;
|
||||||
toggleDevTools(windowId: number): TPromise<void>;
|
toggleDevTools(windowId: number): TPromise<void>;
|
||||||
// TODO@joao: rename, shouldn't this be closeWindow?
|
// 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>;
|
closeFolder(windowId: number): TPromise<void>;
|
||||||
toggleFullScreen(windowId: number): TPromise<void>;
|
toggleFullScreen(windowId: number): TPromise<void>;
|
||||||
setRepresentedFilename(windowId: number, fileName: string): TPromise<void>;
|
setRepresentedFilename(windowId: number, fileName: string): TPromise<void>;
|
||||||
@@ -40,8 +41,7 @@ export interface IWindowsService {
|
|||||||
quit(): TPromise<void>;
|
quit(): TPromise<void>;
|
||||||
|
|
||||||
// Global methods
|
// Global methods
|
||||||
// TODO@joao: rename, shouldn't this be openWindow?
|
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void>;
|
||||||
windowOpen(paths: string[], forceNewWindow?: boolean): TPromise<void>;
|
|
||||||
openNewWindow(): TPromise<void>;
|
openNewWindow(): TPromise<void>;
|
||||||
showWindow(windowId: number): TPromise<void>;
|
showWindow(windowId: number): TPromise<void>;
|
||||||
getWindows(): TPromise<{ id: number; path: string; title: string; }[]>;
|
getWindows(): TPromise<{ id: number; path: string; title: string; }[]>;
|
||||||
@@ -87,7 +87,8 @@ export interface IWindowService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IWindowSettings {
|
export interface IWindowSettings {
|
||||||
openFilesInNewWindow: boolean;
|
openFilesInNewWindow: 'on' | 'off' | 'default';
|
||||||
|
openFoldersInNewWindow: 'on' | 'off' | 'default';
|
||||||
reopenFolders: 'all' | 'one' | 'none';
|
reopenFolders: 'all' | 'one' | 'none';
|
||||||
restoreFullscreen: boolean;
|
restoreFullscreen: boolean;
|
||||||
zoomLevel: number;
|
zoomLevel: number;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export interface IWindowsChannel extends IChannel {
|
|||||||
call(command: 'setDocumentEdited', arg: [number, boolean]): TPromise<void>;
|
call(command: 'setDocumentEdited', arg: [number, boolean]): TPromise<void>;
|
||||||
call(command: 'toggleMenuBar', arg: number): TPromise<void>;
|
call(command: 'toggleMenuBar', arg: number): TPromise<void>;
|
||||||
call(command: 'quit'): 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: 'openNewWindow'): TPromise<void>;
|
||||||
call(command: 'showWindow', arg: number): TPromise<void>;
|
call(command: 'showWindow', arg: number): TPromise<void>;
|
||||||
call(command: 'getWindows'): TPromise<{ id: number; path: string; title: string; }[]>;
|
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 'unmaximizeWindow': return this.service.unmaximizeWindow(arg);
|
||||||
case 'setDocumentEdited': return this.service.setDocumentEdited(arg[0], arg[1]);
|
case 'setDocumentEdited': return this.service.setDocumentEdited(arg[0], arg[1]);
|
||||||
case 'toggleMenuBar': return this.service.toggleMenuBar(arg);
|
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 'openNewWindow': return this.service.openNewWindow();
|
||||||
case 'showWindow': return this.service.showWindow(arg);
|
case 'showWindow': return this.service.showWindow(arg);
|
||||||
case 'getWindows': return this.service.getWindows();
|
case 'getWindows': return this.service.getWindows();
|
||||||
@@ -179,8 +179,8 @@ export class WindowsChannelClient implements IWindowsService {
|
|||||||
return this.channel.call('quit');
|
return this.channel.call('quit');
|
||||||
}
|
}
|
||||||
|
|
||||||
windowOpen(paths: string[], forceNewWindow?: boolean): TPromise<void> {
|
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void> {
|
||||||
return this.channel.call('windowOpen', [paths, forceNewWindow]);
|
return this.channel.call('openWindow', [paths, options]);
|
||||||
}
|
}
|
||||||
|
|
||||||
openNewWindow(): TPromise<void> {
|
openNewWindow(): TPromise<void> {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { fromEventEmitter } from 'vs/base/node/event';
|
|||||||
import { IURLService } from 'vs/platform/url/common/url';
|
import { IURLService } from 'vs/platform/url/common/url';
|
||||||
|
|
||||||
// TODO@Joao: remove this dependency, move all implementation to this class
|
// 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 {
|
export class WindowsService implements IWindowsService, IDisposable {
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||||||
const vscodeWindow = this.windowsMainService.getWindowById(windowId);
|
const vscodeWindow = this.windowsMainService.getWindowById(windowId);
|
||||||
|
|
||||||
if (vscodeWindow) {
|
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);
|
return TPromise.as(null);
|
||||||
@@ -198,17 +198,17 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||||||
return TPromise.as(null);
|
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) {
|
if (!paths || !paths.length) {
|
||||||
return TPromise.as(null);
|
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);
|
return TPromise.as(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
openNewWindow(): TPromise<void> {
|
openNewWindow(): TPromise<void> {
|
||||||
this.windowsMainService.openNewWindow();
|
this.windowsMainService.openNewWindow(OpenContext.OTHER);
|
||||||
return TPromise.as(null);
|
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 cli = assign(Object.create(null), this.environmentService.args, { goto: true });
|
||||||
const pathsToOpen = [filePath];
|
const pathsToOpen = [filePath];
|
||||||
|
|
||||||
this.windowsMainService.open({ cli, pathsToOpen });
|
this.windowsMainService.open({ context: OpenContext.OTHER, cli, pathsToOpen });
|
||||||
return TPromise.as(null);
|
return TPromise.as(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -579,7 +579,7 @@ export class MainThreadEditorsTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _findVisibleTextEditorIds(): string[] {
|
private _findVisibleTextEditorIds(): string[] {
|
||||||
let result = [];
|
let result: string[] = [];
|
||||||
let modelUris = Object.keys(this._model2TextEditors);
|
let modelUris = Object.keys(this._model2TextEditors);
|
||||||
for (let i = 0, len = modelUris.length; i < len; i++) {
|
for (let i = 0, len = modelUris.length; i < len; i++) {
|
||||||
let editors = this._model2TextEditors[modelUris[i]];
|
let editors = this._model2TextEditors[modelUris[i]];
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape {
|
|||||||
private _proxy: ExtHostTreeExplorersShape;
|
private _proxy: ExtHostTreeExplorersShape;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IThreadService private threadService: IThreadService,
|
@IThreadService threadService: IThreadService,
|
||||||
@ITreeExplorerService private treeExplorerService: ITreeExplorerService,
|
@ITreeExplorerService private treeExplorerService: ITreeExplorerService,
|
||||||
@IMessageService private messageService: IMessageService,
|
@IMessageService private messageService: IMessageService,
|
||||||
@ICommandService private commandService: ICommandService
|
@ICommandService private commandService: ICommandService
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape {
|
|||||||
constructor(
|
constructor(
|
||||||
@ISearchService searchService: ISearchService,
|
@ISearchService searchService: ISearchService,
|
||||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||||
@ITextFileService textFileService,
|
@ITextFileService textFileService: ITextFileService,
|
||||||
@IWorkbenchEditorService editorService,
|
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
|
||||||
@ITextModelResolverService textModelResolverService,
|
@ITextModelResolverService textModelResolverService: ITextModelResolverService,
|
||||||
@IFileService fileService: IFileService
|
@IFileService fileService: IFileService
|
||||||
) {
|
) {
|
||||||
super();
|
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);
|
.then(() => true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export class ContributableActionProvider implements IActionProvider {
|
|||||||
private registry: IActionBarRegistry;
|
private registry: IActionBarRegistry;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.registry = (<IActionBarRegistry>Registry.as(Extensions.Actionbar));
|
this.registry = Registry.as<IActionBarRegistry>(Extensions.Actionbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
private toContext(tree: ITree, element: any): any {
|
private toContext(tree: ITree, element: any): any {
|
||||||
|
|||||||
@@ -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);
|
jsonRegistry.registerSchema(schemaId, schema);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user