mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Merge remote-tracking branch 'origin/master' into alex/tokenization
This commit is contained in:
commit
88c45c4e57
|
@ -9,6 +9,8 @@
|
|||
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.
|
||||
|
||||
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">
|
||||
<img alt="VS Code in action" src="https://cloud.githubusercontent.com/assets/11839736/16642200/6624dde0-43bd-11e6-8595-c81885ba0dc2.png">
|
||||
</p>
|
||||
|
|
|
@ -269,7 +269,7 @@ function packageTask(platform, arch, opts) {
|
|||
.pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js']))
|
||||
.pipe(util.cleanNodeModule('pty.js', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/**']));
|
||||
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/**']));
|
||||
|
||||
let all = es.merge(
|
||||
packageJsonStream,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
|
||||
[{
|
||||
"name": "js-beautify",
|
||||
"version": "1.6.4",
|
||||
"version": "1.6.8",
|
||||
"license": "MIT",
|
||||
"repositoryURL": "https://github.com/beautify-web/js-beautify"
|
||||
},{
|
||||
|
|
|
@ -87,9 +87,17 @@
|
|||
"string",
|
||||
"null"
|
||||
],
|
||||
"default": "a, abbr, acronym, b, bdo, big, br, button, cite, code, dfn, em, i, img, input, kbd, label, map, object, pre, q, samp, select, small, span, strong, sub, sup, textarea, tt, var",
|
||||
"default": "a, abbr, acronym, b, bdo, big, br, button, cite, code, dfn, em, i, img, input, kbd, label, map, object, q, samp, select, small, span, strong, sub, sup, textarea, tt, var",
|
||||
"description": "%html.format.unformatted.desc%"
|
||||
},
|
||||
"html.format.contentUnformatted": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"default": "pre",
|
||||
"description": "%html.format.contentUnformatted.desc%"
|
||||
},
|
||||
"html.format.indentInnerHtml": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
@ -126,6 +134,13 @@
|
|||
"default": "head, body, /html",
|
||||
"description": "%html.format.extraLiners.desc%"
|
||||
},
|
||||
"html.format.wrapAttributes": {
|
||||
"type": "string",
|
||||
"default": "auto",
|
||||
"enum": [ "auto", "force", "force-align", "force-expand-multiline" ],
|
||||
"enumDescriptions": ["%html.format.wrapAttributes.auto%", "%html.format.wrapAttributes.force%", "%html.format.wrapAttributes.forcealign%", "%html.format.wrapAttributes.forcemultiline%"],
|
||||
"description": "%html.format.wrapAttributes.desc%"
|
||||
},
|
||||
"html.suggest.angular1": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
|
|
|
@ -2,12 +2,18 @@
|
|||
"html.format.enable.desc": "Enable/disable default HTML formatter (requires restart)",
|
||||
"html.format.wrapLineLength.desc": "Maximum amount of characters per line (0 = disable).",
|
||||
"html.format.unformatted.desc": "List of tags, comma separated, that shouldn't be reformatted. 'null' defaults to all tags listed at https://www.w3.org/TR/html5/dom.html#phrasing-content.",
|
||||
"html.format.contentUnformatted.desc": "List of tags, comma separated, where the content shouldn't be reformatted. 'null' defaults to the 'pre' tag.",
|
||||
"html.format.indentInnerHtml.desc": "Indent <head> and <body> sections.",
|
||||
"html.format.preserveNewLines.desc": "Whether existing line breaks before elements should be preserved. Only works before elements, not inside tags or for text.",
|
||||
"html.format.maxPreserveNewLines.desc": "Maximum number of line breaks to be preserved in one chunk. Use 'null' for unlimited.",
|
||||
"html.format.indentHandlebars.desc": "Format and indent {{#foo}} and {{/foo}}.",
|
||||
"html.format.endWithNewline.desc": "End with a newline.",
|
||||
"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.wrapAttributes.desc": "Wrap attributes.",
|
||||
"html.format.wrapAttributes.auto": "Wrap attributes only when line length is exceeded.",
|
||||
"html.format.wrapAttributes.force": "Wrap each attribute except first.",
|
||||
"html.format.wrapAttributes.forcealign": "Wrap each attribute except first and keep aligned.",
|
||||
"html.format.wrapAttributes.forcemultiline": "Wrap each attribute.",
|
||||
"html.suggest.angular1.desc": "Configures if the built-in HTML language support suggests Angular V1 tags and properties.",
|
||||
"html.suggest.ionic.desc": "Configures if the built-in HTML language support suggests Ionic tags, properties and values.",
|
||||
"html.suggest.html5.desc":"Configures if the built-in HTML language support suggests HTML5 tags, properties and values.",
|
||||
|
|
9
extensions/html/server/npm-shrinkwrap.json
generated
9
extensions/html/server/npm-shrinkwrap.json
generated
|
@ -2,15 +2,20 @@
|
|||
"name": "vscode-html-languageserver",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "6.0.58",
|
||||
"from": "@types/node@>=6.0.51 <7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.58.tgz"
|
||||
},
|
||||
"vscode-css-languageservice": {
|
||||
"version": "2.0.0-next.6",
|
||||
"from": "vscode-css-languageservice@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.0.0-next.6.tgz"
|
||||
},
|
||||
"vscode-html-languageservice": {
|
||||
"version": "2.0.0-next.3",
|
||||
"version": "2.0.0-next.5",
|
||||
"from": "vscode-html-languageservice@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.0-next.3.tgz"
|
||||
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.0-next.5.tgz"
|
||||
},
|
||||
"vscode-jsonrpc": {
|
||||
"version": "3.0.1-alpha.2",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^2.0.0-next.6",
|
||||
"vscode-html-languageservice": "^2.0.0-next.3",
|
||||
"vscode-html-languageservice": "^2.0.0-next.5",
|
||||
"vscode-languageserver": "3.0.1-alpha.2",
|
||||
"vscode-nls": "^1.0.7",
|
||||
"vscode-uri": "^1.0.0"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"extensions": [
|
||||
".jsx"
|
||||
],
|
||||
"configuration": "./language-configuration.json"
|
||||
"configuration": "./javascript-language-configuration.json"
|
||||
},
|
||||
{
|
||||
"id": "javascript",
|
||||
|
@ -47,19 +47,31 @@
|
|||
"mimetypes": [
|
||||
"text/javascript"
|
||||
],
|
||||
"configuration": "./language-configuration.json"
|
||||
"configuration": "./javascript-language-configuration.json"
|
||||
},
|
||||
{
|
||||
"id": "jsx-tags",
|
||||
"configuration": "./tags-language-configuration.json"
|
||||
}
|
||||
],
|
||||
"grammars": [
|
||||
{
|
||||
"language": "javascriptreact",
|
||||
"scopeName": "source.js",
|
||||
"path": "./syntaxes/JavaScript.tmLanguage.json"
|
||||
"path": "./syntaxes/JavaScript.tmLanguage.json",
|
||||
"embeddedLanguages": {
|
||||
"meta.tag.js": "jsx-tags",
|
||||
"meta.tag.without-attributes.js": "jsx-tags"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language": "javascript",
|
||||
"scopeName": "source.js",
|
||||
"path": "./syntaxes/JavaScript.tmLanguage.json"
|
||||
"path": "./syntaxes/JavaScript.tmLanguage.json",
|
||||
"embeddedLanguages": {
|
||||
"meta.tag.js": "jsx-tags",
|
||||
"meta.tag.without-attributes.js": "jsx-tags"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scopeName": "source.js.regexp",
|
||||
|
|
27
extensions/javascript/tags-language-configuration.json
Normal file
27
extensions/javascript/tags-language-configuration.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"comments": {
|
||||
"blockComment": [ "{/*", "*/}" ]
|
||||
},
|
||||
"brackets": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["<", ">"]
|
||||
],
|
||||
"autoClosingPairs": [
|
||||
{ "open": "{", "close": "}" },
|
||||
{ "open": "[", "close": "]" },
|
||||
{ "open": "(", "close": ")" },
|
||||
{ "open": "'", "close": "'", "notIn": ["string", "comment"] },
|
||||
{ "open": "\"", "close": "\"", "notIn": ["string"] },
|
||||
{ "open": "/**", "close": " */", "notIn": ["string"] }
|
||||
],
|
||||
"surroundingPairs": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["<", ">"],
|
||||
["'", "'"],
|
||||
["\"", "\""]
|
||||
]
|
||||
}
|
4
extensions/json/server/npm-shrinkwrap.json
generated
4
extensions/json/server/npm-shrinkwrap.json
generated
|
@ -43,9 +43,9 @@
|
|||
"resolved": "https://registry.npmjs.org/request-light/-/request-light-0.1.0.tgz"
|
||||
},
|
||||
"vscode-json-languageservice": {
|
||||
"version": "2.0.0-next.8",
|
||||
"version": "2.0.0-next.9",
|
||||
"from": "vscode-json-languageservice@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.0-next.8.tgz"
|
||||
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.0-next.9.tgz"
|
||||
},
|
||||
"vscode-jsonrpc": {
|
||||
"version": "3.0.1-alpha.2",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"request-light": "^0.1.0",
|
||||
"vscode-json-languageservice": "^2.0.0-next.8",
|
||||
"vscode-json-languageservice": "^2.0.0-next.9",
|
||||
"vscode-languageserver": "3.0.1-alpha.3",
|
||||
"vscode-nls": "^1.0.7"
|
||||
},
|
||||
|
|
|
@ -68,7 +68,11 @@
|
|||
{
|
||||
"language": "typescriptreact",
|
||||
"scopeName": "source.tsx",
|
||||
"path": "./syntaxes/TypeScriptReact.tmLanguage.json"
|
||||
"path": "./syntaxes/TypeScriptReact.tmLanguage.json",
|
||||
"embeddedLanguages": {
|
||||
"meta.tag.tsx": "jsx-tags",
|
||||
"meta.tag.without-attributes.tsx": "jsx-tags"
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
|
@ -99,6 +103,11 @@
|
|||
"default": true,
|
||||
"description": "%typescript.check.tscVersion%"
|
||||
},
|
||||
"typescript.referencesCodeLens.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%typescript.referencesCodeLens.enabled%"
|
||||
},
|
||||
"typescript.tsserver.trace": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
|
@ -24,5 +24,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.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"
|
||||
}
|
144
extensions/typescript/src/features/referencesCodeLensProvider.ts
Normal file
144
extensions/typescript/src/features/referencesCodeLensProvider.ts
Normal file
|
@ -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 WorkspaceSymbolProvider from './features/workspaceSymbolProvider';
|
||||
import CodeActionProvider from './features/codeActionProvider';
|
||||
import ReferenceCodeLensProvider from './features/referencesCodeLensProvider';
|
||||
|
||||
import * as BuildStatus from './utils/buildStatus';
|
||||
import * as ProjectStatus from './utils/projectStatus';
|
||||
|
@ -107,6 +108,7 @@ class LanguageProvider {
|
|||
private formattingProvider: FormattingProvider;
|
||||
private formattingProviderRegistration: Disposable | null;
|
||||
private typingsStatus: TypingsStatus;
|
||||
private referenceCodeLensProvider: ReferenceCodeLensProvider;
|
||||
|
||||
private _validate: boolean;
|
||||
|
||||
|
@ -156,6 +158,12 @@ class LanguageProvider {
|
|||
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 => {
|
||||
let selector: DocumentFilter = { scheme: 'file', language: modeId };
|
||||
languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.');
|
||||
|
@ -171,6 +179,7 @@ class LanguageProvider {
|
|||
if (client.apiVersion.has213Features()) {
|
||||
languages.registerCodeActionsProvider(selector, new CodeActionProvider(client, modeId));
|
||||
}
|
||||
|
||||
languages.setLanguageConfiguration(modeId, {
|
||||
indentationRules: {
|
||||
// ^(.*\*/)?\s*\}.*$
|
||||
|
@ -217,6 +226,9 @@ class LanguageProvider {
|
|||
if (this.completionItemProvider) {
|
||||
this.completionItemProvider.updateConfiguration(config);
|
||||
}
|
||||
if (this.referenceCodeLensProvider) {
|
||||
this.referenceCodeLensProvider.updateConfiguration(config);
|
||||
}
|
||||
if (this.formattingProvider) {
|
||||
this.formattingProvider.updateConfiguration(config);
|
||||
if (!this.formattingProvider.isEnabled() && this.formattingProviderRegistration) {
|
||||
|
|
12
npm-shrinkwrap.json
generated
12
npm-shrinkwrap.json
generated
|
@ -332,10 +332,10 @@
|
|||
"from": "process-nextick-args@>=1.0.6 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz"
|
||||
},
|
||||
"pty.js": {
|
||||
"version": "0.3.0",
|
||||
"from": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642",
|
||||
"resolved": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642",
|
||||
"node-pty": {
|
||||
"version": "0.4.1",
|
||||
"from": "node-pty@0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.4.1.tgz",
|
||||
"dependencies": {
|
||||
"extend": {
|
||||
"version": "1.2.1",
|
||||
|
@ -430,9 +430,9 @@
|
|||
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz"
|
||||
},
|
||||
"xterm": {
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.3",
|
||||
"from": "git+https://github.com/Tyriar/xterm.js.git#vscode-release/1.9",
|
||||
"resolved": "git+https://github.com/Tyriar/xterm.js.git#618e6bbd0a0ebaabc4b06ab10bea89768ded62b5"
|
||||
"resolved": "git+https://github.com/Tyriar/xterm.js.git#01dd436a56ee2370fa9b5aa5bc2e138b22799eda"
|
||||
},
|
||||
"yauzl": {
|
||||
"version": "2.3.1",
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"iconv-lite": "0.4.15",
|
||||
"minimist": "1.2.0",
|
||||
"native-keymap": "0.3.0",
|
||||
"pty.js": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642",
|
||||
"node-pty": "0.4.1",
|
||||
"semver": "4.3.6",
|
||||
"vscode-debugprotocol": "1.15.0",
|
||||
"vscode-textmate": "3.1.0",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'pty.js' {
|
||||
declare module 'node-pty' {
|
||||
export function fork(file: string, args: string[], options: any): Terminal;
|
||||
export function spawn(file: string, args: string[], options: any): Terminal;
|
||||
export function createTerminal(file: string, args: string[], options: any): Terminal;
|
|
@ -1043,9 +1043,6 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
|
|||
}
|
||||
|
||||
function parseString(isValue: boolean): boolean {
|
||||
if (_scanner.getToken() !== SyntaxKind.StringLiteral) {
|
||||
return false;
|
||||
}
|
||||
let value = _scanner.getTokenValue();
|
||||
if (isValue) {
|
||||
onLiteralValue(value);
|
||||
|
@ -1088,10 +1085,11 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
|
|||
}
|
||||
|
||||
function parseProperty(): boolean {
|
||||
if (!parseString(false)) {
|
||||
if (_scanner.getToken() !== SyntaxKind.StringLiteral) {
|
||||
handleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);
|
||||
return false;
|
||||
}
|
||||
parseString(false);
|
||||
if (_scanner.getToken() === SyntaxKind.ColonToken) {
|
||||
onSeparator(':');
|
||||
scanNext(); // consume colon
|
||||
|
@ -1106,9 +1104,6 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
|
|||
}
|
||||
|
||||
function parseObject(): boolean {
|
||||
if (_scanner.getToken() !== SyntaxKind.OpenBraceToken) {
|
||||
return false;
|
||||
}
|
||||
onObjectBegin();
|
||||
scanNext(); // consume open brace
|
||||
|
||||
|
@ -1138,9 +1133,6 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
|
|||
}
|
||||
|
||||
function parseArray(): boolean {
|
||||
if (_scanner.getToken() !== SyntaxKind.OpenBracketToken) {
|
||||
return false;
|
||||
}
|
||||
onArrayBegin();
|
||||
scanNext(); // consume open bracket
|
||||
|
||||
|
@ -1170,7 +1162,16 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
|
|||
}
|
||||
|
||||
function parseValue(): boolean {
|
||||
return parseArray() || parseObject() || parseString(true) || parseLiteral();
|
||||
switch (_scanner.getToken()) {
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
return parseArray();
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return parseObject();
|
||||
case SyntaxKind.StringLiteral:
|
||||
return parseString(true);
|
||||
default:
|
||||
return parseLiteral();
|
||||
}
|
||||
}
|
||||
|
||||
scanNext();
|
||||
|
|
|
@ -261,8 +261,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
|
|||
}
|
||||
|
||||
// Install Menu
|
||||
const menu = instantiationService2.createInstance(VSCodeMenu);
|
||||
menu.ready();
|
||||
instantiationService2.createInstance(VSCodeMenu);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ import { Keybinding } from 'vs/base/common/keyCodes';
|
|||
import { KeybindingLabels } from 'vs/base/common/keybinding';
|
||||
import product from 'vs/platform/node/product';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import Event, { Emitter, once } from 'vs/base/common/event';
|
||||
import { ConfigWatcher } from 'vs/base/node/config';
|
||||
import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
||||
interface IResolvedKeybinding {
|
||||
id: string;
|
||||
|
@ -46,10 +50,97 @@ interface IConfiguration extends IFilesConfiguration {
|
|||
};
|
||||
}
|
||||
|
||||
export class VSCodeMenu {
|
||||
class KeybindingsResolver {
|
||||
|
||||
private static lastKnownKeybindingsMapStorageKey = 'lastKnownKeybindings';
|
||||
|
||||
private commandIds: Set<string>;
|
||||
private keybindings: { [commandId: string]: string };
|
||||
private keybindingsWatcher: ConfigWatcher<IUserFriendlyKeybinding[]>;
|
||||
|
||||
private _onKeybindingsChanged = new Emitter<void>();
|
||||
onKeybindingsChanged: Event<void> = this._onKeybindingsChanged.event;
|
||||
|
||||
constructor(
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IWindowsMainService private windowsService: IWindowsMainService
|
||||
) {
|
||||
this.commandIds = new Set<string>();
|
||||
this.keybindings = this.storageService.getItem<{ [id: string]: string; }>(KeybindingsResolver.lastKnownKeybindingsMapStorageKey) || Object.create(null);
|
||||
this.keybindingsWatcher = new ConfigWatcher<IUserFriendlyKeybinding[]>(environmentService.appKeybindingsPath, { changeBufferDelay: 1000 /* update after 1s */ });
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Resolve keybindings when any first window is loaded
|
||||
const onceOnWindowReady = once(this.windowsService.onWindowReady);
|
||||
onceOnWindowReady(win => this.resolveKeybindings(win));
|
||||
|
||||
// Listen to resolved keybindings from window
|
||||
ipc.on('vscode:keybindingsResolved', (event, rawKeybindings: string) => {
|
||||
let keybindings: IResolvedKeybinding[] = [];
|
||||
try {
|
||||
keybindings = JSON.parse(rawKeybindings);
|
||||
} catch (error) {
|
||||
// Should not happen
|
||||
}
|
||||
|
||||
// Fill hash map of resolved keybindings and check for changes
|
||||
let keybindingsChanged = false;
|
||||
let keybindingsCount = 0;
|
||||
keybindings.forEach(keybinding => {
|
||||
const accelerator = KeybindingLabels._toElectronAccelerator(new Keybinding(keybinding.binding));
|
||||
if (accelerator) {
|
||||
keybindingsCount++;
|
||||
|
||||
if (accelerator !== this.keybindings[keybinding.id]) {
|
||||
this.keybindings[keybinding.id] = accelerator;
|
||||
keybindingsChanged = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// A keybinding might have been unassigned, so we have to account for that too
|
||||
if (Object.keys(this.keybindings).length !== keybindingsCount) {
|
||||
keybindingsChanged = true;
|
||||
}
|
||||
|
||||
if (keybindingsChanged) {
|
||||
this.storageService.setItem(KeybindingsResolver.lastKnownKeybindingsMapStorageKey, this.keybindings); // keep to restore instantly after restart
|
||||
|
||||
this._onKeybindingsChanged.fire();
|
||||
}
|
||||
});
|
||||
|
||||
// Resolve keybindings again when keybindings.json changes
|
||||
this.keybindingsWatcher.onDidUpdateConfiguration(() => this.resolveKeybindings());
|
||||
|
||||
// Resolve keybindings when window reloads because an installed extension could have an impact
|
||||
this.windowsService.onWindowReload(() => this.resolveKeybindings());
|
||||
}
|
||||
|
||||
private resolveKeybindings(win: VSCodeWindow = this.windowsService.getLastActiveWindow()): void {
|
||||
if (this.commandIds.size && win) {
|
||||
const commandIds = [];
|
||||
this.commandIds.forEach(id => commandIds.push(id));
|
||||
win.sendWhenReady('vscode:resolveKeybindings', JSON.stringify(commandIds));
|
||||
}
|
||||
}
|
||||
|
||||
public getKeybinding(commandId: string): string {
|
||||
if (!this.commandIds.has(commandId)) {
|
||||
this.commandIds.add(commandId);
|
||||
}
|
||||
|
||||
return this.keybindings[commandId];
|
||||
}
|
||||
}
|
||||
|
||||
export class VSCodeMenu {
|
||||
|
||||
private static MAX_MENU_RECENT_ENTRIES = 10;
|
||||
|
||||
private currentAutoSaveSetting: string;
|
||||
|
@ -62,35 +153,28 @@ export class VSCodeMenu {
|
|||
|
||||
private menuUpdater: RunOnceScheduler;
|
||||
|
||||
private actionIdKeybindingRequests: string[];
|
||||
private mapLastKnownKeybindingToActionId: { [id: string]: string; };
|
||||
private mapResolvedKeybindingToActionId: { [id: string]: string; };
|
||||
private keybindingsResolved: boolean;
|
||||
private keybindingsResolver: KeybindingsResolver;
|
||||
|
||||
private extensionViewlets: IExtensionViewlet[];
|
||||
|
||||
constructor(
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@IUpdateService private updateService: IUpdateService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IWindowsMainService private windowsService: IWindowsMainService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService
|
||||
) {
|
||||
this.actionIdKeybindingRequests = [];
|
||||
this.extensionViewlets = [];
|
||||
|
||||
this.mapResolvedKeybindingToActionId = Object.create(null);
|
||||
this.mapLastKnownKeybindingToActionId = this.storageService.getItem<{ [id: string]: string; }>(VSCodeMenu.lastKnownKeybindingsMapStorageKey) || Object.create(null);
|
||||
|
||||
this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0);
|
||||
this.keybindingsResolver = instantiationService.createInstance(KeybindingsResolver);
|
||||
|
||||
this.onConfigurationUpdated(this.configurationService.getConfiguration<IConfiguration>());
|
||||
}
|
||||
|
||||
public ready(): void {
|
||||
this.registerListeners();
|
||||
this.install();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
@ -105,43 +189,6 @@ export class VSCodeMenu {
|
|||
this.windowsService.onRecentPathsChange(paths => this.updateMenu());
|
||||
this.windowsService.onWindowClose(_ => this.onClose(this.windowsService.getWindowCount()));
|
||||
|
||||
// Resolve keybindings when any first workbench is loaded
|
||||
this.windowsService.onWindowReady(win => this.resolveKeybindings(win));
|
||||
|
||||
// Listen to resolved keybindings
|
||||
ipc.on('vscode:keybindingsResolved', (event, rawKeybindings) => {
|
||||
let keybindings: IResolvedKeybinding[] = [];
|
||||
try {
|
||||
keybindings = JSON.parse(rawKeybindings);
|
||||
} catch (error) {
|
||||
// Should not happen
|
||||
}
|
||||
|
||||
// Fill hash map of resolved keybindings
|
||||
let needsMenuUpdate = false;
|
||||
keybindings.forEach(keybinding => {
|
||||
const accelerator = KeybindingLabels._toElectronAccelerator(new Keybinding(keybinding.binding));
|
||||
if (accelerator) {
|
||||
this.mapResolvedKeybindingToActionId[keybinding.id] = accelerator;
|
||||
if (this.mapLastKnownKeybindingToActionId[keybinding.id] !== accelerator) {
|
||||
needsMenuUpdate = true; // we only need to update when something changed!
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// A keybinding might have been unassigned, so we have to account for that too
|
||||
if (Object.keys(this.mapLastKnownKeybindingToActionId).length !== Object.keys(this.mapResolvedKeybindingToActionId).length) {
|
||||
needsMenuUpdate = true;
|
||||
}
|
||||
|
||||
if (needsMenuUpdate) {
|
||||
this.storageService.setItem(VSCodeMenu.lastKnownKeybindingsMapStorageKey, this.mapResolvedKeybindingToActionId); // keep to restore instantly after restart
|
||||
this.mapLastKnownKeybindingToActionId = this.mapResolvedKeybindingToActionId; // update our last known map
|
||||
|
||||
this.updateMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to extension viewlets
|
||||
ipc.on('vscode:extensionViewlets', (event, rawExtensionViewlets) => {
|
||||
let extensionViewlets: IExtensionViewlet[] = [];
|
||||
|
@ -162,6 +209,9 @@ export class VSCodeMenu {
|
|||
|
||||
// Listen to update service
|
||||
this.updateService.onStateChange(() => this.updateMenu());
|
||||
|
||||
// Listen to keybindings change
|
||||
this.keybindingsResolver.onKeybindingsChanged(() => this.updateMenu());
|
||||
}
|
||||
|
||||
private onConfigurationUpdated(config: IConfiguration, handleMenu?: boolean): void {
|
||||
|
@ -201,19 +251,6 @@ export class VSCodeMenu {
|
|||
}
|
||||
}
|
||||
|
||||
private resolveKeybindings(win: VSCodeWindow): void {
|
||||
if (this.keybindingsResolved) {
|
||||
return; // only resolve once
|
||||
}
|
||||
|
||||
this.keybindingsResolved = true;
|
||||
|
||||
// Resolve keybindings when workbench window is up
|
||||
if (this.actionIdKeybindingRequests.length) {
|
||||
win.send('vscode:resolveKeybindings', JSON.stringify(this.actionIdKeybindingRequests));
|
||||
}
|
||||
}
|
||||
|
||||
private updateMenu(): void {
|
||||
this.menuUpdater.schedule(); // buffer multiple attempts to update the menu
|
||||
}
|
||||
|
@ -970,19 +1007,7 @@ export class VSCodeMenu {
|
|||
|
||||
private getAccelerator(actionId: string, fallback?: string): string {
|
||||
if (actionId) {
|
||||
const resolvedKeybinding = this.mapResolvedKeybindingToActionId[actionId];
|
||||
if (resolvedKeybinding) {
|
||||
return resolvedKeybinding; // keybinding is fully resolved
|
||||
}
|
||||
|
||||
if (!this.keybindingsResolved) {
|
||||
this.actionIdKeybindingRequests.push(actionId); // keybinding needs to be resolved
|
||||
}
|
||||
|
||||
const lastKnownKeybinding = this.mapLastKnownKeybindingToActionId[actionId];
|
||||
if (lastKnownKeybinding) {
|
||||
return lastKnownKeybinding; // return the last known keybining (chance of mismatch is very low unless it changed)
|
||||
}
|
||||
return this.keybindingsResolver.getKeybinding(actionId);
|
||||
}
|
||||
|
||||
return fallback;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import * as path from 'path';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import nls = require('vs/nls');
|
||||
import { IStorageService } from 'vs/code/electron-main/storage';
|
||||
import { shell, screen, BrowserWindow, systemPreferences, app } from 'electron';
|
||||
import { TPromise, TValueCallback } from 'vs/base/common/winjs.base';
|
||||
|
@ -117,6 +118,12 @@ export enum ReadyState {
|
|||
READY
|
||||
}
|
||||
|
||||
interface IConfiguration {
|
||||
window: {
|
||||
menuBarVisibility: 'visible' | 'toggle' | 'hidden';
|
||||
};
|
||||
}
|
||||
|
||||
export interface IVSCodeWindow {
|
||||
id: number;
|
||||
readyState: ReadyState;
|
||||
|
@ -127,7 +134,6 @@ export interface IVSCodeWindow {
|
|||
|
||||
export class VSCodeWindow implements IVSCodeWindow {
|
||||
|
||||
public static menuBarHiddenKey = 'menuBarHidden';
|
||||
public static colorThemeStorageKey = 'theme';
|
||||
|
||||
private static MIN_WIDTH = 200;
|
||||
|
@ -143,6 +149,7 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||
private _extensionDevelopmentPath: string;
|
||||
private _isExtensionTestHost: boolean;
|
||||
private windowState: IWindowState;
|
||||
private currentMenuBarVisibility: 'visible' | 'toggle' | 'hidden';
|
||||
private currentWindowMode: WindowMode;
|
||||
|
||||
private whenReadyCallbacks: TValueCallback<VSCodeWindow>[];
|
||||
|
@ -220,15 +227,14 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||
|
||||
this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too
|
||||
|
||||
if (this.storageService.getItem<boolean>(VSCodeWindow.menuBarHiddenKey, false)) {
|
||||
this.setMenuBarVisibility(false); // respect configured menu bar visibility
|
||||
}
|
||||
// respect configured menu bar visibility
|
||||
this.onConfigurationUpdated(this.configurationService.getConfiguration<IConfiguration>());
|
||||
|
||||
// TODO@joao: hook this up to some initialization routine
|
||||
// this causes a race between setting the headers and doing
|
||||
// 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();
|
||||
|
||||
// Eventing
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
|
@ -407,8 +413,19 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle configuration changes
|
||||
this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(e.config));
|
||||
}
|
||||
|
||||
private onConfigurationUpdated(config: IConfiguration): void {
|
||||
const newMenuBarVisibility = this.getMenuBarVisibility(config);
|
||||
if (newMenuBarVisibility !== this.currentMenuBarVisibility) {
|
||||
this.currentMenuBarVisibility = newMenuBarVisibility;
|
||||
this.setMenuBarVisibility(newMenuBarVisibility);
|
||||
}
|
||||
};
|
||||
|
||||
public load(config: IWindowConfiguration): void {
|
||||
|
||||
// If this is the first time the window is loaded, we associate the paths
|
||||
|
@ -656,21 +673,53 @@ export class VSCodeWindow implements IVSCodeWindow {
|
|||
public toggleFullScreen(): void {
|
||||
const willBeFullScreen = !this.win.isFullScreen();
|
||||
|
||||
// set fullscreen flag on window
|
||||
this.win.setFullScreen(willBeFullScreen);
|
||||
|
||||
// Windows & Linux: Hide the menu bar but still allow to bring it up by pressing the Alt key
|
||||
if (platform.isWindows || platform.isLinux) {
|
||||
if (willBeFullScreen) {
|
||||
this.setMenuBarVisibility(false);
|
||||
} else {
|
||||
this.setMenuBarVisibility(!this.storageService.getItem<boolean>(VSCodeWindow.menuBarHiddenKey, false)); // restore as configured
|
||||
}
|
||||
}
|
||||
// respect configured menu bar visibility or default to toggle if not set
|
||||
this.setMenuBarVisibility(this.getMenuBarVisibility(this.configurationService.getConfiguration<IConfiguration>(), willBeFullScreen ? 'toggle' : 'visible'), false);
|
||||
}
|
||||
|
||||
public setMenuBarVisibility(visible: boolean): void {
|
||||
this.win.setMenuBarVisibility(visible);
|
||||
this.win.setAutoHideMenuBar(!visible);
|
||||
private getMenuBarVisibility(configuration: IConfiguration, fallback: 'visible' | 'toggle' | 'hidden' = 'visible'): 'visible' | 'toggle' | 'hidden' {
|
||||
const windowConfig = this.configurationService.getConfiguration<IWindowSettings>('window');
|
||||
|
||||
if (!windowConfig || !windowConfig.menuBarVisibility) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
let menuBarVisibility = windowConfig.menuBarVisibility;
|
||||
if (['visible', 'toggle', 'hidden'].indexOf(menuBarVisibility) < 0) {
|
||||
menuBarVisibility = fallback;
|
||||
}
|
||||
|
||||
return menuBarVisibility;
|
||||
}
|
||||
|
||||
public setMenuBarVisibility(visibility: 'visible' | 'toggle' | 'hidden', notify: boolean = true): void {
|
||||
if (platform.isMacintosh) {
|
||||
return; // ignore for macOS platform
|
||||
}
|
||||
|
||||
switch (visibility) {
|
||||
case ('visible'):
|
||||
this.win.setMenuBarVisibility(true);
|
||||
this.win.setAutoHideMenuBar(false);
|
||||
break;
|
||||
|
||||
case ('toggle'):
|
||||
this.win.setMenuBarVisibility(false);
|
||||
this.win.setAutoHideMenuBar(true);
|
||||
|
||||
if (notify) {
|
||||
this.send('vscode:showInfoMessage', nls.localize('hiddenMenuBar', "You can still access the menu bar by pressing the **Alt** key."));
|
||||
};
|
||||
break;
|
||||
|
||||
case ('hidden'):
|
||||
this.win.setMenuBarVisibility(false);
|
||||
this.win.setAutoHideMenuBar(false);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
public sendWhenReady(channel: string, ...args: any[]): void {
|
||||
|
|
|
@ -104,6 +104,7 @@ export interface IWindowsMainService {
|
|||
// events
|
||||
onWindowReady: CommonEvent<VSCodeWindow>;
|
||||
onWindowClose: CommonEvent<number>;
|
||||
onWindowReload: CommonEvent<number>;
|
||||
onPathsOpen: CommonEvent<IPath[]>;
|
||||
onRecentPathsChange: CommonEvent<void>;
|
||||
|
||||
|
@ -131,7 +132,6 @@ export interface IWindowsMainService {
|
|||
removeFromRecentPathsList(path: string): void;
|
||||
removeFromRecentPathsList(paths: string[]): void;
|
||||
clearRecentPathsList(): void;
|
||||
toggleMenuBar(windowId: number): void;
|
||||
quit(): void;
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,9 @@ export class WindowsManager implements IWindowsMainService {
|
|||
private _onWindowClose = new Emitter<number>();
|
||||
onWindowClose: CommonEvent<number> = this._onWindowClose.event;
|
||||
|
||||
private _onWindowReload = new Emitter<number>();
|
||||
onWindowReload: CommonEvent<number> = this._onWindowReload.event;
|
||||
|
||||
private _onPathsOpen = new Emitter<IPath[]>();
|
||||
onPathsOpen: CommonEvent<IPath> = this._onPathsOpen.event;
|
||||
|
||||
|
@ -292,6 +295,9 @@ export class WindowsManager implements IWindowsMainService {
|
|||
this.lifecycleService.unload(win, UnloadReason.RELOAD).done(veto => {
|
||||
if (!veto) {
|
||||
win.reload(cli);
|
||||
|
||||
// Emit
|
||||
this._onWindowReload.fire(win.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1176,24 +1182,6 @@ export class WindowsManager implements IWindowsMainService {
|
|||
return pathA === pathB;
|
||||
}
|
||||
|
||||
public toggleMenuBar(windowId: number): void {
|
||||
// Update in settings
|
||||
const menuBarHidden = this.storageService.getItem(VSCodeWindow.menuBarHiddenKey, false);
|
||||
const newMenuBarHidden = !menuBarHidden;
|
||||
this.storageService.setItem(VSCodeWindow.menuBarHiddenKey, newMenuBarHidden);
|
||||
|
||||
// Update across windows
|
||||
WindowsManager.WINDOWS.forEach(w => w.setMenuBarVisibility(!newMenuBarHidden));
|
||||
|
||||
// Inform user if menu bar is now hidden
|
||||
if (newMenuBarHidden) {
|
||||
const vscodeWindow = this.getWindowById(windowId);
|
||||
if (vscodeWindow) {
|
||||
vscodeWindow.send('vscode:showInfoMessage', nls.localize('hiddenMenuBar', "You can still access the menu bar by pressing the **Alt** key."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateWindowsJumpList(): void {
|
||||
if (!platform.isWindows) {
|
||||
return; // only on windows
|
||||
|
|
|
@ -54,38 +54,69 @@ export function ensureValidWordDefinition(wordDefinition?: RegExp): RegExp {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition {
|
||||
function getWordAtPosFast(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition {
|
||||
// find whitespace enclosed text around column and match from there
|
||||
|
||||
// console.log('_getWordAtText: ', column, text, textOffset);
|
||||
if (wordDefinition.test(' ')) {
|
||||
return getWordAtPosSlow(column, wordDefinition, text, textOffset);
|
||||
}
|
||||
|
||||
var words = text.match(wordDefinition),
|
||||
k: number,
|
||||
startWord: number,
|
||||
endWord: number,
|
||||
startColumn: number,
|
||||
endColumn: number,
|
||||
word: string;
|
||||
let pos = column - 1 - textOffset;
|
||||
let start = text.lastIndexOf(' ', pos - 1) + 1;
|
||||
let end = text.indexOf(' ', pos);
|
||||
if (end === -1) {
|
||||
end = text.length;
|
||||
}
|
||||
|
||||
if (words) {
|
||||
for (k = 0; k < words.length; k++) {
|
||||
word = words[k].trim();
|
||||
if (word.length > 0) {
|
||||
startWord = text.indexOf(word, endWord);
|
||||
endWord = startWord + word.length;
|
||||
|
||||
startColumn = textOffset + startWord + 1;
|
||||
endColumn = textOffset + endWord + 1;
|
||||
|
||||
if (startColumn <= column && column <= endColumn) {
|
||||
return {
|
||||
word: word,
|
||||
startColumn: startColumn,
|
||||
endColumn: endColumn
|
||||
};
|
||||
}
|
||||
}
|
||||
wordDefinition.lastIndex = start;
|
||||
let match: RegExpMatchArray;
|
||||
while (match = wordDefinition.exec(text)) {
|
||||
if (match.index <= pos && wordDefinition.lastIndex >= pos) {
|
||||
return {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + match.index,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function getWordAtPosSlow(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition {
|
||||
// matches all words starting at the beginning
|
||||
// of the input until it finds a match that encloses
|
||||
// the desired column. slow but correct
|
||||
|
||||
let pos = column - 1 - textOffset;
|
||||
wordDefinition.lastIndex = 0;
|
||||
|
||||
let match: RegExpMatchArray;
|
||||
while (match = wordDefinition.exec(text)) {
|
||||
|
||||
if (match.index > pos) {
|
||||
// |nW -> matched only after the pos
|
||||
return null;
|
||||
|
||||
} else if (wordDefinition.lastIndex >= pos) {
|
||||
// W|W -> match encloses pos
|
||||
return {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + match.index,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition {
|
||||
const result = getWordAtPosFast(column, wordDefinition, text, textOffset);
|
||||
// both (getWordAtPosFast and getWordAtPosSlow) leave the wordDefinition-RegExp
|
||||
// in an undefined state and to not confuse other users of the wordDefinition
|
||||
// we reset the lastIndex
|
||||
wordDefinition.lastIndex = 0;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -148,8 +148,11 @@ class MirrorModel extends MirrorModel2 implements ICommonModel {
|
|||
|
||||
// TODO@Joh, TODO@Alex - remove these and make sure the super-things work
|
||||
private _wordenize(content: string, wordDefinition: RegExp): editorCommon.IWordRange[] {
|
||||
var result: editorCommon.IWordRange[] = [];
|
||||
var match: RegExpExecArray;
|
||||
const result: editorCommon.IWordRange[] = [];
|
||||
let match: RegExpExecArray;
|
||||
|
||||
wordDefinition.lastIndex = 0; // reset lastIndex just to be sure
|
||||
|
||||
while (match = wordDefinition.exec(content)) {
|
||||
if (match[0].length === 0) {
|
||||
// it did match the empty string
|
||||
|
|
|
@ -22,7 +22,7 @@ interface ISnippetPick extends IPickOpenEntry {
|
|||
class Args {
|
||||
|
||||
static fromUser(arg: any): Args {
|
||||
if (typeof arg !== 'object') {
|
||||
if (!arg || typeof arg !== 'object') {
|
||||
return Args._empty;
|
||||
}
|
||||
let {snippet, name, langId} = arg;
|
||||
|
|
|
@ -62,12 +62,10 @@ export interface ProblemPattern {
|
|||
|
||||
loop?: boolean;
|
||||
|
||||
mostSignifikant?: boolean;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export let problemPatternProperties = ['file', 'message', 'location', 'line', 'column', 'endLine', 'endColumn', 'code', 'severity', 'loop', 'mostSignifikant'];
|
||||
export let problemPatternProperties = ['file', 'message', 'location', 'line', 'column', 'endLine', 'endColumn', 'code', 'severity', 'loop'];
|
||||
|
||||
export interface WatchingPattern {
|
||||
regexp: RegExp;
|
||||
|
|
|
@ -37,7 +37,6 @@ export interface IWindowsService {
|
|||
maximizeWindow(windowId: number): TPromise<void>;
|
||||
unmaximizeWindow(windowId: number): TPromise<void>;
|
||||
setDocumentEdited(windowId: number, flag: boolean): TPromise<void>;
|
||||
toggleMenuBar(windowId: number): TPromise<void>;
|
||||
quit(): TPromise<void>;
|
||||
|
||||
// Global methods
|
||||
|
@ -80,7 +79,6 @@ export interface IWindowService {
|
|||
getRecentlyOpen(): TPromise<{ files: string[]; folders: string[]; }>;
|
||||
focusWindow(): TPromise<void>;
|
||||
setDocumentEdited(flag: boolean): TPromise<void>;
|
||||
toggleMenuBar(): TPromise<void>;
|
||||
isMaximized(): TPromise<boolean>;
|
||||
maximizeWindow(): TPromise<void>;
|
||||
unmaximizeWindow(): TPromise<void>;
|
||||
|
@ -94,4 +92,5 @@ export interface IWindowSettings {
|
|||
zoomLevel: number;
|
||||
titleBarStyle: 'native' | 'custom';
|
||||
autoDetectHighContrast: boolean;
|
||||
menuBarVisibility: 'visible' | 'toggle' | 'hidden';
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ export interface IWindowsChannel extends IChannel {
|
|||
call(command: 'maximizeWindow', arg: number): TPromise<void>;
|
||||
call(command: 'unmaximizeWindow', arg: number): TPromise<void>;
|
||||
call(command: 'setDocumentEdited', arg: [number, boolean]): TPromise<void>;
|
||||
call(command: 'toggleMenuBar', arg: number): TPromise<void>;
|
||||
call(command: 'quit'): TPromise<void>;
|
||||
call(command: 'openWindow', arg: [string[], { forceNewWindow?: boolean, forceReuseWindow?: boolean }]): TPromise<void>;
|
||||
call(command: 'openNewWindow'): TPromise<void>;
|
||||
|
@ -75,7 +74,6 @@ export class WindowsChannel implements IWindowsChannel {
|
|||
case 'maximizeWindow': return this.service.maximizeWindow(arg);
|
||||
case 'unmaximizeWindow': return this.service.unmaximizeWindow(arg);
|
||||
case 'setDocumentEdited': return this.service.setDocumentEdited(arg[0], arg[1]);
|
||||
case 'toggleMenuBar': return this.service.toggleMenuBar(arg);
|
||||
case 'openWindow': return this.service.openWindow(arg[0], arg[1]);
|
||||
case 'openNewWindow': return this.service.openNewWindow();
|
||||
case 'showWindow': return this.service.showWindow(arg);
|
||||
|
@ -171,10 +169,6 @@ export class WindowsChannelClient implements IWindowsService {
|
|||
return this.channel.call('setDocumentEdited', [windowId, flag]);
|
||||
}
|
||||
|
||||
toggleMenuBar(windowId: number): TPromise<void> {
|
||||
return this.channel.call('toggleMenuBar', windowId);
|
||||
}
|
||||
|
||||
quit(): TPromise<void> {
|
||||
return this.channel.call('quit');
|
||||
}
|
||||
|
@ -218,4 +212,4 @@ export class WindowsChannelClient implements IWindowsService {
|
|||
startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise<void> {
|
||||
return this.channel.call('startCrashReporter', config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,4 @@ export class WindowService implements IWindowService {
|
|||
return this.windowsService.setDocumentEdited(this.windowId, flag);
|
||||
}
|
||||
|
||||
toggleMenuBar(): TPromise<void> {
|
||||
return this.windowsService.toggleMenuBar(this.windowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,11 +193,6 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
toggleMenuBar(windowId: number): TPromise<void> {
|
||||
this.windowsMainService.toggleMenuBar(windowId);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void> {
|
||||
if (!paths || !paths.length) {
|
||||
return TPromise.as(null);
|
||||
|
@ -278,4 +273,4 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
|||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionManagementService, LocalExtensionType, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
|
@ -169,12 +170,36 @@ export class ToggleMenuBarAction extends Action {
|
|||
static ID = 'workbench.action.toggleMenuBar';
|
||||
static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar");
|
||||
|
||||
constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
|
||||
private static menuBarVisibilityKey = 'window.menuBarVisibility';
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): TPromise<void> {
|
||||
return this.windowService.toggleMenuBar();
|
||||
public run(): TPromise<any> {
|
||||
let currentVisibilityValue = this.configurationService.lookup<'visible' | 'toggle' | 'hidden'>(ToggleMenuBarAction.menuBarVisibilityKey).value;
|
||||
if (typeof (currentVisibilityValue) !== 'string') {
|
||||
currentVisibilityValue = 'visible';
|
||||
}
|
||||
|
||||
let newVisibilityValue: string;
|
||||
if (currentVisibilityValue === 'visible') {
|
||||
newVisibilityValue = 'toggle';
|
||||
} else {
|
||||
newVisibilityValue = 'visible';
|
||||
}
|
||||
|
||||
this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMenuBarAction.menuBarVisibilityKey, value: newVisibilityValue }).then(null, error => {
|
||||
this.messageService.show(Severity.Error, error);
|
||||
});
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -225,6 +225,15 @@ Note that there can still be cases where this setting is ignored (e.g. when usin
|
|||
}
|
||||
};
|
||||
|
||||
if (platform.isWindows || platform.isLinux) {
|
||||
properties['window.menuBarVisibility'] = {
|
||||
'type': 'string',
|
||||
'enum': ['visible', 'toggle', 'hidden'],
|
||||
'default': 'visible',
|
||||
'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that a single press of the alt key will show and hide the menu bar.")
|
||||
};
|
||||
}
|
||||
|
||||
if (platform.isWindows) {
|
||||
properties['window.autoDetectHighContrast'] = {
|
||||
'type': 'boolean',
|
||||
|
@ -273,4 +282,4 @@ configurationRegistry.registerConfiguration({
|
|||
'description': nls.localize('zenMode.hideStatusBar', "Controls if turning on Zen Mode also hides the status bar at the bottom of the workbench.")
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
|
@ -84,15 +84,11 @@ class ExtensionManifestParser extends ExtensionManifestHandler {
|
|||
|
||||
public parse(): TPromise<IExtensionDescription> {
|
||||
return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => {
|
||||
let errors: json.ParseError[] = [];
|
||||
const extensionDescription = json.parse(manifestContents.toString(), errors);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error) => {
|
||||
this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, json.getParseErrorMessage(error.error)));
|
||||
});
|
||||
return null;
|
||||
try {
|
||||
return JSON.parse(manifestContents.toString());
|
||||
} catch (e) {
|
||||
this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, json.getParseErrorMessage(e.message)));
|
||||
}
|
||||
return extensionDescription;
|
||||
}, (err) => {
|
||||
if (err.code === 'ENOENT') {
|
||||
return null;
|
||||
|
@ -165,40 +161,44 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
|||
/**
|
||||
* This routine make the following assumptions:
|
||||
* The root element is a object literal
|
||||
* Strings to replace are one values of a key. So for example string[] are ignored.
|
||||
* This is done to speed things up.
|
||||
*/
|
||||
private static _replaceNLStrings<T>(literal: T, messages: { [key: string]: string; }, collector: MessagesCollector, messageScope: string): void {
|
||||
Object.keys(literal).forEach(key => {
|
||||
if (literal.hasOwnProperty(key)) {
|
||||
let value = literal[key];
|
||||
if (Types.isString(value)) {
|
||||
let str = <string>value;
|
||||
let length = str.length;
|
||||
if (length > 1 && str[0] === '%' && str[length - 1] === '%') {
|
||||
let messageKey = str.substr(1, length - 2);
|
||||
let message = messages[messageKey];
|
||||
if (message) {
|
||||
if (nlsConfig.pseudo) {
|
||||
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
|
||||
message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
|
||||
}
|
||||
literal[key] = message;
|
||||
} else {
|
||||
collector.warn(messageScope, nls.localize('missingNLSKey', "Couldn't find message for key {0}.", messageKey));
|
||||
function processEntry(obj: any, key: string | number) {
|
||||
let value = obj[key];
|
||||
if (Types.isString(value)) {
|
||||
let str = <string>value;
|
||||
let length = str.length;
|
||||
if (length > 1 && str[0] === '%' && str[length - 1] === '%') {
|
||||
let messageKey = str.substr(1, length - 2);
|
||||
let message = messages[messageKey];
|
||||
if (message) {
|
||||
if (nlsConfig.pseudo) {
|
||||
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
|
||||
message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
|
||||
}
|
||||
obj[key] = message;
|
||||
} else {
|
||||
collector.warn(messageScope, nls.localize('missingNLSKey', "Couldn't find message for key {0}.", messageKey));
|
||||
}
|
||||
} else if (Types.isObject(value)) {
|
||||
ExtensionManifestNLSReplacer._replaceNLStrings(value, messages, collector, messageScope);
|
||||
} else if (Types.isArray(value)) {
|
||||
(<any[]>value).forEach(element => {
|
||||
if (Types.isObject(element)) {
|
||||
ExtensionManifestNLSReplacer._replaceNLStrings(element, messages, collector, messageScope);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (Types.isObject(value)) {
|
||||
for (let k in value) {
|
||||
if (value.hasOwnProperty(k)) {
|
||||
processEntry(value, k);
|
||||
}
|
||||
}
|
||||
} else if (Types.isArray(value)) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
processEntry(value, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let key in literal) {
|
||||
if (literal.hasOwnProperty(key)) {
|
||||
processEntry(literal, key);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -520,7 +520,7 @@ export class Process implements debug.IProcess {
|
|||
thread.stopped = true;
|
||||
thread.clearCallStack();
|
||||
});
|
||||
} else {
|
||||
} else if (this.threads.has(data.threadId)) {
|
||||
// One thread is stopped, only update that thread.
|
||||
const thread = this.threads.get(data.threadId);
|
||||
thread.stoppedDetails = data.stoppedDetails;
|
||||
|
|
|
@ -580,11 +580,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
|
|||
.then(null, onUnexpectedError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.gallery) {
|
||||
// Report telemetry only for gallery extensions
|
||||
this.reportTelemetry(installing, !error);
|
||||
if (extension.gallery) {
|
||||
// Report telemetry only for gallery extensions
|
||||
this.reportTelemetry(installing, !error);
|
||||
}
|
||||
}
|
||||
this._onChange.fire();
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
|||
import { Keybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { getCodeEditor } from 'vs/editor/common/services/codeEditorService';
|
||||
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
export interface IEditableData {
|
||||
action: IAction;
|
||||
|
@ -271,7 +273,9 @@ class RenameFileAction extends BaseRenameAction {
|
|||
element: FileStat,
|
||||
@IFileService fileService: IFileService,
|
||||
@IMessageService messageService: IMessageService,
|
||||
@ITextFileService textFileService: ITextFileService
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@ITextModelResolverService private textModelResolverService: ITextModelResolverService,
|
||||
@IBackupFileService private backupFileService: IBackupFileService
|
||||
) {
|
||||
super(RenameFileAction.ID, nls.localize('rename', "Rename"), element, fileService, messageService, textFileService);
|
||||
|
||||
|
@ -280,40 +284,44 @@ class RenameFileAction extends BaseRenameAction {
|
|||
|
||||
public runAction(newName: string): TPromise<any> {
|
||||
|
||||
// Handle dirty
|
||||
let revertPromise: TPromise<any> = TPromise.as(null);
|
||||
// 1. check for dirty files that are being moved and backup to new target
|
||||
const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, this.element.resource.fsPath));
|
||||
if (dirty.length) {
|
||||
let message: string;
|
||||
if (this.element.isDirectory) {
|
||||
if (dirty.length === 1) {
|
||||
message = nls.localize('dirtyMessageFolderOne', "You are renaming a folder with unsaved changes in 1 file. Do you want to continue?");
|
||||
} else {
|
||||
message = nls.localize('dirtyMessageFolder', "You are renaming a folder with unsaved changes in {0} files. Do you want to continue?", dirty.length);
|
||||
}
|
||||
} else {
|
||||
message = nls.localize('dirtyMessageFile', "You are renaming a file with unsaved changes. Do you want to continue?");
|
||||
const dirtyRenamed: URI[] = [];
|
||||
return TPromise.join(dirty.map(d => {
|
||||
const targetPath = paths.join(this.element.parent.resource.fsPath, newName);
|
||||
let renamed: URI;
|
||||
|
||||
// If the dirty file itself got moved, just reparent it to the target folder
|
||||
if (this.element.resource.fsPath === d.fsPath) {
|
||||
renamed = URI.file(targetPath);
|
||||
}
|
||||
|
||||
const res = this.messageService.confirm({
|
||||
message,
|
||||
type: 'warning',
|
||||
detail: nls.localize('dirtyWarning', "Your changes will be lost if you don't save them."),
|
||||
primaryButton: nls.localize({ key: 'renameLabel', comment: ['&& denotes a mnemonic'] }, "&&Rename")
|
||||
});
|
||||
|
||||
if (!res) {
|
||||
return TPromise.as(null);
|
||||
// Otherwise, a parent of the dirty resource got moved, so we have to reparent more complicated. Example:
|
||||
else {
|
||||
renamed = URI.file(paths.join(targetPath, d.fsPath.substr(this.element.resource.fsPath.length + 1)));
|
||||
}
|
||||
|
||||
revertPromise = this.textFileService.revertAll(dirty);
|
||||
}
|
||||
dirtyRenamed.push(renamed);
|
||||
|
||||
return revertPromise.then(() => {
|
||||
return this.fileService.rename(this.element.resource, newName).then(null, (error: Error) => {
|
||||
this.onErrorWithRetry(error, () => this.runAction(newName));
|
||||
const model = this.textFileService.models.get(d);
|
||||
|
||||
return this.backupFileService.backupResource(renamed, model.getValue(), model.getVersionId());
|
||||
}))
|
||||
|
||||
// 2. soft revert all dirty since we have backed up their contents
|
||||
.then(() => this.textFileService.revertAll(dirty, { soft: true /* do not attempt to load content from disk */ }))
|
||||
|
||||
// 3.) run the rename operation
|
||||
.then(() => this.fileService.rename(this.element.resource, newName).then(null, (error: Error) => {
|
||||
return TPromise.join(dirtyRenamed.map(d => this.backupFileService.discardResourceBackup(d))).then(() => {
|
||||
this.onErrorWithRetry(error, () => this.runAction(newName));
|
||||
});
|
||||
}))
|
||||
|
||||
// 4.) resolve those that were dirty to load their previous dirty contents from disk
|
||||
.then(() => {
|
||||
return TPromise.join(dirtyRenamed.map(t => this.textModelResolverService.createModelReference(t)));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,12 +829,23 @@ export class ImportFileAction extends BaseFileAction {
|
|||
|
||||
// Run import in sequence
|
||||
const importPromisesFactory: ITask<TPromise<void>>[] = [];
|
||||
filesArray.forEach((file) => {
|
||||
filesArray.forEach(file => {
|
||||
importPromisesFactory.push(() => {
|
||||
const sourceFile = URI.file(file.path);
|
||||
const targetFile = URI.file(paths.join(targetElement.resource.fsPath, paths.basename(file.path)));
|
||||
|
||||
return this.fileService.importFile(sourceFile, targetElement.resource).then(null, (error: any) => {
|
||||
this.messageService.show(Severity.Error, error);
|
||||
// if the target exists and is dirty, make sure to revert it. otherwise the dirty contents
|
||||
// of the target file would replace the contents of the imported file. since we already
|
||||
// confirmed the overwrite before, this is OK.
|
||||
let revertPromise = TPromise.as(null);
|
||||
if (this.textFileService.isDirty(targetFile)) {
|
||||
revertPromise = this.textFileService.revertAll([targetFile], { soft: true });
|
||||
}
|
||||
|
||||
return revertPromise.then(() => {
|
||||
return this.fileService.importFile(sourceFile, targetElement.resource).then(null, (error: any) => {
|
||||
this.messageService.show(Severity.Error, error);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -49,6 +49,8 @@ import { Keybinding, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
|||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
export class FileDataSource implements IDataSource {
|
||||
constructor(
|
||||
|
@ -723,7 +725,9 @@ export class FileDragAndDrop implements IDragAndDrop {
|
|||
@IFileService private fileService: IFileService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ITextFileService private textFileService: ITextFileService
|
||||
@ITextFileService private textFileService: ITextFileService,
|
||||
@ITextModelResolverService private textModelResolverService: ITextModelResolverService,
|
||||
@IBackupFileService private backupFileService: IBackupFileService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
|
||||
|
@ -868,70 +872,87 @@ export class FileDragAndDrop implements IDragAndDrop {
|
|||
|
||||
promise = tree.expand(target).then(() => {
|
||||
|
||||
// Reuse action if user copies
|
||||
// Reuse duplicate action if user copies
|
||||
if (isCopy) {
|
||||
const copyAction = this.instantiationService.createInstance(DuplicateFileAction, tree, source, target);
|
||||
return copyAction.run();
|
||||
return this.instantiationService.createInstance(DuplicateFileAction, tree, source, target).run();
|
||||
}
|
||||
|
||||
// Handle dirty (in file or inside the folder if any)
|
||||
let revertPromise: TPromise<any> = TPromise.as(null);
|
||||
const dirtyMoved: URI[] = [];
|
||||
|
||||
// Success: load all files that are dirty again to restore their dirty contents
|
||||
// Error: discard any backups created during the process
|
||||
const onSuccess = () => TPromise.join(dirtyMoved.map(t => this.textModelResolverService.createModelReference(t)));
|
||||
const onError = (error?: Error, showError?: boolean) => {
|
||||
if (showError) {
|
||||
this.messageService.show(Severity.Error, error);
|
||||
}
|
||||
|
||||
return TPromise.join(dirtyMoved.map(d => this.backupFileService.discardResourceBackup(d)));
|
||||
};
|
||||
|
||||
// 1. check for dirty files that are being moved and backup to new target
|
||||
const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, source.resource.fsPath));
|
||||
if (dirty.length) {
|
||||
let message: string;
|
||||
if (source.isDirectory) {
|
||||
if (dirty.length === 1) {
|
||||
message = nls.localize('dirtyMessageFolderOne', "You are moving a folder with unsaved changes in 1 file. Do you want to continue?");
|
||||
} else {
|
||||
message = nls.localize('dirtyMessageFolder', "You are moving a folder with unsaved changes in {0} files. Do you want to continue?", dirty.length);
|
||||
}
|
||||
} else {
|
||||
message = nls.localize('dirtyMessageFile', "You are moving a file with unsaved changes. Do you want to continue?");
|
||||
return TPromise.join(dirty.map(d => {
|
||||
let moved: URI;
|
||||
|
||||
// If the dirty file itself got moved, just reparent it to the target folder
|
||||
if (source.resource.fsPath === d.fsPath) {
|
||||
moved = URI.file(paths.join(target.resource.fsPath, source.name));
|
||||
}
|
||||
|
||||
const res = this.messageService.confirm({
|
||||
message,
|
||||
type: 'warning',
|
||||
detail: nls.localize('dirtyWarning', "Your changes will be lost if you don't save them."),
|
||||
primaryButton: nls.localize({ key: 'moveLabel', comment: ['&& denotes a mnemonic'] }, "&&Move")
|
||||
});
|
||||
|
||||
if (!res) {
|
||||
return TPromise.as(null);
|
||||
// Otherwise, a parent of the dirty resource got moved, so we have to reparent more complicated. Example:
|
||||
else {
|
||||
moved = URI.file(paths.join(target.resource.fsPath, d.fsPath.substr(source.parent.resource.fsPath.length + 1)));
|
||||
}
|
||||
|
||||
revertPromise = this.textFileService.revertAll(dirty);
|
||||
}
|
||||
dirtyMoved.push(moved);
|
||||
|
||||
return revertPromise.then(() => {
|
||||
const targetResource = URI.file(paths.join(target.resource.fsPath, source.name));
|
||||
let didHandleConflict = false;
|
||||
const model = this.textFileService.models.get(d);
|
||||
|
||||
// Move File/Folder
|
||||
return this.fileService.moveFile(source.resource, targetResource).then(null, error => {
|
||||
return this.backupFileService.backupResource(moved, model.getValue(), model.getVersionId());
|
||||
}))
|
||||
|
||||
// Conflict
|
||||
if ((<IFileOperationResult>error).fileOperationResult === FileOperationResult.FILE_MOVE_CONFLICT) {
|
||||
didHandleConflict = true;
|
||||
// 2. soft revert all dirty since we have backed up their contents
|
||||
.then(() => this.textFileService.revertAll(dirty, { soft: true /* do not attempt to load content from disk */ }))
|
||||
|
||||
const confirm: IConfirmation = {
|
||||
message: nls.localize('confirmOverwriteMessage', "'{0}' already exists in the destination folder. Do you want to replace it?", source.name),
|
||||
detail: nls.localize('irreversible', "This action is irreversible!"),
|
||||
primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace")
|
||||
};
|
||||
// 3.) run the move operation
|
||||
.then(() => {
|
||||
const targetResource = URI.file(paths.join(target.resource.fsPath, source.name));
|
||||
let didHandleConflict = false;
|
||||
|
||||
if (this.messageService.confirm(confirm)) {
|
||||
return this.fileService.moveFile(source.resource, targetResource, true).then(null, (error) => {
|
||||
this.messageService.show(Severity.Error, error);
|
||||
});
|
||||
return this.fileService.moveFile(source.resource, targetResource).then(null, error => {
|
||||
|
||||
// Conflict
|
||||
if ((<IFileOperationResult>error).fileOperationResult === FileOperationResult.FILE_MOVE_CONFLICT) {
|
||||
didHandleConflict = true;
|
||||
|
||||
const confirm: IConfirmation = {
|
||||
message: nls.localize('confirmOverwriteMessage', "'{0}' already exists in the destination folder. Do you want to replace it?", source.name),
|
||||
detail: nls.localize('irreversible', "This action is irreversible!"),
|
||||
primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace")
|
||||
};
|
||||
|
||||
// Move with overwrite if the user confirms
|
||||
if (this.messageService.confirm(confirm)) {
|
||||
const targetDirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, targetResource.fsPath));
|
||||
|
||||
// Make sure to revert all dirty in target first to be able to overwrite properly
|
||||
return this.textFileService.revertAll(targetDirty, { soft: true /* do not attempt to load content from disk */ }).then(() => {
|
||||
|
||||
// Then continue to do the move operation
|
||||
return this.fileService.moveFile(source.resource, targetResource, true).then(onSuccess, error => onError(error, true));
|
||||
});
|
||||
}
|
||||
|
||||
return onError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
return onError(error, true);
|
||||
});
|
||||
})
|
||||
|
||||
this.messageService.show(Severity.Error, error);
|
||||
});
|
||||
});
|
||||
// 4.) resolve those that were dirty to load their previous dirty contents from disk
|
||||
.then(onSuccess, onError);
|
||||
}, errors.onUnexpectedError);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
|||
import errors = require('vs/base/common/errors');
|
||||
import URI from 'vs/base/common/uri';
|
||||
import paths = require('vs/base/common/paths');
|
||||
import { IEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditor, IEditorViewState, isCommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditor as IBaseEditor } from 'vs/platform/editor/common/editor';
|
||||
import { EditorInput, IEditorStacksModel, SideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { toResource, EditorInput, IEditorStacksModel, SideBySideEditorInput, IEditorGroup } from 'vs/workbench/common/editor';
|
||||
import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/parts/files/common/files';
|
||||
import { ITextFileService, ModelState } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files';
|
||||
|
@ -157,13 +157,42 @@ export class FileEditorTracker implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
// Reopen
|
||||
this.editorService.openEditor({ resource: reopenFileResource, options: { preserveFocus: true, pinned: group.isPinned(input), index: group.indexOf(input), inactive: !group.isActive(input) } }, stacks.positionOfGroup(group)).done(null, errors.onUnexpectedError);
|
||||
this.editorService.openEditor({
|
||||
resource: reopenFileResource,
|
||||
options: {
|
||||
preserveFocus: true,
|
||||
pinned: group.isPinned(input),
|
||||
index: group.indexOf(input),
|
||||
inactive: !group.isActive(input),
|
||||
viewState: this.getViewStateFor(oldResource, group)
|
||||
}
|
||||
}, stacks.positionOfGroup(group)).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getViewStateFor(resource: URI, group: IEditorGroup): IEditorViewState {
|
||||
const stacks = this.editorGroupService.getStacksModel();
|
||||
const editors = this.editorService.getVisibleEditors();
|
||||
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
const editor = editors[i];
|
||||
if (editor && editor.position === stacks.positionOfGroup(group)) {
|
||||
const resource = toResource(editor.input, { filter: 'file' });
|
||||
if (resource && resource.fsPath === resource.fsPath) {
|
||||
const control = editor.getControl();
|
||||
if (isCommonCodeEditor(control)) {
|
||||
return control.saveViewState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return void 0;
|
||||
}
|
||||
|
||||
private handleUpdatesToVisibleEditors(e: FileChangesEvent) {
|
||||
const editors = this.editorService.getVisibleEditors();
|
||||
editors.forEach(editor => {
|
||||
|
|
|
@ -142,7 +142,6 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
|||
options.folding = false;
|
||||
options.renderWhitespace = 'none';
|
||||
options.wrappingColumn = 0;
|
||||
options.overviewRulerLanes = 0;
|
||||
options.renderIndentGuides = false;
|
||||
options.rulers = [];
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
|||
openWorkspaceSettings(): TPromise<void> {
|
||||
if (!this.contextService.hasWorkspace()) {
|
||||
this.messageService.show(Severity.Info, nls.localize('openFolderFirst', "Open a folder first to create workspace settings"));
|
||||
return;
|
||||
return TPromise.as(null);
|
||||
}
|
||||
return this.openSettings(ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
|
|
|
@ -91,8 +91,11 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
|
|||
}
|
||||
|
||||
private layout(): void {
|
||||
this.titleContainer.style.lineHeight = this.editor.getConfiguration().lineHeight + 3 + 'px';
|
||||
this.titleContainer.style.fontSize = this.editor.getConfiguration().fontInfo.fontSize + 'px';
|
||||
const configuration = this.editor.getConfiguration();
|
||||
const layoutInfo = this.editor.getLayoutInfo();
|
||||
this.titleContainer.style.width = layoutInfo.contentWidth - layoutInfo.verticalScrollbarWidth + 'px';
|
||||
this.titleContainer.style.lineHeight = configuration.lineHeight + 3 + 'px';
|
||||
this.titleContainer.style.fontSize = configuration.fontInfo.fontSize + 'px';
|
||||
const iconSize = this.getIconSize();
|
||||
this.icon.style.height = `${iconSize}px`;
|
||||
this.icon.style.width = `${iconSize}px`;
|
||||
|
|
|
@ -470,6 +470,7 @@ export class SearchViewlet extends Viewlet {
|
|||
}
|
||||
|
||||
// Reveal the newly selected element
|
||||
this.tree.setFocus(next, eventPayload);
|
||||
this.tree.setSelection([next], eventPayload);
|
||||
this.tree.reveal(next);
|
||||
}
|
||||
|
@ -497,7 +498,9 @@ export class SearchViewlet extends Viewlet {
|
|||
}
|
||||
|
||||
// Reveal the newly selected element
|
||||
this.tree.setFocus(prev, eventPayload);
|
||||
this.tree.setSelection([prev], eventPayload);
|
||||
this.tree.reveal(prev);
|
||||
}
|
||||
|
||||
public setVisible(visible: boolean): TPromise<void> {
|
||||
|
|
|
@ -229,11 +229,6 @@ class PatternBuilder {
|
|||
this.result.loop = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public mostSignifikant(value: boolean): PatternBuilder {
|
||||
this.result.mostSignifikant = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1007,6 +1002,5 @@ suite('Tasks Configuration parsing tests', () => {
|
|||
assert.strictEqual(actual.code, expected.code);
|
||||
assert.strictEqual(actual.severity, expected.severity);
|
||||
assert.strictEqual(actual.loop, expected.loop);
|
||||
assert.strictEqual(actual.mostSignifikant, expected.mostSignifikant);
|
||||
}
|
||||
});
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IConfiguration, DefaultConfig } from 'vs/editor/common/config/defaultConfig';
|
||||
import { IConfiguration as IEditorConfiguration, DefaultConfig } from 'vs/editor/common/config/defaultConfig';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITerminalConfiguration, ITerminalConfigHelper, ITerminalFont, IShell } from 'vs/workbench/parts/terminal/common/terminal';
|
||||
import { Platform } from 'vs/base/common/platform';
|
||||
|
@ -91,16 +91,16 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
|
|||
this._charMeasureElement = document.createElement('div');
|
||||
this.panelContainer.appendChild(this._charMeasureElement);
|
||||
}
|
||||
let style = this._charMeasureElement.style;
|
||||
const style = this._charMeasureElement.style;
|
||||
style.display = 'block';
|
||||
style.fontFamily = fontFamily;
|
||||
style.fontSize = fontSize + 'px';
|
||||
style.height = Math.floor(lineHeight * fontSize) + 'px';
|
||||
style.lineHeight = lineHeight.toString(10);
|
||||
this._charMeasureElement.innerText = 'X';
|
||||
let rect = this._charMeasureElement.getBoundingClientRect();
|
||||
const rect = this._charMeasureElement.getBoundingClientRect();
|
||||
style.display = 'none';
|
||||
let charWidth = Math.ceil(rect.width);
|
||||
let charHeight = Math.ceil(rect.height);
|
||||
const charWidth = rect.width;
|
||||
const charHeight = rect.height;
|
||||
return {
|
||||
fontFamily,
|
||||
fontSize: fontSize + 'px',
|
||||
|
@ -115,37 +115,46 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
|
|||
* terminal.integrated.fontSize, terminal.integrated.lineHeight configuration properties
|
||||
*/
|
||||
public getFont(): ITerminalFont {
|
||||
let terminalConfig = this._configurationService.getConfiguration<ITerminalConfiguration>().terminal.integrated;
|
||||
let editorConfig = this._configurationService.getConfiguration<IConfiguration>();
|
||||
const config = this._configurationService.getConfiguration();
|
||||
const editorConfig = (<IEditorConfiguration>config).editor;
|
||||
const terminalConfig = (<ITerminalConfiguration>config).terminal.integrated;
|
||||
|
||||
let fontFamily = terminalConfig.fontFamily || editorConfig.editor.fontFamily;
|
||||
const fontFamily = terminalConfig.fontFamily || editorConfig.fontFamily;
|
||||
let fontSize = this._toInteger(terminalConfig.fontSize, 0);
|
||||
if (fontSize <= 0) {
|
||||
fontSize = DefaultConfig.editor.fontSize;
|
||||
}
|
||||
let lineHeight = terminalConfig.lineHeight <= 0 ? DEFAULT_LINE_HEIGHT : terminalConfig.lineHeight;
|
||||
if (!lineHeight) {
|
||||
lineHeight = DEFAULT_LINE_HEIGHT;
|
||||
}
|
||||
|
||||
return this._measureFont(fontFamily, fontSize, lineHeight);
|
||||
}
|
||||
|
||||
public getFontLigaturesEnabled(): boolean {
|
||||
let terminalConfig = this._configurationService.getConfiguration<ITerminalConfiguration>().terminal.integrated;
|
||||
return terminalConfig.fontLigatures;
|
||||
const terminalConfig = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
return terminalConfig.terminal.integrated.fontLigatures;
|
||||
}
|
||||
|
||||
public getCursorBlink(): boolean {
|
||||
let terminalConfig = this._configurationService.getConfiguration<ITerminalConfiguration>().terminal.integrated;
|
||||
return terminalConfig.cursorBlinking;
|
||||
const terminalConfig = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
return terminalConfig.terminal.integrated.cursorBlinking;
|
||||
}
|
||||
|
||||
public getRightClickCopyPaste(): boolean {
|
||||
let config = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
const config = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
return config.terminal.integrated.rightClickCopyPaste;
|
||||
}
|
||||
|
||||
public getCommandsToSkipShell(): string[] {
|
||||
const config = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
return config.terminal.integrated.commandsToSkipShell;
|
||||
}
|
||||
|
||||
public getShell(): IShell {
|
||||
let config = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
let shell: IShell = {
|
||||
const config = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
const shell: IShell = {
|
||||
executable: '',
|
||||
args: []
|
||||
};
|
||||
|
@ -190,9 +199,4 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
|
|||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public getCommandsToSkipShell(): string[] {
|
||||
let config = this._configurationService.getConfiguration<ITerminalConfiguration>();
|
||||
return config.terminal.integrated.commandsToSkipShell;
|
||||
}
|
||||
}
|
|
@ -156,8 +156,8 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}, 0);
|
||||
});
|
||||
|
||||
let xtermHelper: HTMLElement = this._xterm.element.querySelector('.xterm-helpers');
|
||||
let focusTrap: HTMLElement = document.createElement('div');
|
||||
const xtermHelper: HTMLElement = this._xterm.element.querySelector('.xterm-helpers');
|
||||
const focusTrap: HTMLElement = document.createElement('div');
|
||||
focusTrap.setAttribute('tabindex', '0');
|
||||
DOM.addClass(focusTrap, 'focus-trap');
|
||||
focusTrap.addEventListener('focus', function (event: FocusEvent) {
|
||||
|
@ -165,7 +165,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
while (!DOM.hasClass(currentElement, 'part')) {
|
||||
currentElement = currentElement.parentElement;
|
||||
}
|
||||
let hidePanelElement = <HTMLElement>currentElement.querySelector('.hide-panel-action');
|
||||
const hidePanelElement = <HTMLElement>currentElement.querySelector('.hide-panel-action');
|
||||
hidePanelElement.focus();
|
||||
});
|
||||
xtermHelper.insertBefore(focusTrap, this._xterm.textarea);
|
||||
|
@ -240,7 +240,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
if (!this._xterm) {
|
||||
return;
|
||||
}
|
||||
let text = window.getSelection().toString();
|
||||
const text = window.getSelection().toString();
|
||||
if (!text || force) {
|
||||
this._xterm.focus();
|
||||
}
|
||||
|
@ -331,11 +331,11 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}
|
||||
|
||||
protected _createProcess(workspace: IWorkspace, name: string, shell: IShell) {
|
||||
let locale = this._configHelper.isSetLocaleVariables() ? platform.locale : undefined;
|
||||
const locale = this._configHelper.isSetLocaleVariables() ? platform.locale : undefined;
|
||||
if (!shell.executable) {
|
||||
shell = this._configHelper.getShell();
|
||||
}
|
||||
let env = TerminalInstance.createTerminalEnv(process.env, shell, this._getCwd(workspace, shell.ignoreCustomCwd), locale);
|
||||
const env = TerminalInstance.createTerminalEnv(process.env, shell, this._getCwd(workspace, shell.ignoreCustomCwd), locale);
|
||||
this._title = name ? name : '';
|
||||
this._process = cp.fork('./terminalProcess', [], {
|
||||
env: env,
|
||||
|
@ -378,7 +378,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
// TODO: This should be private/protected
|
||||
// TODO: locale should not be optional
|
||||
public static createTerminalEnv(parentEnv: IStringDictionary<string>, shell: IShell, cwd: string, locale?: string): IStringDictionary<string> {
|
||||
let env = TerminalInstance._cloneEnv(parentEnv);
|
||||
const env = TerminalInstance._cloneEnv(parentEnv);
|
||||
env['PTYPID'] = process.pid.toString();
|
||||
env['PTYSHELL'] = shell.executable;
|
||||
if (shell.args) {
|
||||
|
@ -402,7 +402,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}
|
||||
|
||||
private static _cloneEnv(env: IStringDictionary<string>): IStringDictionary<string> {
|
||||
let newEnv: IStringDictionary<string> = Object.create(null);
|
||||
const newEnv: IStringDictionary<string> = Object.create(null);
|
||||
Object.keys(env).forEach((key) => {
|
||||
newEnv[key] = env[key];
|
||||
});
|
||||
|
@ -442,7 +442,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}
|
||||
|
||||
public layout(dimension: { width: number, height: number }): void {
|
||||
let font = this._configHelper.getFont();
|
||||
const font = this._configHelper.getFont();
|
||||
if (!font || !font.charWidth || !font.charHeight) {
|
||||
return;
|
||||
}
|
||||
|
@ -455,10 +455,12 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
// Upstream issue: https://github.com/sourcelair/xterm.js/issues/291
|
||||
this._xterm.emit('scroll', this._xterm.ydisp);
|
||||
}
|
||||
let leftPadding = parseInt(getComputedStyle(document.querySelector('.terminal-outer-container')).paddingLeft.split('px')[0], 10);
|
||||
let innerWidth = dimension.width - leftPadding;
|
||||
let cols = Math.floor(innerWidth / font.charWidth);
|
||||
let rows = Math.floor(dimension.height / font.charHeight);
|
||||
const padding = parseInt(getComputedStyle(document.querySelector('.terminal-outer-container')).paddingLeft.split('px')[0], 10);
|
||||
// Use left padding as right padding, right padding is not defined in CSS just in case
|
||||
// xterm.js causes an unexpected overflow.
|
||||
const innerWidth = dimension.width - padding * 2;
|
||||
const cols = Math.floor(innerWidth / font.charWidth);
|
||||
const rows = Math.floor(dimension.height / font.charHeight);
|
||||
if (this._xterm) {
|
||||
this._xterm.resize(cols, rows);
|
||||
this._xterm.element.style.width = innerWidth + 'px';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
var ptyJs = require('pty.js');
|
||||
var ptyJs = require('node-pty');
|
||||
|
||||
// The pty process needs to be run in its own child process to get around maxing out CPU on Mac,
|
||||
// see https://github.com/electron/electron/issues/38
|
||||
|
|
|
@ -207,7 +207,7 @@ suite('ExtHostDocument', () => {
|
|||
|
||||
test('getWordRangeAtPosition', function () {
|
||||
data = new ExtHostDocumentData(undefined, URI.file(''), [
|
||||
'aaaa bbbb cccc abc'
|
||||
'aaaa bbbb+cccc abc'
|
||||
], '\n', 'text', 1, false);
|
||||
|
||||
let range = data.getWordRangeAtPosition(new Position(0, 2));
|
||||
|
@ -216,19 +216,20 @@ suite('ExtHostDocument', () => {
|
|||
assert.equal(range.end.line, 0);
|
||||
assert.equal(range.end.character, 4);
|
||||
|
||||
// ignore bad regular expresson /.*/
|
||||
range = data.getWordRangeAtPosition(new Position(0, 2), /.*/);
|
||||
assert.equal(range.start.line, 0);
|
||||
assert.equal(range.start.character, 0);
|
||||
assert.equal(range.end.line, 0);
|
||||
assert.equal(range.end.character, 4);
|
||||
|
||||
range = data.getWordRangeAtPosition(new Position(0, 2), /a+.+?c/);
|
||||
range = data.getWordRangeAtPosition(new Position(0, 5), /[a-z+]+/);
|
||||
assert.equal(range.start.line, 0);
|
||||
assert.equal(range.start.character, 0);
|
||||
assert.equal(range.start.character, 5);
|
||||
assert.equal(range.end.line, 0);
|
||||
assert.equal(range.end.character, 11);
|
||||
assert.equal(range.end.character, 14);
|
||||
|
||||
range = data.getWordRangeAtPosition(new Position(0, 17), /a+.+?c/);
|
||||
range = data.getWordRangeAtPosition(new Position(0, 17), /[a-z+]+/);
|
||||
assert.equal(range.start.line, 0);
|
||||
assert.equal(range.start.character, 15);
|
||||
assert.equal(range.end.line, 0);
|
||||
|
|
|
@ -774,10 +774,6 @@ export class TestWindowService implements IWindowService {
|
|||
return TPromise.as(void 0);
|
||||
}
|
||||
|
||||
toggleMenuBar(): TPromise<void> {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
|
||||
isMaximized(): TPromise<boolean> {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
|
@ -879,9 +875,6 @@ export class TestWindowsService implements IWindowsService {
|
|||
setDocumentEdited(windowId: number, flag: boolean): TPromise<void> {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
toggleMenuBar(windowId: number): TPromise<void> {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
quit(): TPromise<void> {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
|
@ -923,4 +916,4 @@ export class TestWindowsService implements IWindowsService {
|
|||
startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise<void> {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue