From 354956f6382236000f2272da2e4a513d74dabcef Mon Sep 17 00:00:00 2001 From: parkourkarthik Date: Wed, 10 Oct 2018 08:38:30 +0530 Subject: [PATCH 01/88] include uri to open file cmd on clean tree --- extensions/git/src/commands.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 9c838715840..4dbc3784806 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -608,6 +608,9 @@ export class CommandCenter { uris = resources.map(r => r.resourceUri); } + else { + uris = [(window.activeTextEditor && window.activeTextEditor.document.uri)] as Uri[]; + } } if (!uris) { From 4228c786c45ccc4f403fac9e08574d47e67794a1 Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Tue, 15 Jan 2019 19:58:07 -0600 Subject: [PATCH 02/88] git prompts to save only staged files --- extensions/git/src/commands.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index eb45f107f4b..26685a0afa3 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1200,19 +1200,21 @@ export class CommandCenter { const promptToSaveFilesBeforeCommit = config.get('promptToSaveFilesBeforeCommit') === true; if (promptToSaveFilesBeforeCommit) { - const unsavedTextDocuments = workspace.textDocuments - .filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath)); + const stagedUnsavedTextDocuments = workspace.textDocuments + .filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath)) + .filter(d => repository.indexGroup.resourceStates.some(s => + s.resourceUri.path === d.uri.fsPath)); - if (unsavedTextDocuments.length > 0) { - const message = unsavedTextDocuments.length === 1 - ? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(unsavedTextDocuments[0].uri.fsPath)) - : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", unsavedTextDocuments.length); + if (stagedUnsavedTextDocuments.length > 0) { + const message = stagedUnsavedTextDocuments.length === 1 + ? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) + : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", stagedUnsavedTextDocuments.length); const saveAndCommit = localize('save and commit', "Save All & Commit"); const commit = localize('commit', "Commit Anyway"); const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit); if (pick === saveAndCommit) { - await Promise.all(unsavedTextDocuments.map(d => d.save())); + await Promise.all(stagedUnsavedTextDocuments.map(d => d.save())); await repository.status(); } else if (pick !== commit) { return false; // do not commit on cancel From e78b75e9452e026a6bc415911151aa365ce12c10 Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Wed, 16 Jan 2019 00:18:15 -0600 Subject: [PATCH 03/88] update strings for prompt to save staged files --- extensions/git/src/commands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 26685a0afa3..14a3e8b2cf8 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1207,8 +1207,8 @@ export class CommandCenter { if (stagedUnsavedTextDocuments.length > 0) { const message = stagedUnsavedTextDocuments.length === 1 - ? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) - : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", stagedUnsavedTextDocuments.length); + ? localize('unsaved files single', "The following staged file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) + : localize('unsaved files', "There are {0} unsaved staged files.\n\nWould you like to save them before committing?", stagedUnsavedTextDocuments.length); const saveAndCommit = localize('save and commit', "Save All & Commit"); const commit = localize('commit', "Commit Anyway"); const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit); From dce56c504c08ab5e63fda05b793c581fac2a0851 Mon Sep 17 00:00:00 2001 From: Pawel Urbanski Date: Tue, 22 Jan 2019 19:43:58 +0100 Subject: [PATCH 04/88] Assigned an empty string to silence too verbose alerts, which try to handle function, much better handled by the screen readers, and therefore they should be removed. --- src/vs/editor/contrib/suggest/suggestController.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 05e535ac302..9f9f2594ef0 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -292,7 +292,8 @@ export class SuggestController implements IEditorContribution { } private _alertCompletionItem({ completion: suggestion }: CompletionItem): void { - let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' did insert the following text: {1}", suggestion.label, suggestion.insertText); + // @todo Remove alert support. Assigning an empty string temporarly to silence alers. + let msg = null; alert(msg); } From 700de5683e0072561cbc11d175c4f1533df934b3 Mon Sep 17 00:00:00 2001 From: Pawel Urbanski Date: Tue, 22 Jan 2019 21:11:40 +0100 Subject: [PATCH 05/88] Changed verbosity of code completion widget alerts to provide the current completion item without unnecesary snippet/regular hints, or if items have details. --- src/vs/editor/contrib/suggest/suggestWidget.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 347de4b6499..57c53a281bf 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -535,23 +535,25 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { this.onDidSelectEmitter.fire({ item, index, model: completionModel }); - alert(nls.localize('suggestionAriaAccepted', "{0}, accepted", item.completion.label)); this.editor.focus(); }); } private _getSuggestionAriaAlertLabel(item: CompletionItem): string { + // It is not so important to know the type of completion: regular or snippet. + // Snippets can be identified by their names. + // They are usually created by users themselves. const isSnippet = item.completion.kind === CompletionItemKind.Snippet; if (!canExpandCompletionItem(item)) { - return isSnippet ? nls.localize('ariaCurrentSnippetSuggestion', "{0}, snippet suggestion", item.completion.label) - : nls.localize('ariaCurrentSuggestion', "{0}, suggestion", item.completion.label); + return isSnippet ? item.completion.label + : item.completion.label; } else if (this.expandDocsSettingFromStorage()) { - return isSnippet ? nls.localize('ariaCurrentSnippeSuggestionReadDetails', "{0}, snippet suggestion. Reading details. {1}", item.completion.label, this.details.getAriaLabel()) - : nls.localize('ariaCurrenttSuggestionReadDetails', "{0}, suggestion. Reading details. {1}", item.completion.label, this.details.getAriaLabel()); + return isSnippet ? nls.localize('ariaCurrentSnippeSuggestionReadDetails', "{0}: {1}", item.completion.label, this.details.getAriaLabel()) + : nls.localize('ariaCurrenttSuggestionReadDetails', "{0}: {1}", item.completion.label, this.details.getAriaLabel()); } else { - return isSnippet ? nls.localize('ariaCurrentSnippetSuggestionWithDetails', "{0}, snippet suggestion, has details", item.completion.label) - : nls.localize('ariaCurrentSuggestionWithDetails', "{0}, suggestion, has details", item.completion.label); + return isSnippet ? item.completion.label + : item.completion.label; } } From 12c69a6475e5ca4a7d4a8611b0cecbb387391679 Mon Sep 17 00:00:00 2001 From: Pawel Urbanski Date: Fri, 25 Jan 2019 17:11:00 +0100 Subject: [PATCH 06/88] Removed reporting the number of times alerted string appeared, which has no use for a blind user, and causes too much verbosity. --- src/vs/base/browser/ui/aria/aria.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/vs/base/browser/ui/aria/aria.ts b/src/vs/base/browser/ui/aria/aria.ts index 1922450144d..d7dad9cba5c 100644 --- a/src/vs/base/browser/ui/aria/aria.ts +++ b/src/vs/base/browser/ui/aria/aria.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./aria'; -import * as nls from 'vs/nls'; import { isMacintosh } from 'vs/base/common/platform'; import * as dom from 'vs/base/browser/dom'; @@ -48,29 +47,12 @@ export function status(msg: string): void { } } -let repeatedTimes = 0; -let prevText: string | undefined = undefined; function insertMessage(target: HTMLElement, msg: string): void { if (!ariaContainer) { // console.warn('ARIA support needs a container. Call setARIAContainer() first.'); return; } - if (prevText === msg) { - repeatedTimes++; - } - else { - prevText = msg; - repeatedTimes = 0; - } - - - switch (repeatedTimes) { - case 0: break; - case 1: msg = nls.localize('repeated', "{0} (occurred again)", msg); break; - default: msg = nls.localize('repeatedNtimes', "{0} (occurred {1} times)", msg, repeatedTimes); break; - } - dom.clearNode(target); target.textContent = msg; From c3269a3966017a08077d3bbeee50905d416bffdd Mon Sep 17 00:00:00 2001 From: Pawel Urbanski Date: Fri, 25 Jan 2019 17:43:10 +0100 Subject: [PATCH 07/88] Changes to how documentation strings are presented. Includes previous fixes to alerts. --- src/vs/editor/contrib/suggest/suggestWidget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 57c53a281bf..8de80617e8d 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -549,8 +549,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate Date: Mon, 28 Jan 2019 20:08:06 +0100 Subject: [PATCH 08/88] Fixes duplicating screen reader features with alert - needs further code refactoring. --- src/vs/editor/contrib/suggest/suggestController.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 9f9f2594ef0..20f37c560e0 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { alert } from 'vs/base/browser/ui/aria/aria'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -292,9 +291,8 @@ export class SuggestController implements IEditorContribution { } private _alertCompletionItem({ completion: suggestion }: CompletionItem): void { - // @todo Remove alert support. Assigning an empty string temporarly to silence alers. - let msg = null; - alert(msg); + // A temporary fix for too verbose, unnecesary screen reader alerts. + // Todo: Remove calls to this empty method body. } triggerSuggest(onlyFrom?: CompletionItemProvider[]): void { From 552227eb5badb82c7a6d04f6c8eaae80743b96e4 Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Tue, 29 Jan 2019 18:18:00 -0600 Subject: [PATCH 09/88] debugger console recognizes italic ansi code --- src/vs/workbench/parts/debug/browser/debugANSIHandling.ts | 4 +++- src/vs/workbench/parts/debug/browser/media/repl.css | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts b/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts index b373c452689..5fef576530f 100644 --- a/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts +++ b/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts @@ -56,7 +56,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML * Certain ranges that are matched here do not contain real graphics rendition sequences. For * the sake of having a simpler expression, they have been included anyway. */ - if (ansiSequence.match(/^(?:[349][0-7]|10[0-7]|[01]|4|[34]9)(?:;(?:[349][0-7]|10[0-7]|[01]|4|[34]9))*;?m$/)) { + if (ansiSequence.match(/^(?:[349][0-7]|10[0-7]|[013]|4|[34]9)(?:;(?:[349][0-7]|10[0-7]|[01]|4|[34]9))*;?m$/)) { const styleCodes: number[] = ansiSequence.slice(0, -1) // Remove final 'm' character. .split(';') // Separate style codes. @@ -68,6 +68,8 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML styleNames = []; } else if (code === 1) { styleNames.push('code-bold'); + } else if (code === 3) { + styleNames.push('code-italic'); } else if (code === 4) { styleNames.push('code-underline'); } else if ((code >= 30 && code <= 37) || (code >= 90 && code <= 97)) { diff --git a/src/vs/workbench/parts/debug/browser/media/repl.css b/src/vs/workbench/parts/debug/browser/media/repl.css index 9662f5852ee..b79c318a213 100644 --- a/src/vs/workbench/parts/debug/browser/media/repl.css +++ b/src/vs/workbench/parts/debug/browser/media/repl.css @@ -151,6 +151,7 @@ /* ANSI Codes */ .monaco-workbench .repl .repl-tree .output.expression .code-bold { font-weight: bold; } +.monaco-workbench .repl .repl-tree .output.expression .code-italic { font-style: italic; } .monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; } /* Regular and bright color codes are currently treated the same. */ From 351cffa181cd0553c238ac1b02d75a39b9da330a Mon Sep 17 00:00:00 2001 From: Phil <35127144+flurmbo@users.noreply.github.com> Date: Tue, 29 Jan 2019 18:26:57 -0600 Subject: [PATCH 10/88] add '3' to second half of regex --- src/vs/workbench/parts/debug/browser/debugANSIHandling.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts b/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts index 5fef576530f..a177fc39161 100644 --- a/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts +++ b/src/vs/workbench/parts/debug/browser/debugANSIHandling.ts @@ -56,7 +56,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML * Certain ranges that are matched here do not contain real graphics rendition sequences. For * the sake of having a simpler expression, they have been included anyway. */ - if (ansiSequence.match(/^(?:[349][0-7]|10[0-7]|[013]|4|[34]9)(?:;(?:[349][0-7]|10[0-7]|[01]|4|[34]9))*;?m$/)) { + if (ansiSequence.match(/^(?:[349][0-7]|10[0-7]|[013]|4|[34]9)(?:;(?:[349][0-7]|10[0-7]|[013]|4|[34]9))*;?m$/)) { const styleCodes: number[] = ansiSequence.slice(0, -1) // Remove final 'm' character. .split(';') // Separate style codes. From 9960d7babdb11c602f9a77ede2e18fa6d441cddd Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Wed, 6 Feb 2019 16:46:18 -0600 Subject: [PATCH 11/88] Revert "update strings for prompt to save staged files" This reverts commit e78b75e9452e026a6bc415911151aa365ce12c10. --- extensions/git/src/commands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 14a3e8b2cf8..26685a0afa3 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1207,8 +1207,8 @@ export class CommandCenter { if (stagedUnsavedTextDocuments.length > 0) { const message = stagedUnsavedTextDocuments.length === 1 - ? localize('unsaved files single', "The following staged file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) - : localize('unsaved files', "There are {0} unsaved staged files.\n\nWould you like to save them before committing?", stagedUnsavedTextDocuments.length); + ? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) + : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", stagedUnsavedTextDocuments.length); const saveAndCommit = localize('save and commit', "Save All & Commit"); const commit = localize('commit', "Commit Anyway"); const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit); From bec02409988e520eb13d9cfd648245eee32fbb31 Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Wed, 6 Feb 2019 16:46:25 -0600 Subject: [PATCH 12/88] Revert "git prompts to save only staged files" This reverts commit 4228c786c45ccc4f403fac9e08574d47e67794a1. --- extensions/git/src/commands.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 26685a0afa3..eb45f107f4b 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1200,21 +1200,19 @@ export class CommandCenter { const promptToSaveFilesBeforeCommit = config.get('promptToSaveFilesBeforeCommit') === true; if (promptToSaveFilesBeforeCommit) { - const stagedUnsavedTextDocuments = workspace.textDocuments - .filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath)) - .filter(d => repository.indexGroup.resourceStates.some(s => - s.resourceUri.path === d.uri.fsPath)); + const unsavedTextDocuments = workspace.textDocuments + .filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath)); - if (stagedUnsavedTextDocuments.length > 0) { - const message = stagedUnsavedTextDocuments.length === 1 - ? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(stagedUnsavedTextDocuments[0].uri.fsPath)) - : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", stagedUnsavedTextDocuments.length); + if (unsavedTextDocuments.length > 0) { + const message = unsavedTextDocuments.length === 1 + ? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before committing?", path.basename(unsavedTextDocuments[0].uri.fsPath)) + : localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", unsavedTextDocuments.length); const saveAndCommit = localize('save and commit', "Save All & Commit"); const commit = localize('commit', "Commit Anyway"); const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit); if (pick === saveAndCommit) { - await Promise.all(stagedUnsavedTextDocuments.map(d => d.save())); + await Promise.all(unsavedTextDocuments.map(d => d.save())); await repository.status(); } else if (pick !== commit) { return false; // do not commit on cancel From 26d5172258e36a756935e7e20634572343b59d6f Mon Sep 17 00:00:00 2001 From: jeanp413 Date: Mon, 11 Feb 2019 23:46:08 -0500 Subject: [PATCH 13/88] Invalidate _messageTitleDisposable when disposed. Fixes #68287 --- .../contrib/terminal/electron-browser/terminalInstance.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index 0a38e48b7fd..3741120f02a 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -182,7 +182,7 @@ export class TerminalInstance implements ITerminalInstance { private _titleReadyComplete: (title: string) => any; private _disposables: lifecycle.IDisposable[]; - private _messageTitleDisposable: lifecycle.IDisposable; + private _messageTitleDisposable: lifecycle.IDisposable | undefined; private _widgetManager: TerminalWidgetManager; private _linkHandler: TerminalLinkHandler; @@ -1255,6 +1255,7 @@ export class TerminalInstance implements ITerminalInstance { // automatically updates the terminal name if (this._messageTitleDisposable) { lifecycle.dispose(this._messageTitleDisposable); + this._messageTitleDisposable = undefined; } } const didTitleChange = title !== this._title; From 59b8b2eeb9dc9570cef66f2b8f51ecbce0b6d628 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 20 Feb 2019 06:13:03 -0800 Subject: [PATCH 14/88] Fix strict null checks in terminalPanel Part of #60565 --- src/tsconfig.strictNullChecks.json | 1 + .../editor/contrib/find/simpleFindWidget.ts | 3 +-- .../electron-browser/terminalPanel.ts | 20 +++++++++++++------ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index c4d5bc85314..923edcb13bd 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -295,6 +295,7 @@ "./vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler.ts", + "./vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalCommandTracker.ts", diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 9eb65759b17..3148a62b196 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -26,7 +26,7 @@ const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); export abstract class SimpleFindWidget extends Widget { private _findInput: FindInput; - private _domNode?: HTMLElement; + private _domNode: HTMLElement; private _innerDomNode: HTMLElement; private _isVisible: boolean = false; private _focusTracker: dom.IFocusTracker; @@ -182,7 +182,6 @@ export abstract class SimpleFindWidget extends Widget { if (this._domNode && this._domNode.parentElement) { this._domNode.parentElement.removeChild(this._domNode); - this._domNode = undefined; } } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts index bfde146007b..b4e7019e896 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts @@ -165,7 +165,7 @@ export class TerminalPanel extends Panel { return this._contextMenuActions; } - public getActionItem(action: Action): IActionItem { + public getActionItem(action: Action): IActionItem | null { if (action.id === SwitchTerminalAction.ID) { return this._instantiationService.createInstance(SwitchTerminalActionItem, action); } @@ -182,7 +182,7 @@ export class TerminalPanel extends Panel { public focusFindWidget() { const activeInstance = this._terminalService.getActiveInstance(); - if (activeInstance && activeInstance.hasSelection() && (activeInstance.selection.indexOf('\n') === -1)) { + if (activeInstance && activeInstance.hasSelection() && activeInstance.selection!.indexOf('\n') === -1) { this._findWidget.reveal(activeInstance.selection); } else { this._findWidget.reveal(); @@ -195,7 +195,7 @@ export class TerminalPanel extends Panel { public showFindWidget() { const activeInstance = this._terminalService.getActiveInstance(); - if (activeInstance && activeInstance.hasSelection() && (activeInstance.selection.indexOf('\n') === -1)) { + if (activeInstance && activeInstance.hasSelection() && activeInstance.selection!.indexOf('\n') === -1) { this._findWidget.show(activeInstance.selection); } else { this._findWidget.show(); @@ -215,10 +215,16 @@ export class TerminalPanel extends Panel { if (event.which === 2 && platform.isLinux) { // Drop selection and focus terminal on Linux to enable middle button paste when click // occurs on the selection itself. - this._terminalService.getActiveInstance().focus(); + const terminal = this._terminalService.getActiveInstance(); + if (terminal) { + terminal.focus(); + } } else if (event.which === 3) { if (this._terminalService.configHelper.config.rightClickBehavior === 'copyPaste') { const terminal = this._terminalService.getActiveInstance(); + if (!terminal) { + return; + } if (terminal.hasSelection()) { terminal.copySelection(); terminal.clearSelection(); @@ -246,7 +252,7 @@ export class TerminalPanel extends Panel { if (event.which === 1) { const terminal = this._terminalService.getActiveInstance(); - if (terminal.hasSelection()) { + if (terminal && terminal.hasSelection()) { terminal.copySelection(); } } @@ -299,7 +305,9 @@ export class TerminalPanel extends Panel { } const terminal = this._terminalService.getActiveInstance(); - terminal.sendText(terminalEnvironment.preparePathForTerminal(path), false); + if (terminal) { + terminal.sendText(terminalEnvironment.preparePathForTerminal(path), false); + } } })); } From 6da6653f4f8345b23d9bddcdaebeb340b1d0a7f0 Mon Sep 17 00:00:00 2001 From: "mgquan@myseneca.ca" Date: Wed, 20 Feb 2019 15:46:28 -0500 Subject: [PATCH 15/88] fixed 62968 --- src/vs/editor/common/controller/cursorTypeOperations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 032d035e41e..c18d081379d 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -526,7 +526,7 @@ export class TypeOperations { const lineText = model.getLineContent(position.lineNumber); // Do not auto-close ' or " after a word character - if (chIsQuote && position.column > 1) { + if ((chIsQuote && position.column > 1) && autoCloseConfig !== 'always') { const wordSeparators = getMapForWordSeparators(config.wordSeparators); const characterBeforeCode = lineText.charCodeAt(position.column - 2); const characterBeforeType = wordSeparators.get(characterBeforeCode); From afabf659aecd231a64cf057bc74dd33e1893877c Mon Sep 17 00:00:00 2001 From: khaled4vokalz Date: Sat, 23 Feb 2019 09:11:50 +0600 Subject: [PATCH 16/88] Fixed TYPO --- src/vs/editor/contrib/dnd/dnd.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index 3d028223cee..f1adcb78ecf 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -38,7 +38,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { private _dragSelection: Selection; private _dndDecorationIds: string[]; private _mouseDown: boolean; - private _modiferPressed: boolean; + private _modifierPressed: boolean; static TRIGGER_KEY_VALUE = isMacintosh ? KeyCode.Alt : KeyCode.Ctrl; static get(editor: ICodeEditor): DragAndDropController { @@ -56,7 +56,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { this._toUnhook.push(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e))); this._dndDecorationIds = []; this._mouseDown = false; - this._modiferPressed = false; + this._modifierPressed = false; this._dragSelection = null; } @@ -66,7 +66,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { } if (hasTriggerModifier(e)) { - this._modiferPressed = true; + this._modifierPressed = true; } if (this._mouseDown && hasTriggerModifier(e)) { @@ -82,7 +82,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { } if (hasTriggerModifier(e)) { - this._modiferPressed = false; + this._modifierPressed = false; } if (this._mouseDown && e.keyCode === DragAndDropController.TRIGGER_KEY_VALUE) { @@ -156,13 +156,13 @@ export class DragAndDropController implements editorCommon.IEditorContribution { ( ( hasTriggerModifier(mouseEvent.event) || - this._modiferPressed + this._modifierPressed ) && ( this._dragSelection.getEndPosition().equals(newCursorPosition) || this._dragSelection.getStartPosition().equals(newCursorPosition) ) // we allow users to paste content beside the selection )) { this._editor.pushUndoStop(); - this._editor.executeCommand(DragAndDropController.ID, new DragAndDropCommand(this._dragSelection, newCursorPosition, hasTriggerModifier(mouseEvent.event) || this._modiferPressed)); + this._editor.executeCommand(DragAndDropController.ID, new DragAndDropCommand(this._dragSelection, newCursorPosition, hasTriggerModifier(mouseEvent.event) || this._modifierPressed)); this._editor.pushUndoStop(); } } @@ -213,7 +213,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { this._removeDecoration(); this._dragSelection = null; this._mouseDown = false; - this._modiferPressed = false; + this._modifierPressed = false; this._toUnhook = dispose(this._toUnhook); } } From 55cb25ecbdac60695230eba27f0f5d48738dba70 Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Mon, 25 Feb 2019 23:01:52 -0600 Subject: [PATCH 17/88] added tests for debugger itliac ANSI code --- .../test/browser/debugANSIHandling.test.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts index e42257fb540..f439453c3b2 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts @@ -92,6 +92,11 @@ suite('Debug - ANSI Handling', () => { assert(dom.hasClass(child, 'code-bold')); }); + // Italic code + assertSingleSequenceElement('\x1b[3m', (child) => { + assert(dom.hasClass(child, 'code-italic')); + }); + // Underline code assertSingleSequenceElement('\x1b[4m', (child) => { assert(dom.hasClass(child, 'code-underline')); @@ -126,10 +131,11 @@ suite('Debug - ANSI Handling', () => { } // Codes do not interfere - assertSingleSequenceElement('\x1b[1;4;30;31;32;33;34;35;36;37m', (child) => { + assertSingleSequenceElement('\x1b[1;3;4;30;31;32;33;34;35;36;37m', (child) => { assert.equal(10, child.classList.length); assert(dom.hasClass(child, 'code-bold')); + assert(dom.hasClass(child, 'code-italic')); assert(dom.hasClass(child, 'code-underline')); for (let i = 30; i <= 37; i++) { assert(dom.hasClass(child, 'code-foreground-' + i)); @@ -178,14 +184,15 @@ suite('Debug - ANSI Handling', () => { test('Expected multiple sequence operation', () => { // Multiple codes affect the same text - assertSingleSequenceElement('\x1b[1m\x1b[4m\x1b[32m', (child) => { + assertSingleSequenceElement('\x1b[1m\x1b[3m\x1b[4m\x1b[32m', (child) => { assert(dom.hasClass(child, 'code-bold')); + assert(dom.hasClass(child, 'code-italic')); assert(dom.hasClass(child, 'code-underline')); assert(dom.hasClass(child, 'code-foreground-32')); }); // Consecutive codes do not affect previous ones - assertMultipleSequenceElements('\x1b[1mbold\x1b[32mgreen\x1b[4munderline\x1b[0mnothing', [ + assertMultipleSequenceElements('\x1b[1mbold\x1b[32mgreen\x1b[4munderline\x1b[3mitalic\x1b[0mnothing', [ (bold) => { assert.equal(1, bold.classList.length); assert(dom.hasClass(bold, 'code-bold')); @@ -201,6 +208,13 @@ suite('Debug - ANSI Handling', () => { assert(dom.hasClass(underline, 'code-foreground-32')); assert(dom.hasClass(underline, 'code-underline')); }, + (italic) => { + assert.equal(4, italic.classList.length); + assert(dom.hasClass(italic, 'code-bold')); + assert(dom.hasClass(italic, 'code-foreground-32')); + assert(dom.hasClass(italic, 'code-underline')); + assert(dom.hasClass(italic, 'code-italic')); + }, (nothing) => { assert.equal(0, nothing.classList.length); }, From 06095789080e0cd642f08483e9e05a9d46306cfe Mon Sep 17 00:00:00 2001 From: Phil Marshall Date: Mon, 25 Feb 2019 23:41:41 -0600 Subject: [PATCH 18/88] fixed assertion for debugger italic ANSI code test --- .../contrib/debug/test/browser/debugANSIHandling.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts index f439453c3b2..4902d43a463 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts @@ -132,7 +132,7 @@ suite('Debug - ANSI Handling', () => { // Codes do not interfere assertSingleSequenceElement('\x1b[1;3;4;30;31;32;33;34;35;36;37m', (child) => { - assert.equal(10, child.classList.length); + assert.equal(11, child.classList.length); assert(dom.hasClass(child, 'code-bold')); assert(dom.hasClass(child, 'code-italic')); From a0851ca719d423d82776bab621339e31fb5f08d7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Mar 2019 21:08:16 -0800 Subject: [PATCH 19/88] Strict null check textEditorModel Enables strict null checking for `textEditorModel`. I also had to add a few null supressions to difficult errors. --- src/tsconfig.strictNullChecks.json | 10 ++++++ .../common/services/languagesRegistry.ts | 2 +- src/vs/editor/common/services/modeService.ts | 2 +- .../editor/common/services/modeServiceImpl.ts | 4 +-- .../editor/common/services/resolverService.ts | 8 +++-- .../standalone/browser/simpleServices.ts | 6 ++-- .../common/editor/textEditorModel.ts | 10 +++--- .../bulkEdit/browser/bulkEditService.ts | 6 ++-- .../configuration/node/jsonEditingService.ts | 10 +++--- .../textfile/common/textFileEditorModel.ts | 36 +++++++++---------- .../common/textFileEditorModelManager.ts | 10 +++--- .../services/textfile/common/textfiles.ts | 4 +-- 12 files changed, 62 insertions(+), 46 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 315d356b476..ddcdd59c311 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -132,6 +132,10 @@ "./vs/workbench/common/editor/dataUriEditorInput.ts", "./vs/workbench/common/editor/diffEditorModel.ts", "./vs/workbench/common/editor/editorGroup.ts", + "./vs/workbench/common/editor/resourceEditorInput.ts", + "./vs/workbench/common/editor/resourceEditorModel.ts", + "./vs/workbench/common/editor/textDiffEditorModel.ts", + "./vs/workbench/common/editor/textEditorModel.ts", "./vs/workbench/common/memento.ts", "./vs/workbench/common/notifications.ts", "./vs/workbench/common/panel.ts", @@ -205,8 +209,10 @@ "./vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts", "./vs/workbench/contrib/feedback/electron-browser/feedback.ts", "./vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem.ts", + "./vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts", "./vs/workbench/contrib/files/browser/files.ts", "./vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts", + "./vs/workbench/contrib/files/common/editors/fileEditorInput.ts", "./vs/workbench/contrib/files/common/explorerModel.ts", "./vs/workbench/contrib/files/common/explorerService.ts", "./vs/workbench/contrib/files/common/files.ts", @@ -229,6 +235,8 @@ "./vs/workbench/contrib/output/common/outputLinkComputer.ts", "./vs/workbench/contrib/output/common/outputLinkProvider.ts", "./vs/workbench/contrib/output/node/outputAppender.ts", + "./vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts", + "./vs/workbench/contrib/performance/electron-browser/startupProfiler.ts", "./vs/workbench/contrib/performance/electron-browser/startupTimings.ts", "./vs/workbench/contrib/preferences/browser/settingsWidgets.ts", "./vs/workbench/contrib/preferences/common/smartSnippetInserter.ts", @@ -414,6 +422,8 @@ "./vs/workbench/services/textMate/common/textMateService.ts", "./vs/workbench/services/textMate/electron-browser/TMGrammars.ts", "./vs/workbench/services/textMate/electron-browser/textMateService.ts", + "./vs/workbench/services/textfile/common/textFileEditorModel.ts", + "./vs/workbench/services/textfile/common/textFileEditorModelManager.ts", "./vs/workbench/services/textfile/common/textfiles.ts", "./vs/workbench/services/textfile/node/textResourcePropertiesService.ts", "./vs/workbench/services/timer/electron-browser/timerService.ts", diff --git a/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts index e5f39e13df3..5534b442510 100644 --- a/src/vs/editor/common/services/languagesRegistry.ts +++ b/src/vs/editor/common/services/languagesRegistry.ts @@ -270,7 +270,7 @@ export class LanguagesRegistry extends Disposable { return (language.mimetypes[0] || null); } - public extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds: string): string[] { + public extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string[] { if (!commaSeparatedMimetypesOrCommaSeparatedIds) { return []; } diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index bf6a6e51a06..de852f670f7 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -47,7 +47,7 @@ export interface IModeService { getConfigurationFiles(modeId: string): URI[]; // --- instantiation - create(commaSeparatedMimetypesOrCommaSeparatedIds: string): ILanguageSelection; + create(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): ILanguageSelection; createByLanguageName(languageName: string): ILanguageSelection; createByFilepathOrFirstLine(filepath: string | null, firstLine?: string): ILanguageSelection; diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index db3cd258a1f..9b4667220e8 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -104,7 +104,7 @@ export class ModeServiceImpl implements IModeService { return null; } - public getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string | null { + public getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string | null { const modeIds = this._registry.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds); if (modeIds.length > 0) { @@ -124,7 +124,7 @@ export class ModeServiceImpl implements IModeService { // --- instantiation - public create(commaSeparatedMimetypesOrCommaSeparatedIds: string): ILanguageSelection { + public create(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): ILanguageSelection { return new LanguageSelection(this.onLanguagesMaybeChanged, () => { const modeId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds); return this._createModeAndGetLanguageIdentifier(modeId); diff --git a/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts index e000629c298..2b04d4b1218 100644 --- a/src/vs/editor/common/services/resolverService.ts +++ b/src/vs/editor/common/services/resolverService.ts @@ -18,7 +18,7 @@ export interface ITextModelService { * Provided a resource URI, it will return a model reference * which should be disposed once not needed anymore. */ - createModelReference(resource: URI): Promise>; + createModelReference(resource: URI): Promise>; /** * Registers a specific `scheme` content provider. @@ -44,7 +44,11 @@ export interface ITextEditorModel extends IEditorModel { /** * Provides access to the underlying `ITextModel`. */ - readonly textEditorModel: ITextModel; + readonly textEditorModel: ITextModel | null; isReadonly(): boolean; } + +export interface IActiveTextEditorModel extends ITextEditorModel { + readonly textEditorModel: ITextModel; +} diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index ea099deb164..7c6487339f2 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -22,7 +22,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { TextEdit, WorkspaceEdit, isResourceTextEdit } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { ITextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IActiveTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -44,7 +44,7 @@ import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFolde import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -export class SimpleModel implements ITextEditorModel { +export class SimpleModel implements IActiveTextEditorModel { private model: ITextModel; private readonly _onDispose: Emitter; @@ -98,7 +98,7 @@ export class SimpleEditorModelResolverService implements ITextModelService { this.editor = editor; } - public createModelReference(resource: URI): Promise> { + public createModelReference(resource: URI): Promise> { let model: ITextModel | null = withTypedEditor(this.editor, (editor) => this.findModel(editor, resource), (diffEditor) => this.findModel(diffEditor.getOriginalEditor(), resource) || this.findModel(diffEditor.getModifiedEditor(), resource) diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index b300ee95fb5..b8279be7d5c 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -6,7 +6,7 @@ import { ITextModel, ITextBufferFactory } from 'vs/editor/common/model'; import { EditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; -import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; +import { ITextEditorModel, IActiveTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -59,7 +59,7 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd }); } - get textEditorModel(): ITextModel { + get textEditorModel(): ITextModel | null { return this.textEditorModelHandle ? this.modelService.getModel(this.textEditorModelHandle) : null; } @@ -68,7 +68,7 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd /** * Creates the text editor model with the provided value, modeId (can be comma separated for multiple values) and optional resource URL. */ - protected createTextEditorModel(value: ITextBufferFactory, resource?: URI, modeId?: string): EditorModel { + protected createTextEditorModel(value: ITextBufferFactory, resource: URI, modeId?: string): EditorModel { const firstLineText = this.getFirstLineText(value); const languageSelection = this.getOrCreateMode(this.modeService, modeId, firstLineText); @@ -111,7 +111,7 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd * * @param firstLineText optional first line of the text buffer to set the mode on. This can be used to guess a mode from content. */ - protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection { + protected getOrCreateMode(modeService: IModeService, modeId: string | undefined, firstLineText?: string): ILanguageSelection { return modeService.create(modeId); } @@ -135,7 +135,7 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd return null; } - isResolved(): boolean { + isResolved(): this is IActiveTextEditorModel { return !!this.textEditorModelHandle; } diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index 28142311db4..93494c3bbc7 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -13,7 +13,7 @@ import { Range } from 'vs/editor/common/core/range'; import { EndOfLineSequence, IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model'; import { isResourceFileEdit, isResourceTextEdit, ResourceFileEdit, ResourceTextEdit, WorkspaceEdit } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; +import { ITextModelService, IActiveTextEditorModel } from 'vs/editor/common/services/resolverService'; import { localize } from 'vs/nls'; import { IFileService } from 'vs/platform/files/common/files'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -53,7 +53,7 @@ class ModelEditTask implements IDisposable { private _expectedModelVersionId: number | undefined; protected _newEol: EndOfLineSequence; - constructor(private readonly _modelReference: IReference) { + constructor(private readonly _modelReference: IReference) { this._model = this._modelReference.object.textEditorModel; this._edits = []; } @@ -115,7 +115,7 @@ class EditorEditTask extends ModelEditTask { private _editor: ICodeEditor; - constructor(modelReference: IReference, editor: ICodeEditor) { + constructor(modelReference: IReference, editor: ICodeEditor) { super(modelReference); this._editor = editor; } diff --git a/src/vs/workbench/services/configuration/node/jsonEditingService.ts b/src/vs/workbench/services/configuration/node/jsonEditingService.ts index c02b276b524..e12ed97cf59 100644 --- a/src/vs/workbench/services/configuration/node/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/node/jsonEditingService.ts @@ -17,7 +17,7 @@ import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; -import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService'; +import { ITextModelService, IActiveTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IJSONEditingService, IJSONValue, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ITextModel } from 'vs/editor/common/model'; @@ -83,7 +83,7 @@ export class JSONEditingService implements IJSONEditingService { return setProperty(model.getValue(), [key], value, { tabSize, insertSpaces, eol }); } - private async resolveModelReference(resource: URI): Promise> { + private async resolveModelReference(resource: URI): Promise> { const exists = await this.fileService.existsFile(resource); if (!exists) { await this.fileService.updateContent(resource, '{}', { encoding: encoding.UTF8 }); @@ -97,18 +97,18 @@ export class JSONEditingService implements IJSONEditingService { return parseErrors.length > 0; } - private resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { + private resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { return this.resolveModelReference(resource) .then(reference => { const model = reference.object.textEditorModel; if (this.hasParseErrors(model)) { - return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); + return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); } // Target cannot be dirty if not writing into buffer if (checkDirty && this.textFileService.isDirty(resource)) { - return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); + return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); } return reference; }); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index e7f9af79cf3..d492662209f 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -70,7 +70,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private saveSequentializer: SaveSequentializer; private disposed: boolean; private lastSaveAttemptTime: number; - private createTextEditorModelPromise: Promise; + private createTextEditorModelPromise: Promise | null; private inConflictMode: boolean; private inOrphanMode: boolean; private inErrorMode: boolean; @@ -435,7 +435,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.updateSavedVersionId(); } - private doCreateTextModel(resource: URI, value: ITextBufferFactory, backup: URI): Promise { + private doCreateTextModel(resource: URI, value: ITextBufferFactory, backup: URI | undefined): Promise { this.logService.trace('load() - created text editor model', this.resource); this.createTextEditorModelPromise = this.doLoadBackup(backup).then(backupContent => { @@ -443,7 +443,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Create model const hasBackupContent = !!backupContent; - this.createTextEditorModel(hasBackupContent ? backupContent : value, resource); + this.createTextEditorModel(backupContent ? backupContent : value, resource); // We restored a backup so we have to set the model as being dirty // We also want to trigger auto save if it is enabled to simulate the exact same behaviour @@ -480,15 +480,15 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // where `value` was captured in the content change listener closure scope. // Content Change - this._register(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); + this._register(this.textEditorModel!.onDidChangeContent(() => this.onModelContentChanged())); } - private doLoadBackup(backup: URI): Promise { + private doLoadBackup(backup: URI | undefined): Promise { if (!backup) { return Promise.resolve(null); } - return this.backupFileService.resolveBackupContent(backup).then(backupContent => backupContent, error => null /* ignore errors */); + return this.backupFileService.resolveBackupContent(backup).then(backupContent => backupContent || null, error => null /* ignore errors */); } protected getOrCreateMode(modeService: IModeService, preferredModeIds: string | undefined, firstLineText?: string): ILanguageSelection { @@ -511,7 +511,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // In this case we clear the dirty flag and emit a SAVED event to indicate this state. // Note: we currently only do this check when auto-save is turned off because there you see // a dirty indicator that you want to get rid of when undoing to the saved version. - if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel.getAlternativeVersionId() === this.bufferSavedVersionId) { + if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel!.getAlternativeVersionId() === this.bufferSavedVersionId) { this.logService.trace('onModelContentChanged() - model content changed back to last saved version', this.resource); // Clear flags @@ -609,7 +609,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (this.saveSequentializer.hasPendingSave(versionId)) { this.logService.trace(`doSave(${versionId}) - exit - found a pending save for versionId ${versionId}`, this.resource); - return this.saveSequentializer.pendingSave; + return this.saveSequentializer.pendingSave || Promise.resolve(undefined); } // Return early if not dirty (unless forced) or version changed meanwhile @@ -643,7 +643,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Push all edit operations to the undo stack so that the user has a chance to // Ctrl+Z back to the saved version. We only do this when auto-save is turned off if (!this.autoSaveAfterMilliesEnabled) { - this.textEditorModel.pushStackElement(); + this.textEditorModel!.pushStackElement(); } // A save participant can still change the model now and since we are so close to saving @@ -698,7 +698,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Save to Disk // mark the save operation as currently pending with the versionId (it might have changed from a save participant triggering) this.logService.trace(`doSave(${versionId}) - before updateContent()`, this.resource); - return this.saveSequentializer.setPending(newVersionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, this.createSnapshot(), { + return this.saveSequentializer.setPending(newVersionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, this.createSnapshot()!, { overwriteReadonly: options.overwriteReadonly, overwriteEncoding: options.overwriteEncoding, mtime: this.lastResolvedDiskStat.mtime, @@ -807,7 +807,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return ''; } - private getTelemetryData(reason: number): Object { + private getTelemetryData(reason: number | undefined): Object { const ext = extname(this.resource); const fileName = basename(this.resource); const telemetryData = { @@ -834,7 +834,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private doTouch(versionId: number): Promise { - return this.saveSequentializer.setPending(versionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, this.createSnapshot(), { + return this.saveSequentializer.setPending(versionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, this.createSnapshot()!, { mtime: this.lastResolvedDiskStat.mtime, encoding: this.getEncoding(), etag: this.lastResolvedDiskStat.etag @@ -915,7 +915,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } getETag(): string | null { - return this.lastResolvedDiskStat ? this.lastResolvedDiskStat.etag : null; + return this.lastResolvedDiskStat ? this.lastResolvedDiskStat.etag || null : null; } hasState(state: ModelState): boolean { @@ -1100,8 +1100,8 @@ export class SaveSequentializer { // so that we can return a promise that completes when the save operation // has completed. if (!this._nextSave) { - let promiseResolve: (() => void) | undefined; - let promiseReject: ((error: Error) => void) | undefined; + let promiseResolve: () => void; + let promiseReject: (error: Error) => void; const promise = new Promise((resolve, reject) => { promiseResolve = resolve; promiseReject = reject; @@ -1110,8 +1110,8 @@ export class SaveSequentializer { this._nextSave = { run, promise, - promiseResolve: promiseResolve, - promiseReject: promiseReject + promiseResolve: promiseResolve!, + promiseReject: promiseReject! }; } @@ -1120,7 +1120,7 @@ export class SaveSequentializer { this._nextSave.run = run; } - return this._nextSave.promise; + return this._nextSave!.promise; } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index b8f80e3f6b6..f90ff9bc7d6 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -117,7 +117,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE return 250; } - get(resource: URI): ITextFileEditorModel { + get(resource: URI): ITextFileEditorModel | undefined { return this.mapResourceToModel.get(resource); } @@ -158,7 +158,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Install state change listener this.mapResourceToStateChangeListener.set(resource, model.onDidStateChange(state => { - const event = new TextFileModelChangeEvent(model, state); + const event = new TextFileModelChangeEvent(model!, state); switch (state) { case StateChange.DIRTY: this._onModelDirty.fire(event); @@ -183,7 +183,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Install model content change listener this.mapResourceToModelContentChangeListener.set(resource, model.onDidContentChange(e => { - this._onModelContentChanged.fire(new TextFileModelChangeEvent(model, e)); + this._onModelContentChanged.fire(new TextFileModelChangeEvent(model!, e)); })); } @@ -207,7 +207,9 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE }, error => { // Free resources of this invalid model - model.dispose(); + if (model) { + model.dispose(); + } // Remove from pending loads this.mapResourceToPendingModelLoaders.delete(resource); diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 43d88b808ae..a51df6695ac 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -189,7 +189,7 @@ export interface ITextFileEditorModelManager { onModelsSaved: Event; onModelsReverted: Event; - get(resource: URI): ITextFileEditorModel; + get(resource: URI): ITextFileEditorModel | undefined; getAll(resource?: URI): ITextFileEditorModel[]; @@ -240,7 +240,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport updatePreferredEncoding(encoding: string): void; - save(options?: ISaveOptions): Promise; + save(options?: ISaveOptions): Promise | undefined; load(options?: ILoadOptions): Promise; From 02ca5bde963ff890433427da44c630d8379014fb Mon Sep 17 00:00:00 2001 From: Takashi Tamura Date: Sat, 2 Mar 2019 19:09:32 +0900 Subject: [PATCH 20/88] Make an error message easier to understand --- build/gulpfile.hygiene.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 1af30179a06..9ec4d5ef336 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -228,7 +228,7 @@ function hygiene(some) { let formatted = result.dest.replace(/\r\n/gm, '\n'); if (original !== formatted) { - console.error('File not formatted:', file.relative); + console.error('File not formatted with tsfmt:', file.relative); errorCount++; } cb(null, file); From 13a11b3931477a9c84effa4a5d3c6e59e1ab932c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Mar 2019 16:57:29 +0100 Subject: [PATCH 21/88] debt - split more layout things out of workbench --- .../workbench/electron-browser/workbench.ts | 214 +++++++++--------- 1 file changed, 111 insertions(+), 103 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index d3fbc90ed25..067a2e1489f 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -158,10 +158,7 @@ enum Settings { ZEN_MODE_RESTORE = 'zenMode.restore' } -type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto'; -const fontAliasingValues: FontAliasingOption[] = ['antialiased', 'none', 'auto']; - -enum State { +enum Storage { SIDEBAR_HIDDEN = 'workbench.sidebar.hidden', PANEL_HIDDEN = 'workbench.panel.hidden', @@ -213,8 +210,6 @@ export class Workbench extends Disposable implements IPartService { private notificationsCenter: NotificationsCenter; private notificationsToasts: NotificationsToasts; - private fontAliasing: FontAliasingOption; - constructor( private container: HTMLElement, private configuration: IWindowConfiguration, @@ -325,11 +320,12 @@ export class Workbench extends Disposable implements IPartService { // Register Listeners this.registerListeners(); + this.registerLayoutListeners(); - // Settings - this.initState(); + // Layout State + this.initLayoutState(); - // Create Workbench and Parts + // Render Workbench this.renderWorkbench(); // Workbench Layout @@ -571,73 +567,16 @@ export class Workbench extends Disposable implements IPartService { (this.configuration.filesToDiff && this.configuration.filesToDiff.length > 0)); } - //#region event handling - private registerListeners(): void { // Storage this._register(this.storageService.onWillSaveState(e => this.saveState(e))); - // Restore editor if hidden and it changes - this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false))); - this._register(this.editorPart.onDidActivateGroup(() => this.setEditorHidden(false))); - // Configuration changes this._register(this.configurationService.onDidChangeConfiguration(() => this.setFontAliasing())); - this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); - - // Fullscreen changes - this._register(onDidChangeFullscreen(() => this.onFullscreenChanged())); - - // Group changes - this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.state.editor.centered))); - this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.state.editor.centered))); - - // Prevent workbench from scrolling #55456 - this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => this.workbench.scrollTop = 0)); - - // Menubar visibility changes - if ((isWindows || isLinux) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { - this._register(this.titlebarPart.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); - } } - private onMenubarToggled(visible: boolean) { - if (visible !== this.state.menuBar.toggled) { - this.state.menuBar.toggled = visible; - - if (isFullscreen() && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) { - this._onTitleBarVisibilityChange.fire(); - this.layout(); - } - } - } - - private onFullscreenChanged(): void { - - // Apply as CSS class - if (isFullscreen()) { - addClass(this.workbench, 'fullscreen'); - } else { - removeClass(this.workbench, 'fullscreen'); - - if (this.state.zenMode.transitionedToFullScreen && this.state.zenMode.active) { - this.toggleZenMode(); - } - } - - // Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update - if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { - this._onTitleBarVisibilityChange.fire(); - this.layout(); // handle title bar when fullscreen changes - } - } - - //#endregion - private renderWorkbench(): void { - - // Apply sidebar state as CSS class if (this.state.sideBar.hidden) { addClass(this.workbench, 'nosidebar'); } @@ -650,14 +589,13 @@ export class Workbench extends Disposable implements IPartService { addClass(this.workbench, 'nostatusbar'); } - // Apply font aliasing - this.setFontAliasing(); - - // Apply fullscreen state - if (isFullscreen()) { + if (this.state.fullscreen) { addClass(this.workbench, 'fullscreen'); } + // Apply font aliasing + this.setFontAliasing(); + // Create Parts this.createTitlebarPart(); this.createActivityBarPart(); @@ -673,8 +611,9 @@ export class Workbench extends Disposable implements IPartService { this.container.appendChild(this.workbench); } + private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto'; private setFontAliasing() { - const aliasing = this.configurationService.getValue(Settings.FONT_ALIASING); + const aliasing = this.configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>(Settings.FONT_ALIASING); if (this.fontAliasing === aliasing) { return; } @@ -682,6 +621,7 @@ export class Workbench extends Disposable implements IPartService { this.fontAliasing = aliasing; // Remove all + const fontAliasingValues: (typeof aliasing)[] = ['antialiased', 'none', 'auto']; removeClasses(this.workbench, ...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`)); // Add specific @@ -882,19 +822,6 @@ export class Workbench extends Disposable implements IPartService { private saveState(e: IWillSaveStateEvent): void { - // Zen Mode - if (this.state.zenMode.active) { - this.storageService.store(State.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE); - } else { - this.storageService.remove(State.ZEN_MODE_ENABLED, StorageScope.WORKSPACE); - } - - if (e.reason === WillSaveStateReason.SHUTDOWN && this.state.zenMode.active) { - if (!this.configurationService.getValue(Settings.ZEN_MODE_RESTORE)) { - this.toggleZenMode(true); // We will not restore zen mode, need to clear all zen mode state changes - } - } - // Font info saveFontInfo(this.storageService); } @@ -922,7 +849,9 @@ export class Workbench extends Disposable implements IPartService { private editorPartView: View; private statusBarPartView: View; - private state = { + private readonly state = { + fullscreen: false, + menuBar: { visibility: undefined as MenuBarVisibility, toggled: false @@ -969,7 +898,67 @@ export class Workbench extends Disposable implements IPartService { } }; - private onDidUpdateConfiguration(skipLayout?: boolean): void { + private registerLayoutListeners(): void { + + // Storage + this._register(this.storageService.onWillSaveState(e => this.saveLayoutState(e))); + + // Restore editor if hidden and it changes + this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false))); + this._register(this.editorPart.onDidActivateGroup(() => this.setEditorHidden(false))); + + // Configuration changes + this._register(this.configurationService.onDidChangeConfiguration(() => this.doUpdateLayoutConfiguration())); + + // Fullscreen changes + this._register(onDidChangeFullscreen(() => this.onFullscreenChanged())); + + // Group changes + this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.state.editor.centered))); + this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.state.editor.centered))); + + // Prevent workbench from scrolling #55456 + this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => this.workbench.scrollTop = 0)); + + // Menubar visibility changes + if ((isWindows || isLinux) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + this._register(this.titlebarPart.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); + } + } + + private onMenubarToggled(visible: boolean) { + if (visible !== this.state.menuBar.toggled) { + this.state.menuBar.toggled = visible; + + if (this.state.fullscreen && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) { + this._onTitleBarVisibilityChange.fire(); + this.layout(); + } + } + } + + private onFullscreenChanged(): void { + this.state.fullscreen = isFullscreen(); + + // Apply as CSS class + if (this.state.fullscreen) { + addClass(this.workbench, 'fullscreen'); + } else { + removeClass(this.workbench, 'fullscreen'); + + if (this.state.zenMode.transitionedToFullScreen && this.state.zenMode.active) { + this.toggleZenMode(); + } + } + + // Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update + if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + this._onTitleBarVisibilityChange.fire(); + this.layout(); // handle title bar when fullscreen changes + } + } + + private doUpdateLayoutConfiguration(skipLayout?: boolean): void { // Sidebar Position const newSidebarPositionValue = this.configurationService.getValue(Settings.SIDEBAR_POSITION); @@ -1001,7 +990,10 @@ export class Workbench extends Disposable implements IPartService { this.setMenubarVisibility(newMenubarVisibility, !!skipLayout); } - private initState(): void { + private initLayoutState(): void { + + // Fullscreen + this.state.fullscreen = isFullscreen(); // Menubar visibility this.state.menuBar.visibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); @@ -1010,7 +1002,7 @@ export class Workbench extends Disposable implements IPartService { this.state.activityBar.hidden = !this.configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); // Sidebar visibility - this.state.sideBar.hidden = this.storageService.getBoolean(State.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY); + this.state.sideBar.hidden = this.storageService.getBoolean(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY); // Sidebar position this.state.sideBar.position = (this.configurationService.getValue(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT; @@ -1035,13 +1027,13 @@ export class Workbench extends Disposable implements IPartService { } // Editor centered layout - this.state.editor.restoreCentered = this.storageService.getBoolean(State.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false); + this.state.editor.restoreCentered = this.storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false); // Editors to open this.state.editor.editorsToOpen = this.resolveEditorsToOpen(); // Panel visibility - this.state.panel.hidden = this.storageService.getBoolean(State.PANEL_HIDDEN, StorageScope.WORKSPACE, true); + this.state.panel.hidden = this.storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true); // Panel position this.setPanelPositionFromStorageOrConfig(); @@ -1067,7 +1059,7 @@ export class Workbench extends Disposable implements IPartService { this.state.statusBar.hidden = !statusBarVisible; // Zen mode enablement - const wasZenActive = this.storageService.getBoolean(State.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false); + const wasZenActive = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false); this.state.zenMode.restore = wasZenActive && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); } @@ -1154,7 +1146,7 @@ export class Workbench extends Disposable implements IPartService { private setPanelPositionFromStorageOrConfig() { const defaultPanelPosition = this.configurationService.getValue(Settings.PANEL_POSITION); - const panelPosition = this.storageService.get(State.PANEL_POSITION, StorageScope.WORKSPACE, defaultPanelPosition); + const panelPosition = this.storageService.get(Storage.PANEL_POSITION, StorageScope.WORKSPACE, defaultPanelPosition); this.state.panel.position = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM; } @@ -1198,7 +1190,7 @@ export class Workbench extends Disposable implements IPartService { case Parts.TITLEBAR_PART: if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') { return false; - } else if (!isFullscreen()) { + } else if (!this.state.fullscreen) { return true; } else if (isMacintosh) { return false; @@ -1272,7 +1264,7 @@ export class Workbench extends Disposable implements IPartService { hideLineNumbers: boolean; } = this.configurationService.getValue('zenMode'); - toggleFullScreen = !isFullscreen() && config.fullScreen; + toggleFullScreen = !this.state.fullscreen && config.fullScreen; this.state.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen; this.state.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout; this.state.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART); @@ -1319,11 +1311,11 @@ export class Workbench extends Disposable implements IPartService { setLineNumbers(this.configurationService.getValue('editor.lineNumbers')); // Status bar and activity bar visibility come from settings -> update their visibility. - this.onDidUpdateConfiguration(true); + this.doUpdateLayoutConfiguration(true); this.editorGroupService.activeGroup.focus(); - toggleFullScreen = this.state.zenMode.transitionedToFullScreen && isFullscreen(); + toggleFullScreen = this.state.zenMode.transitionedToFullScreen && this.state.fullscreen; } if (!skipLayout) { @@ -1512,7 +1504,7 @@ export class Workbench extends Disposable implements IPartService { } centerEditorLayout(active: boolean, skipLayout?: boolean): void { - this.storageService.store(State.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE); + this.storageService.store(Storage.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE); this.state.editor.centered = active; let smartActive = active; @@ -1617,9 +1609,9 @@ export class Workbench extends Disposable implements IPartService { // Remember in settings const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY; if (hidden !== defaultHidden) { - this.storageService.store(State.SIDEBAR_HIDDEN, hidden ? 'true' : 'false', StorageScope.WORKSPACE); + this.storageService.store(Storage.SIDEBAR_HIDDEN, hidden ? 'true' : 'false', StorageScope.WORKSPACE); } else { - this.storageService.remove(State.SIDEBAR_HIDDEN, StorageScope.WORKSPACE); + this.storageService.remove(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE); } // Layout @@ -1659,9 +1651,9 @@ export class Workbench extends Disposable implements IPartService { // Remember in settings if (!hidden) { - this.storageService.store(State.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE); + this.storageService.store(Storage.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE); } else { - this.storageService.remove(State.PANEL_HIDDEN, StorageScope.WORKSPACE); + this.storageService.remove(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE); } // The editor and panel cannot be hidden at the same time @@ -1779,7 +1771,7 @@ export class Workbench extends Disposable implements IPartService { const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right'; const oldPositionValue = (this.state.panel.position === Position.BOTTOM) ? 'bottom' : 'right'; this.state.panel.position = position; - this.storageService.store(State.PANEL_POSITION, PositionToString(this.state.panel.position).toLowerCase(), StorageScope.WORKSPACE); + this.storageService.store(Storage.PANEL_POSITION, PositionToString(this.state.panel.position).toLowerCase(), StorageScope.WORKSPACE); // Adjust CSS removeClass(this.panelPart.getContainer(), oldPositionValue); @@ -1817,5 +1809,21 @@ export class Workbench extends Disposable implements IPartService { } } + private saveLayoutState(e: IWillSaveStateEvent): void { + + // Zen Mode + if (this.state.zenMode.active) { + this.storageService.store(Storage.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE); + } else { + this.storageService.remove(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE); + } + + if (e.reason === WillSaveStateReason.SHUTDOWN && this.state.zenMode.active) { + if (!this.configurationService.getValue(Settings.ZEN_MODE_RESTORE)) { + this.toggleZenMode(true); // We will not restore zen mode, need to clear all zen mode state changes + } + } + } + //#endregion } From 4b1c338a8f396d27ed21991b269c5f0eac5916bf Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Mon, 4 Mar 2019 17:08:35 +0100 Subject: [PATCH 22/88] improve launch.json schema for serverReady feature --- extensions/debug-server-ready/package.json | 102 ++++++++++++++------- 1 file changed, 69 insertions(+), 33 deletions(-) diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index 7d84a8e27d5..ee66be8012d 100644 --- a/extensions/debug-server-ready/package.json +++ b/extensions/debug-server-ready/package.json @@ -23,41 +23,77 @@ "launch": { "properties": { "serverReadyAction": { - "type": "object", - "markdownDescription": "%debug.server.ready.serverReadyAction.description%", - "default": { - "action": "openExternally" - }, - "properties": { - "pattern": { - "type": "string", - "markdownDescription": "%debug.server.ready.pattern.description%", - "default": "listening on port ([0-9]+)" + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "markdownDescription": "%debug.server.ready.serverReadyAction.description%", + "default": { + "action": "openExternally" + }, + "properties": { + "action": { + "type": "string", + "enum": [ + "openExternally" + ], + "enumDescriptions": [ + "%debug.server.ready.action.openExternally.description%", + "%debug.server.ready.action.debugWithChrome.description%" + ], + "markdownDescription": "%debug.server.ready.action.description%", + "default": "openExternally" + }, + "pattern": { + "type": "string", + "markdownDescription": "%debug.server.ready.pattern.description%", + "default": "listening on port ([0-9]+)" + }, + "uriFormat": { + "type": "string", + "markdownDescription": "%debug.server.ready.uriFormat.description%", + "default": "http://localhost:%s" + } + } }, - "uriFormat": { - "type": "string", - "markdownDescription": "%debug.server.ready.uriFormat.description%", - "default": "http://localhost:%s" - }, - "action": { - "type": "string", - "enum": [ - "openExternally", - "debugWithChrome" - ], - "enumDescriptions": [ - "%debug.server.ready.action.openExternally.description%", - "%debug.server.ready.action.debugWithChrome.description%" - ], - "markdownDescription": "%debug.server.ready.action.description%", - "default": "openExternally" - }, - "webRoot": { - "type": "string", - "markdownDescription": "%debug.server.ready.webRoot.description%", - "default": "${workspaceFolder}" + { + "type": "object", + "additionalProperties": false, + "markdownDescription": "%debug.server.ready.serverReadyAction.description%", + "default": { + "action": "openExternally" + }, + "properties": { + "action": { + "type": "string", + "enum": [ + "debugWithChrome" + ], + "enumDescriptions": [ + "%debug.server.ready.action.openExternally.description%", + "%debug.server.ready.action.debugWithChrome.description%" + ], + "markdownDescription": "%debug.server.ready.action.description%", + "default": "openExternally" + }, + "pattern": { + "type": "string", + "markdownDescription": "%debug.server.ready.pattern.description%", + "default": "listening on port ([0-9]+)" + }, + "uriFormat": { + "type": "string", + "markdownDescription": "%debug.server.ready.uriFormat.description%", + "default": "http://localhost:%s" + }, + "webRoot": { + "type": "string", + "markdownDescription": "%debug.server.ready.webRoot.description%", + "default": "${workspaceFolder}" + } + } } - } + ] } } } From f8d688f0c5b617f848aa877d4ab6fc06b3a0a912 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Mar 2019 17:43:48 +0100 Subject: [PATCH 23/88] :lipstick: IPartService --- .../workbench/electron-browser/workbench.ts | 158 +++++++++--------- .../services/part/common/partService.ts | 7 - 2 files changed, 75 insertions(+), 90 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 067a2e1489f..d293d8e11b0 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -33,7 +33,7 @@ import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickO import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput'; import { getServices } from 'vs/platform/instantiation/common/extensions'; -import { Position, Parts, IPartService, PositionToString, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; +import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage'; import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; @@ -72,7 +72,6 @@ import { EditorService } from 'vs/workbench/services/editor/browser/editorServic import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid'; -import { IEditor } from 'vs/editor/common/editorCommon'; import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { setARIAContainer } from 'vs/base/browser/ui/aria/aria'; @@ -170,6 +169,8 @@ enum Storage { export class Workbench extends Disposable implements IPartService { + //#region workbench + _serviceBrand: any; private readonly _onShutdown = this._register(new Emitter()); @@ -832,6 +833,8 @@ export class Workbench extends Disposable implements IPartService { this.disposed = true; } + //#endregion + //#region IPartService private readonly _onTitleBarVisibilityChange: Emitter = this._register(new Emitter()); @@ -960,36 +963,76 @@ export class Workbench extends Disposable implements IPartService { private doUpdateLayoutConfiguration(skipLayout?: boolean): void { - // Sidebar Position + // Sidebar position const newSidebarPositionValue = this.configurationService.getValue(Settings.SIDEBAR_POSITION); const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT; if (newSidebarPosition !== this.getSideBarPosition()) { this.setSideBarPosition(newSidebarPosition); } - // Panel Position - this.setPanelPositionFromStorageOrConfig(); + // Panel position + this.updatePanelPosition(); if (!this.state.zenMode.active) { - // Statusbar Visibility + // Statusbar visibility const newStatusbarHiddenValue = !this.configurationService.getValue(Settings.STATUSBAR_VISIBLE); if (newStatusbarHiddenValue !== this.state.statusBar.hidden) { this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout); } - // Activitybar Visibility + // Activitybar visibility const newActivityBarHiddenValue = !this.configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); if (newActivityBarHiddenValue !== this.state.activityBar.hidden) { this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout); } } - // Menubar Visibility + // Menubar visibility const newMenubarVisibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); this.setMenubarVisibility(newMenubarVisibility, !!skipLayout); } + private setSideBarPosition(position: Position): void { + const wasHidden = this.state.sideBar.hidden; + + if (this.state.sideBar.hidden) { + this.setSideBarHidden(false, true /* Skip Layout */); + } + + const newPositionValue = (position === Position.LEFT) ? 'left' : 'right'; + const oldPositionValue = (this.state.sideBar.position === Position.LEFT) ? 'left' : 'right'; + this.state.sideBar.position = position; + + // Adjust CSS + removeClass(this.activitybarPart.getContainer(), oldPositionValue); + removeClass(this.sidebarPart.getContainer(), oldPositionValue); + addClass(this.activitybarPart.getContainer(), newPositionValue); + addClass(this.sidebarPart.getContainer(), newPositionValue); + + // Update Styles + this.activitybarPart.updateStyles(); + this.sidebarPart.updateStyles(); + + // Layout + if (this.workbenchGrid instanceof Grid) { + if (!wasHidden) { + this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView); + } + + this.workbenchGrid.removeView(this.sideBarPartView); + this.workbenchGrid.removeView(this.activityBarPartView); + + if (!this.state.panel.hidden && this.state.panel.position === Position.BOTTOM) { + this.workbenchGrid.removeView(this.panelPartView); + } + + this.layout(); + } else { + this.workbenchGrid.layout(); + } + } + private initLayoutState(): void { // Fullscreen @@ -1036,7 +1079,7 @@ export class Workbench extends Disposable implements IPartService { this.state.panel.hidden = this.storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true); // Panel position - this.setPanelPositionFromStorageOrConfig(); + this.updatePanelPosition(); // Panel to restore if (!this.state.panel.hidden) { @@ -1055,12 +1098,10 @@ export class Workbench extends Disposable implements IPartService { } // Statusbar visibility - const statusBarVisible = this.configurationService.getValue(Settings.STATUSBAR_VISIBLE); - this.state.statusBar.hidden = !statusBarVisible; + this.state.statusBar.hidden = !this.configurationService.getValue(Settings.STATUSBAR_VISIBLE); // Zen mode enablement - const wasZenActive = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false); - this.state.zenMode.restore = wasZenActive && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); + this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); } private resolveEditorsToOpen(): Promise | IResourceEditor[] { @@ -1087,7 +1128,7 @@ export class Workbench extends Disposable implements IPartService { } // Empty workbench - else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) { + else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') { const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0; if (!isEmpty) { return []; // do not open any empty untitled file if we restored editors from previous session @@ -1130,21 +1171,7 @@ export class Workbench extends Disposable implements IPartService { }); } - private openUntitledFile(): boolean { - const startupEditor = this.configurationService.inspect('workbench.startupEditor'); - - // Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined - if (!startupEditor.user && !startupEditor.workspace) { - const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled'); - if (typeof welcomeEnabledValue === 'boolean') { - return !welcomeEnabledValue; - } - } - - return startupEditor.value === 'newUntitledFile'; - } - - private setPanelPositionFromStorageOrConfig() { + private updatePanelPosition() { const defaultPanelPosition = this.configurationService.getValue(Settings.PANEL_POSITION); const panelPosition = this.storageService.get(Storage.PANEL_POSITION, StorageScope.WORKSPACE, defaultPanelPosition); @@ -1241,17 +1268,11 @@ export class Workbench extends Disposable implements IPartService { this.state.zenMode.active = !this.state.zenMode.active; this.state.zenMode.transitionDisposeables = dispose(this.state.zenMode.transitionDisposeables); + const setLineNumbers = (lineNumbers: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => editor.updateOptions({ lineNumbers })); + // Check if zen mode transitioned to full screen and if now we are out of zen mode // -> we need to go out of full screen (same goes for the centered editor layout) let toggleFullScreen = false; - const setLineNumbers = (lineNumbers: any) => { - this.editorService.visibleControls.forEach(editor => { - const control = editor.getControl(); - if (control) { - control.updateOptions({ lineNumbers }); - } - }); - }; // Zen Mode Active if (this.state.zenMode.active) { @@ -1265,6 +1286,7 @@ export class Workbench extends Disposable implements IPartService { } = this.configurationService.getValue('zenMode'); toggleFullScreen = !this.state.fullscreen && config.fullScreen; + this.state.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen; this.state.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout; this.state.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART); @@ -1499,14 +1521,19 @@ export class Workbench extends Disposable implements IPartService { } } + private getPanelDimension(position: Position): number | undefined { + return position === Position.BOTTOM ? this.state.panel.height : this.state.panel.width; + } + isEditorLayoutCentered(): boolean { return this.state.editor.centered; } centerEditorLayout(active: boolean, skipLayout?: boolean): void { - this.storageService.store(Storage.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE); this.state.editor.centered = active; + this.storageService.store(Storage.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE); + let smartActive = active; if (this.editorPart.groups.length > 1 && this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')) { smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group. @@ -1695,46 +1722,6 @@ export class Workbench extends Disposable implements IPartService { return this.state.sideBar.position; } - private setSideBarPosition(position: Position): void { - const wasHidden = this.state.sideBar.hidden; - - if (this.state.sideBar.hidden) { - this.setSideBarHidden(false, true /* Skip Layout */); - } - - const newPositionValue = (position === Position.LEFT) ? 'left' : 'right'; - const oldPositionValue = (this.state.sideBar.position === Position.LEFT) ? 'left' : 'right'; - this.state.sideBar.position = position; - - // Adjust CSS - removeClass(this.activitybarPart.getContainer(), oldPositionValue); - removeClass(this.sidebarPart.getContainer(), oldPositionValue); - addClass(this.activitybarPart.getContainer(), newPositionValue); - addClass(this.sidebarPart.getContainer(), newPositionValue); - - // Update Styles - this.activitybarPart.updateStyles(); - this.sidebarPart.updateStyles(); - - // Layout - if (this.workbenchGrid instanceof Grid) { - if (!wasHidden) { - this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView); - } - - this.workbenchGrid.removeView(this.sideBarPartView); - this.workbenchGrid.removeView(this.activityBarPartView); - - if (!this.state.panel.hidden && this.state.panel.position === Position.BOTTOM) { - this.workbenchGrid.removeView(this.panelPartView); - } - - this.layout(); - } else { - this.workbenchGrid.layout(); - } - } - setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void { if (this.state.menuBar.visibility !== visibility) { this.state.menuBar.visibility = visibility; @@ -1771,7 +1758,16 @@ export class Workbench extends Disposable implements IPartService { const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right'; const oldPositionValue = (this.state.panel.position === Position.BOTTOM) ? 'bottom' : 'right'; this.state.panel.position = position; - this.storageService.store(Storage.PANEL_POSITION, PositionToString(this.state.panel.position).toLowerCase(), StorageScope.WORKSPACE); + + function positionToString(position: Position): string { + switch (position) { + case Position.LEFT: return 'left'; + case Position.RIGHT: return 'right'; + case Position.BOTTOM: return 'bottom'; + } + } + + this.storageService.store(Storage.PANEL_POSITION, positionToString(this.state.panel.position), StorageScope.WORKSPACE); // Adjust CSS removeClass(this.panelPart.getContainer(), oldPositionValue); @@ -1793,10 +1789,6 @@ export class Workbench extends Disposable implements IPartService { } } - private getPanelDimension(position: Position): number | undefined { - return position === Position.BOTTOM ? this.state.panel.height : this.state.panel.width; - } - private savePanelDimension(): void { if (!(this.workbenchGrid instanceof Grid)) { return; diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index 269ce816af3..6ccd362ba74 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -21,13 +21,6 @@ export const enum Position { RIGHT, BOTTOM } -export function PositionToString(position: Position): string { - switch (position) { - case Position.LEFT: return 'LEFT'; - case Position.RIGHT: return 'RIGHT'; - case Position.BOTTOM: return 'BOTTOM'; - } -} export interface ILayoutOptions { toggleMaximizedPanel?: boolean; From 6c5aadb0c2cd7d8bf182a3888b8f00d2a56a967b Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 4 Mar 2019 09:01:18 -0800 Subject: [PATCH 24/88] Re#69258. Another typo. --- src/vs/editor/contrib/dnd/dnd.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index 6016641bcf5..a716d8fa10d 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -64,7 +64,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { this._removeDecoration(); this._dragSelection = null; this._mouseDown = false; - this._modiferPressed = false; + this._modifierPressed = false; } private onEditorKeyDown(e: IKeyboardEvent): void { From 02a6339139d7c0b113cc510cc589aa2ae3bb9127 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 4 Mar 2019 11:35:53 -0800 Subject: [PATCH 25/88] Remove most null supressions --- .../textfile/common/textFileEditorModel.ts | 24 +++++++++++++------ .../common/textFileEditorModelManager.ts | 6 ++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index d492662209f..64f2a50b4dc 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -480,7 +480,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // where `value` was captured in the content change listener closure scope. // Content Change - this._register(this.textEditorModel!.onDidChangeContent(() => this.onModelContentChanged())); + if (this.textEditorModel) { + this._register(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); + } } private doLoadBackup(backup: URI | undefined): Promise { @@ -511,7 +513,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // In this case we clear the dirty flag and emit a SAVED event to indicate this state. // Note: we currently only do this check when auto-save is turned off because there you see // a dirty indicator that you want to get rid of when undoing to the saved version. - if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel!.getAlternativeVersionId() === this.bufferSavedVersionId) { + if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel && this.textEditorModel.getAlternativeVersionId() === this.bufferSavedVersionId) { this.logService.trace('onModelContentChanged() - model content changed back to last saved version', this.resource); // Clear flags @@ -642,8 +644,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Push all edit operations to the undo stack so that the user has a chance to // Ctrl+Z back to the saved version. We only do this when auto-save is turned off - if (!this.autoSaveAfterMilliesEnabled) { - this.textEditorModel!.pushStackElement(); + if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel) { + this.textEditorModel.pushStackElement(); } // A save participant can still change the model now and since we are so close to saving @@ -698,7 +700,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Save to Disk // mark the save operation as currently pending with the versionId (it might have changed from a save participant triggering) this.logService.trace(`doSave(${versionId}) - before updateContent()`, this.resource); - return this.saveSequentializer.setPending(newVersionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, this.createSnapshot()!, { + const snapshot = this.createSnapshot(); + if (!snapshot) { + throw new Error('Invalid snapshot'); + } + return this.saveSequentializer.setPending(newVersionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, snapshot, { overwriteReadonly: options.overwriteReadonly, overwriteEncoding: options.overwriteEncoding, mtime: this.lastResolvedDiskStat.mtime, @@ -834,7 +840,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private doTouch(versionId: number): Promise { - return this.saveSequentializer.setPending(versionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, this.createSnapshot()!, { + const snapshot = this.createSnapshot(); + if (!snapshot) { + throw new Error('invalid snapshot'); + } + return this.saveSequentializer.setPending(versionId, this.fileService.updateContent(this.lastResolvedDiskStat.resource, snapshot, { mtime: this.lastResolvedDiskStat.mtime, encoding: this.getEncoding(), etag: this.lastResolvedDiskStat.etag @@ -1120,7 +1130,7 @@ export class SaveSequentializer { this._nextSave.run = run; } - return this._nextSave!.promise; + return this._nextSave.promise; } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index f90ff9bc7d6..33dc731d7bb 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -153,12 +153,12 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Model does not exist else { - model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined); + const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined); modelPromise = model.load(options); // Install state change listener this.mapResourceToStateChangeListener.set(resource, model.onDidStateChange(state => { - const event = new TextFileModelChangeEvent(model!, state); + const event = new TextFileModelChangeEvent(newModel, state); switch (state) { case StateChange.DIRTY: this._onModelDirty.fire(event); @@ -183,7 +183,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Install model content change listener this.mapResourceToModelContentChangeListener.set(resource, model.onDidContentChange(e => { - this._onModelContentChanged.fire(new TextFileModelChangeEvent(model!, e)); + this._onModelContentChanged.fire(new TextFileModelChangeEvent(newModel, e)); })); } From 53ac75cd9a1f49927c314ef82c01ca6fcc53bbdf Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 12:43:50 -0800 Subject: [PATCH 26/88] Also dispose windows shell helper --- .../contrib/terminal/electron-browser/terminalInstance.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index 709bdfe60bb..b45de738612 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -1254,8 +1254,8 @@ export class TerminalInstance implements ITerminalInstance { // If the title has not been set by the API or the rename command, unregister the handler that // automatically updates the terminal name if (this._messageTitleDisposable) { - lifecycle.dispose(this._messageTitleDisposable); - this._messageTitleDisposable = undefined; + this._messageTitleDisposable = lifecycle.dispose(this._messageTitleDisposable); + this._windowsShellHelper = lifecycle.dispose(this._windowsShellHelper); } } const didTitleChange = title !== this._title; From b8a184d998c1d35a260ed1475013988cc9f624ce Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 12:45:05 -0800 Subject: [PATCH 27/88] Mark windows shell helper as | undefined --- .../contrib/terminal/electron-browser/terminalInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index b45de738612..e1ac2cc4a16 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -175,7 +175,7 @@ export class TerminalInstance implements ITerminalInstance { private _cols: number; private _rows: number; private _dimensionsOverride: ITerminalDimensions; - private _windowsShellHelper: WindowsShellHelper; + private _windowsShellHelper: WindowsShellHelper | undefined; private _xtermReadyPromise: Promise; private _titleReadyPromise: Promise; private _titleReadyComplete: (title: string) => any; From fc860b8c0af4af57df6692d7775d81dd4b2fc698 Mon Sep 17 00:00:00 2001 From: Krish De Souza Date: Sun, 3 Mar 2019 02:19:37 +0000 Subject: [PATCH 28/88] Fix for bug 69583 to use a mechanism that is more Linux compatible to get the value of the cwd for the integrated terminal --- .../contrib/terminal/node/terminalProcess.ts | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index fdadec7eda5..3fdb6a7683d 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -7,6 +7,7 @@ import * as os from 'os'; import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; import * as pty from 'node-pty'; +import * as fs from 'fs'; import { Event, Emitter } from 'vs/base/common/event'; import { ITerminalChildProcess } from 'vs/workbench/contrib/terminal/node/terminal'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -196,18 +197,28 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { } public getCwd(): Promise { - if (platform.isWindows) { + if (platform.isMacintosh) { return new Promise(resolve => { - resolve(this._initialCwd); + exec('lsof -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => { + if (stdout !== '') { + resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1)); + } + }); + }); + } + + if (platform.isLinux) { + return new Promise(resolve => { + fs.readlink('/proc/' + this._ptyProcess.pid + '/cwd', (err, linkedstr) => { + if (linkedstr) { + resolve(linkedstr); + } + }); }); } return new Promise(resolve => { - exec('lsof -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => { - if (stdout !== '') { - resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1)); - } - }); + resolve(this._initialCwd); }); } } From 1eb7e38b6d06e3ed61c443f3362800e939332aaf Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 15:33:48 -0800 Subject: [PATCH 29/88] Correctly set disposables to undefined --- .../terminal/electron-browser/terminalInstance.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index e1ac2cc4a16..f3764101c3a 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -717,7 +717,8 @@ export class TerminalInstance implements ITerminalInstance { public dispose(immediate?: boolean): void { this._logService.trace(`terminalInstance#dispose (id: ${this.id})`); - this._windowsShellHelper = lifecycle.dispose(this._windowsShellHelper); + lifecycle.dispose(this._windowsShellHelper); + this._windowsShellHelper = undefined; this._linkHandler = lifecycle.dispose(this._linkHandler); this._commandTracker = lifecycle.dispose(this._commandTracker); this._widgetManager = lifecycle.dispose(this._widgetManager); @@ -1254,8 +1255,10 @@ export class TerminalInstance implements ITerminalInstance { // If the title has not been set by the API or the rename command, unregister the handler that // automatically updates the terminal name if (this._messageTitleDisposable) { - this._messageTitleDisposable = lifecycle.dispose(this._messageTitleDisposable); - this._windowsShellHelper = lifecycle.dispose(this._windowsShellHelper); + lifecycle.dispose(this._messageTitleDisposable); + lifecycle.dispose(this._windowsShellHelper); + this._messageTitleDisposable = undefined; + this._windowsShellHelper = undefined; } } const didTitleChange = title !== this._title; From da85a2c302021a5d741381426c6603cff355e71a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 15:41:40 -0800 Subject: [PATCH 30/88] Handle error in getCwd for Linux --- src/vs/workbench/contrib/terminal/node/terminalProcess.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index 3fdb6a7683d..fbebae679ee 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -210,9 +210,10 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { if (platform.isLinux) { return new Promise(resolve => { fs.readlink('/proc/' + this._ptyProcess.pid + '/cwd', (err, linkedstr) => { - if (linkedstr) { - resolve(linkedstr); + if (err) { + resolve(this._initialCwd); } + resolve(linkedstr); }); }); } From 0e5614f00287597620702a570441ec8da3613d99 Mon Sep 17 00:00:00 2001 From: Takashi Tamura Date: Tue, 5 Mar 2019 08:44:13 +0900 Subject: [PATCH 31/88] change the message to clarify the intention. --- build/gulpfile.hygiene.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 9ec4d5ef336..187968a95bc 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -228,7 +228,7 @@ function hygiene(some) { let formatted = result.dest.replace(/\r\n/gm, '\n'); if (original !== formatted) { - console.error('File not formatted with tsfmt:', file.relative); + console.error("File not formatted. Run the 'Format Document' command to fix it:", file.relative); errorCount++; } cb(null, file); From d93221d7d5bf30b3161a230909c3c85191139574 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 16:07:52 -0800 Subject: [PATCH 32/88] Strict null check contrib/terminal Fixes #69686 --- .../contrib/terminal/common/terminal.ts | 2 +- .../terminal/common/terminalService.ts | 2 +- .../electron-browser/terminalService.ts | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index d36b3cbeae3..5673030976d 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -251,7 +251,7 @@ export interface ITerminalService { findPrevious(): void; setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; - selectDefaultWindowsShell(): Promise; + selectDefaultWindowsShell(): Promise; setWorkspaceShellAllowed(isAllowed: boolean): void; requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void; diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 2af5a375481..ab539243fc7 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -92,7 +92,7 @@ export abstract class TerminalService implements ITerminalService { public abstract createTerminalRenderer(name: string): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance; - public abstract selectDefaultWindowsShell(): Promise; + public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; public abstract requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index fbace8ec6fb..fcbd99a09b3 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -64,7 +64,10 @@ export class TerminalService extends AbstractTerminalService implements ITermina if (request.termProgram === 'vscode' && request.filesToWait) { pfs.whenDeleted(request.filesToWait.waitMarkerFilePath).then(() => { if (this.terminalInstances.length > 0) { - this.getActiveInstance().focus(); + const terminal = this.getActiveInstance(); + if (terminal) { + terminal.focus(); + } } }); } @@ -215,14 +218,14 @@ export class TerminalService extends AbstractTerminalService implements ITermina ); } - public selectDefaultWindowsShell(): Promise { + public selectDefaultWindowsShell(): Promise { return this._detectWindowsShells().then(shells => { const options: IPickOptions = { placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings") }; return this._quickInputService.pick(shells, options).then(value => { if (!value) { - return null; + return undefined; } const shell = value.description; return this._configurationService.updateValue('terminal.integrated.shell.windows', shell, ConfigurationTarget.USER).then(() => shell); @@ -270,13 +273,13 @@ export class TerminalService extends AbstractTerminalService implements ITermina }); } - private _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string]> { + private _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { + if (potentialPaths.length === 0) { + return Promise.resolve(null); + } const current = potentialPaths.shift(); - return pfs.fileExists(current).then(exists => { + return pfs.fileExists(current!).then(exists => { if (!exists) { - if (potentialPaths.length === 0) { - return null; - } return this._validateShellPaths(label, potentialPaths); } return [label, current] as [string, string]; From 08f1e188f6e66c8b6f97640069e600bf83e9b708 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 16:29:20 -0800 Subject: [PATCH 33/88] Rename contrib/execution to externalTerminal Part of #69107 --- build/gulpfile.vscode.js | 2 +- build/lib/i18n.resources.json | 4 +- src/tsconfig.strictNullChecks.json | 2 +- .../debug/electron-browser/terminalSupport.ts | 6 +-- .../workbench/contrib/debug/node/terminals.ts | 2 +- .../common/externalTerminal.ts} | 15 +++++++- .../electron-browser/TerminalHelper.scpt | Bin .../externalTerminal.contribution.ts} | 18 ++++----- .../electron-browser/externalTerminal.ts} | 11 ------ .../externalTerminalService.ts} | 36 +++++++++--------- .../electron-browser/iTermHelper.scpt | Bin .../externalTerminalService.test.ts} | 22 +++++------ src/vs/workbench/workbench.main.ts | 2 +- 13 files changed, 60 insertions(+), 60 deletions(-) rename src/vs/workbench/contrib/{execution/common/execution.ts => externalTerminal/common/externalTerminal.ts} (65%) rename src/vs/workbench/contrib/{execution => externalTerminal}/electron-browser/TerminalHelper.scpt (100%) rename src/vs/workbench/contrib/{execution/electron-browser/execution.contribution.ts => externalTerminal/electron-browser/externalTerminal.contribution.ts} (87%) rename src/vs/workbench/contrib/{execution/electron-browser/terminal.ts => externalTerminal/electron-browser/externalTerminal.ts} (90%) rename src/vs/workbench/contrib/{execution/electron-browser/terminalService.ts => externalTerminal/electron-browser/externalTerminalService.ts} (82%) rename src/vs/workbench/contrib/{execution => externalTerminal}/electron-browser/iTermHelper.scpt (100%) rename src/vs/workbench/contrib/{execution/test/electron-browser/terminalService.test.ts => externalTerminal/test/electron-browser/externalTerminalService.test.ts} (86%) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 1770b2c149d..9c2231119e9 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -69,7 +69,7 @@ const vscodeResources = [ 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/contrib/debug/**/*.json', - 'out-build/vs/workbench/contrib/execution/**/*.scpt', + 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', 'out-build/vs/workbench/contrib/webview/electron-browser/webview-pre.js', 'out-build/vs/**/markdown.css', 'out-build/vs/workbench/contrib/tasks/**/*.json', diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index dc49b431f87..424fd364c57 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -55,11 +55,11 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/execution", + "name": "vs/workbench/contrib/extensions", "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/extensions", + "name": "vs/workbench/contrib/externalTerminal", "project": "vscode-workbench" }, { diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 7802f41674b..cc45a82aa66 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -14,7 +14,7 @@ "./vs/workbench/browser/parts/quickinput/**/*", "./vs/workbench/electron-browser/actions/**/*", "./vs/workbench/contrib/emmet/**/*", - "./vs/workbench/contrib/execution/**/*", + "./vs/workbench/contrib/externalTerminal/**/*", "./vs/workbench/contrib/snippets/**/*.ts", "./vs/workbench/contrib/welcome/**/*.ts", "./vs/workbench/contrib/issue/**/*", diff --git a/src/vs/workbench/contrib/debug/electron-browser/terminalSupport.ts b/src/vs/workbench/contrib/debug/electron-browser/terminalSupport.ts index 43be1917204..e91e056226a 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/terminalSupport.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/terminalSupport.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/common/terminal'; -import { ITerminalService as IExternalTerminalService } from 'vs/workbench/contrib/execution/common/execution'; +import { IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; import { ITerminalLauncher, ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; import { hasChildProcesses, prepareCommand } from 'vs/workbench/contrib/debug/node/terminals'; @@ -17,14 +17,14 @@ export class TerminalLauncher implements ITerminalLauncher { constructor( @ITerminalService private readonly terminalService: ITerminalService, - @IExternalTerminalService private readonly nativeTerminalService: IExternalTerminalService + @IExternalTerminalService private readonly externalTerminalService: IExternalTerminalService ) { } runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { if (args.kind === 'external') { - return this.nativeTerminalService.runInTerminal(args.title, args.cwd, args.args, args.env || {}); + return this.externalTerminalService.runInTerminal(args.title, args.cwd, args.args, args.env || {}); } if (!this.terminalDisposedListener) { diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index d91a788c908..f399b6bb8d9 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -129,7 +129,7 @@ class MacTerminalService extends TerminalLauncher { // and then launches the program inside that window. const script = terminalApp === MacTerminalService.DEFAULT_TERMINAL_OSX ? 'TerminalHelper' : 'iTermHelper'; - const scriptpath = getPathFromAmdModule(require, `vs/workbench/contrib/execution/electron-browser/${script}.scpt`); + const scriptpath = getPathFromAmdModule(require, `vs/workbench/contrib/externalTerminal/electron-browser/${script}.scpt`); const osaArgs = [ scriptpath, diff --git a/src/vs/workbench/contrib/execution/common/execution.ts b/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts similarity index 65% rename from src/vs/workbench/contrib/execution/common/execution.ts rename to src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts index 4be8a75555e..8b7f051b339 100644 --- a/src/vs/workbench/contrib/execution/common/execution.ts +++ b/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts @@ -6,10 +6,21 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment } from 'vs/base/common/platform'; -export const ITerminalService = createDecorator('nativeTerminalService'); +export const IExternalTerminalService = createDecorator('nativeTerminalService'); -export interface ITerminalService { +export interface IExternalTerminalService { _serviceBrand: any; openTerminal(path: string): void; runInTerminal(title: string, cwd: string, args: string[], env: IProcessEnvironment): Promise; +} + +export interface IExternalTerminalConfiguration { + terminal: { + explorerKind: 'integrated' | 'external', + external: { + linuxExec: string, + osxExec: string, + windowsExec: string + } + }; } \ No newline at end of file diff --git a/src/vs/workbench/contrib/execution/electron-browser/TerminalHelper.scpt b/src/vs/workbench/contrib/externalTerminal/electron-browser/TerminalHelper.scpt similarity index 100% rename from src/vs/workbench/contrib/execution/electron-browser/TerminalHelper.scpt rename to src/vs/workbench/contrib/externalTerminal/electron-browser/TerminalHelper.scpt diff --git a/src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution.ts similarity index 87% rename from src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts rename to src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution.ts index b7993790f8c..d72561ce0a0 100644 --- a/src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution.ts @@ -10,13 +10,13 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import * as paths from 'vs/base/common/path'; import { URI as uri } from 'vs/base/common/uri'; -import { ITerminalService } from 'vs/workbench/contrib/execution/common/execution'; +import { IExternalTerminalConfiguration, IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { ITerminalService as IIntegratedTerminalService, KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; -import { getDefaultTerminalWindows, getDefaultTerminalLinuxReady, DEFAULT_TERMINAL_OSX, ITerminalConfiguration } from 'vs/workbench/contrib/execution/electron-browser/terminal'; -import { WinTerminalService, MacTerminalService, LinuxTerminalService } from 'vs/workbench/contrib/execution/electron-browser/terminalService'; +import { getDefaultTerminalWindows, getDefaultTerminalLinuxReady, DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal'; +import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminalService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -29,11 +29,11 @@ import { distinct } from 'vs/base/common/arrays'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; if (env.isWindows) { - registerSingleton(ITerminalService, WinTerminalService, true); + registerSingleton(IExternalTerminalService, WindowsExternalTerminalService, true); } else if (env.isMacintosh) { - registerSingleton(ITerminalService, MacTerminalService, true); + registerSingleton(IExternalTerminalService, MacExternalTerminalService, true); } else if (env.isLinux) { - registerSingleton(ITerminalService, LinuxTerminalService, true); + registerSingleton(IExternalTerminalService, LinuxExternalTerminalService, true); } getDefaultTerminalLinuxReady().then(defaultTerminalLinux => { @@ -87,13 +87,13 @@ CommandsRegistry.registerCommand({ const editorService = accessor.get(IEditorService); const fileService = accessor.get(IFileService); const integratedTerminalService = accessor.get(IIntegratedTerminalService); - const terminalService = accessor.get(ITerminalService); + const terminalService = accessor.get(IExternalTerminalService); const resources = getMultiSelectedResources(resource, accessor.get(IListService), editorService); return fileService.resolveFiles(resources.map(r => ({ resource: r }))).then(stats => { const directoriesToOpen = distinct(stats.map(({ stat }) => stat.isDirectory ? stat.resource.fsPath : paths.dirname(stat.resource.fsPath))); return directoriesToOpen.map(dir => { - if (configurationService.getValue().terminal.explorerKind === 'integrated') { + if (configurationService.getValue().terminal.explorerKind === 'integrated') { const instance = integratedTerminalService.createTerminal({ cwd: dir }, true); if (instance && (resources.length === 1 || !resource || dir === resource.fsPath || dir === paths.dirname(resource.fsPath))) { integratedTerminalService.setActiveInstance(instance); @@ -115,7 +115,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ weight: KeybindingWeight.WorkbenchContrib, handler: (accessor) => { const historyService = accessor.get(IHistoryService); - const terminalService = accessor.get(ITerminalService); + const terminalService = accessor.get(IExternalTerminalService); const root = historyService.getLastActiveWorkspaceRoot(Schemas.file); if (root) { terminalService.openTerminal(root.fsPath); diff --git a/src/vs/workbench/contrib/execution/electron-browser/terminal.ts b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.ts similarity index 90% rename from src/vs/workbench/contrib/execution/electron-browser/terminal.ts rename to src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.ts index 64ca19ecb76..ccbfeed874f 100644 --- a/src/vs/workbench/contrib/execution/electron-browser/terminal.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.ts @@ -45,14 +45,3 @@ export function getDefaultTerminalWindows(): string { } return _DEFAULT_TERMINAL_WINDOWS; } - -export interface ITerminalConfiguration { - terminal: { - explorerKind: 'integrated' | 'external', - external: { - linuxExec: string, - osxExec: string, - windowsExec: string - } - }; -} diff --git a/src/vs/workbench/contrib/execution/electron-browser/terminalService.ts b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminalService.ts similarity index 82% rename from src/vs/workbench/contrib/execution/electron-browser/terminalService.ts rename to src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminalService.ts index 0462e10ec86..e463d6893ce 100644 --- a/src/vs/workbench/contrib/execution/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminalService.ts @@ -8,9 +8,9 @@ import * as path from 'vs/base/common/path'; import * as processes from 'vs/base/node/processes'; import * as nls from 'vs/nls'; import { assign } from 'vs/base/common/objects'; -import { ITerminalService } from 'vs/workbench/contrib/execution/common/execution'; +import { IExternalTerminalService, IExternalTerminalConfiguration } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ITerminalConfiguration, getDefaultTerminalWindows, getDefaultTerminalLinuxReady, DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/execution/electron-browser/terminal'; +import { getDefaultTerminalWindows, getDefaultTerminalLinuxReady, DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { getPathFromAmdModule } from 'vs/base/common/amd'; @@ -21,7 +21,7 @@ enum WinSpawnType { CMDER } -export class WinTerminalService implements ITerminalService { +export class WindowsExternalTerminalService implements IExternalTerminalService { public _serviceBrand: any; private static readonly CMD = 'cmd.exe'; @@ -32,14 +32,14 @@ export class WinTerminalService implements ITerminalService { } public openTerminal(cwd?: string): void { - const configuration = this._configurationService.getValue(); + const configuration = this._configurationService.getValue(); this.spawnTerminal(cp, configuration, processes.getWindowsShell(), cwd); } public runInTerminal(title: string, dir: string, args: string[], envVars: IProcessEnvironment): Promise { - const configuration = this._configurationService.getValue(); + const configuration = this._configurationService.getValue(); const terminalConfig = configuration.terminal.external; const exec = terminalConfig.windowsExec || getDefaultTerminalWindows(); @@ -64,14 +64,14 @@ export class WinTerminalService implements ITerminalService { windowsVerbatimArguments: true }; - const cmd = cp.spawn(WinTerminalService.CMD, cmdArgs, options); + const cmd = cp.spawn(WindowsExternalTerminalService.CMD, cmdArgs, options); cmd.on('error', e); c(undefined); }); } - private spawnTerminal(spawner, configuration: ITerminalConfiguration, command: string, cwd?: string): Promise { + private spawnTerminal(spawner, configuration: IExternalTerminalConfiguration, command: string, cwd?: string): Promise { const terminalConfig = configuration.terminal.external; const exec = terminalConfig.windowsExec || getDefaultTerminalWindows(); const spawnType = this.getSpawnType(exec); @@ -113,7 +113,7 @@ export class WinTerminalService implements ITerminalService { } } -export class MacTerminalService implements ITerminalService { +export class MacExternalTerminalService implements IExternalTerminalService { public _serviceBrand: any; private static readonly OSASCRIPT = '/usr/bin/osascript'; // osascript is the AppleScript interpreter on OS X @@ -123,14 +123,14 @@ export class MacTerminalService implements ITerminalService { ) { } public openTerminal(cwd?: string): void { - const configuration = this._configurationService.getValue(); + const configuration = this._configurationService.getValue(); this.spawnTerminal(cp, configuration, cwd); } public runInTerminal(title: string, dir: string, args: string[], envVars: IProcessEnvironment): Promise { - const configuration = this._configurationService.getValue(); + const configuration = this._configurationService.getValue(); const terminalConfig = configuration.terminal.external; const terminalApp = terminalConfig.osxExec || DEFAULT_TERMINAL_OSX; @@ -142,7 +142,7 @@ export class MacTerminalService implements ITerminalService { // and then launches the program inside that window. const script = terminalApp === DEFAULT_TERMINAL_OSX ? 'TerminalHelper' : 'iTermHelper'; - const scriptpath = getPathFromAmdModule(require, `vs/workbench/contrib/execution/electron-browser/${script}.scpt`); + const scriptpath = getPathFromAmdModule(require, `vs/workbench/contrib/externalTerminal/electron-browser/${script}.scpt`); const osaArgs = [ scriptpath, @@ -169,7 +169,7 @@ export class MacTerminalService implements ITerminalService { } let stderr = ''; - const osa = cp.spawn(MacTerminalService.OSASCRIPT, osaArgs); + const osa = cp.spawn(MacExternalTerminalService.OSASCRIPT, osaArgs); osa.on('error', e); osa.stderr.on('data', (data) => { stderr += data.toString(); @@ -192,7 +192,7 @@ export class MacTerminalService implements ITerminalService { }); } - private spawnTerminal(spawner, configuration: ITerminalConfiguration, cwd?: string): Promise { + private spawnTerminal(spawner, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { const terminalConfig = configuration.terminal.external; const terminalApp = terminalConfig.osxExec || DEFAULT_TERMINAL_OSX; @@ -204,7 +204,7 @@ export class MacTerminalService implements ITerminalService { } } -export class LinuxTerminalService implements ITerminalService { +export class LinuxExternalTerminalService implements IExternalTerminalService { public _serviceBrand: any; private static readonly WAIT_MESSAGE = nls.localize('press.any.key', "Press any key to continue..."); @@ -215,14 +215,14 @@ export class LinuxTerminalService implements ITerminalService { public openTerminal(cwd?: string): void { - const configuration = this._configurationService.getValue(); + const configuration = this._configurationService.getValue(); this.spawnTerminal(cp, configuration, cwd); } public runInTerminal(title: string, dir: string, args: string[], envVars: IProcessEnvironment): Promise { - const configuration = this._configurationService.getValue(); + const configuration = this._configurationService.getValue(); const terminalConfig = configuration.terminal.external; const execPromise = terminalConfig.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : getDefaultTerminalLinuxReady(); @@ -240,7 +240,7 @@ export class LinuxTerminalService implements ITerminalService { termArgs.push('bash'); termArgs.push('-c'); - const bashCommand = `${quote(args)}; echo; read -p "${LinuxTerminalService.WAIT_MESSAGE}" -n1;`; + const bashCommand = `${quote(args)}; echo; read -p "${LinuxExternalTerminalService.WAIT_MESSAGE}" -n1;`; termArgs.push(`''${bashCommand}''`); // wrapping argument in two sets of ' because node is so "friendly" that it removes one set... // merge environment variables into a copy of the process.env @@ -276,7 +276,7 @@ export class LinuxTerminalService implements ITerminalService { }); } - private spawnTerminal(spawner, configuration: ITerminalConfiguration, cwd?: string): Promise { + private spawnTerminal(spawner, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { const terminalConfig = configuration.terminal.external; const execPromise = terminalConfig.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : getDefaultTerminalLinuxReady(); const env = cwd ? { cwd: cwd } : undefined; diff --git a/src/vs/workbench/contrib/execution/electron-browser/iTermHelper.scpt b/src/vs/workbench/contrib/externalTerminal/electron-browser/iTermHelper.scpt similarity index 100% rename from src/vs/workbench/contrib/execution/electron-browser/iTermHelper.scpt rename to src/vs/workbench/contrib/externalTerminal/electron-browser/iTermHelper.scpt diff --git a/src/vs/workbench/contrib/execution/test/electron-browser/terminalService.test.ts b/src/vs/workbench/contrib/externalTerminal/test/electron-browser/externalTerminalService.test.ts similarity index 86% rename from src/vs/workbench/contrib/execution/test/electron-browser/terminalService.test.ts rename to src/vs/workbench/contrib/externalTerminal/test/electron-browser/externalTerminalService.test.ts index 7795082c1fa..8690ad8ae34 100644 --- a/src/vs/workbench/contrib/execution/test/electron-browser/terminalService.test.ts +++ b/src/vs/workbench/contrib/externalTerminal/test/electron-browser/externalTerminalService.test.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { deepEqual, equal } from 'assert'; -import { WinTerminalService, LinuxTerminalService, MacTerminalService } from 'vs/workbench/contrib/execution/electron-browser/terminalService'; -import { getDefaultTerminalWindows, getDefaultTerminalLinuxReady, DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/execution/electron-browser/terminal'; +import { WindowsExternalTerminalService, LinuxExternalTerminalService, MacExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminalService'; +import { getDefaultTerminalWindows, getDefaultTerminalLinuxReady, DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal'; -suite('Execution - TerminalService', () => { +suite('ExternalTerminalService', () => { let mockOnExit: Function; let mockOnError: Function; let mockConfig: any; @@ -42,7 +42,7 @@ suite('Execution - TerminalService', () => { }; } }; - let testService = new WinTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -67,7 +67,7 @@ suite('Execution - TerminalService', () => { } }; mockConfig.terminal.external.windowsExec = undefined; - let testService = new WinTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -91,7 +91,7 @@ suite('Execution - TerminalService', () => { }; } }; - let testService = new WinTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -115,7 +115,7 @@ suite('Execution - TerminalService', () => { return { on: (evt: any) => evt }; } }; - let testService = new WinTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -138,7 +138,7 @@ suite('Execution - TerminalService', () => { }; } }; - let testService = new MacTerminalService(mockConfig); + let testService = new MacExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -161,7 +161,7 @@ suite('Execution - TerminalService', () => { } }; mockConfig.terminal.external.osxExec = undefined; - let testService = new MacTerminalService(mockConfig); + let testService = new MacExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -184,7 +184,7 @@ suite('Execution - TerminalService', () => { }; } }; - let testService = new LinuxTerminalService(mockConfig); + let testService = new LinuxExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -208,7 +208,7 @@ suite('Execution - TerminalService', () => { } }; mockConfig.terminal.external.linuxExec = undefined; - let testService = new LinuxTerminalService(mockConfig); + let testService = new LinuxExternalTerminalService(mockConfig); (testService).spawnTerminal( mockSpawner, mockConfig, diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 7fc0c7748e1..7a1ce54df5f 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -171,7 +171,7 @@ import 'vs/workbench/contrib/codeEditor/browser/codeEditor.contribution'; import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution'; // Execution -import 'vs/workbench/contrib/execution/electron-browser/execution.contribution'; +import 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution'; // Snippets import 'vs/workbench/contrib/snippets/browser/snippets.contribution'; From fe169ce4d28fde2a8f71c2d8600c4780b6457e46 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 16:46:45 -0800 Subject: [PATCH 34/88] Move terminalLinkHandler, electron-browser->browser Part of #69115 --- src/tsconfig.strictNullChecks.json | 2 +- .../terminalLinkHandler.ts | 58 +++++++++++++++++-- .../electron-browser/terminalInstance.ts | 2 +- .../terminalLinkHandler.test.ts | 16 ++--- 4 files changed, 62 insertions(+), 16 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/terminalLinkHandler.ts (87%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 7802f41674b..c6deb24a509 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -279,6 +279,7 @@ "./vs/workbench/contrib/surveys/electron-browser/nps.contribution.ts", "./vs/workbench/contrib/terminal/browser/terminalFindWidget.ts", + "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", "./vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts", "./vs/workbench/contrib/terminal/browser/terminalTab.ts", "./vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts", @@ -290,7 +291,6 @@ "./vs/workbench/contrib/terminal/electron-browser/terminalActions.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", - "./vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts similarity index 87% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler.ts rename to src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts index 734d13fd45a..d0c1214879c 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts @@ -6,8 +6,7 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; -import * as pfs from 'vs/base/node/pfs'; -import { URI as Uri } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; @@ -15,7 +14,53 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ILinkMatcherOptions } from 'vscode-xterm'; +import { IFileService } from 'vs/platform/files/common/files'; + +// Since importing from vscode-xterm would be a layer breakage here the type is copied inline +// import { ILinkMatcherOptions } from 'vscode-xterm'; + +/** + * An object containing options for a link matcher. + */ +export interface ILinkMatcherOptions { + /** + * The index of the link from the regex.match(text) call. This defaults to 0 + * (for regular expressions without capture groups). + */ + matchIndex?: number; + + /** + * A callback that validates whether to create an individual link, pass + * whether the link is valid to the callback. + */ + validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; + + /** + * A callback that fires when the mouse hovers over a link for a moment. + */ + tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; + + /** + * A callback that fires when the mouse leaves a link. Note that this can + * happen even when tooltipCallback hasn't fired for the link yet. + */ + leaveCallback?: (event: MouseEvent, uri: string) => boolean | void; + + /** + * The priority of the link matcher, this defines the order in which the link + * matcher is evaluated relative to others, from highest to lowest. The + * default value is 0. + */ + priority?: number; + + /** + * A callback that fires when the mousedown and click events occur that + * determines whether a link will be activated upon click. This enables + * only activating a link when a certain modifier is held down, if not the + * mouse event will continue propagation (eg. double click to select word). + */ + willLinkActivate?: (event: MouseEvent, uri: string) => boolean; +} const pathPrefix = '(\\.\\.?|\\~)'; const pathSeparatorClause = '\\/'; @@ -74,6 +119,7 @@ export class TerminalLinkHandler { @IEditorService private readonly _editorService: IEditorService, @IConfigurationService private readonly _configurationService: IConfigurationService, @ITerminalService private readonly _terminalService: ITerminalService, + @IFileService private readonly _fileService: IFileService ) { const baseLocalLinkClause = _platform === platform.Platform.Windows ? winLocalLinkClause : unixLocalLinkClause; // Append line and column number regex @@ -203,7 +249,7 @@ export class TerminalLinkHandler { if (!normalizedUrl) { return Promise.resolve(null); } - const resource = Uri.file(normalizedUrl); + const resource = URI.file(normalizedUrl); const lineColumnInfo: LineColumnInfo = this.extractLineColumnInfo(link); const selection: ITextEditorSelection = { startLineNumber: lineColumnInfo.lineNumber, @@ -223,7 +269,7 @@ export class TerminalLinkHandler { } private _handleHypertextLink(url: string): void { - const uri = Uri.parse(url); + const uri = URI.parse(url); this._openerService.open(uri); } @@ -288,7 +334,7 @@ export class TerminalLinkHandler { } // Ensure the file exists on disk, so an editor can be opened after clicking it - return pfs.fileExists(linkUrl).then(isFile => { + return this._fileService.existsFile(URI.file(linkUrl)).then(isFile => { if (!isFile) { return null; } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index f3764101c3a..22f9378da7b 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -31,7 +31,7 @@ import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalPr import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; -import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler'; +import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/electron-browser/terminalProcessManager'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/node/terminalCommandTracker'; import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts index 99edaab4671..5b708d68123 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { Platform } from 'vs/base/common/platform'; -import { TerminalLinkHandler, LineColumnInfo } from 'vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler'; +import { TerminalLinkHandler, LineColumnInfo } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import * as strings from 'vs/base/common/strings'; import * as path from 'vs/base/common/path'; import * as sinon from 'sinon'; @@ -39,7 +39,7 @@ interface LinkFormatInfo { suite('Workbench - TerminalLinkHandler', () => { suite('localLinkRegex', () => { test('Windows', () => { - const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null!, null!, null!, null!); + const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null!, null!, null!, null!, null!); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -111,7 +111,7 @@ suite('Workbench - TerminalLinkHandler', () => { }); test('Linux', () => { - const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!); + const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!, null!); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -175,7 +175,7 @@ suite('Workbench - TerminalLinkHandler', () => { suite('preprocessPath', () => { test('Windows', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null!, null!, null!, null!); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null!, null!, null!, null!, null!); linkHandler.processCwd = 'C:\\base'; let stub = sinon.stub(path, 'join', function (arg1: string, arg2: string) { @@ -188,7 +188,7 @@ suite('Workbench - TerminalLinkHandler', () => { stub.restore(); }); test('Windows - spaces', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null!, null!, null!, null!); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null!, null!, null!, null!, null!); linkHandler.processCwd = 'C:\\base dir'; let stub = sinon.stub(path, 'join', function (arg1: string, arg2: string) { @@ -202,7 +202,7 @@ suite('Workbench - TerminalLinkHandler', () => { }); test('Linux', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!, null!); linkHandler.processCwd = '/base'; let stub = sinon.stub(path, 'join', function (arg1: string, arg2: string) { @@ -216,7 +216,7 @@ suite('Workbench - TerminalLinkHandler', () => { }); test('No Workspace', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!, null!); assert.equal(linkHandler.preprocessPath('./src/file1'), null); assert.equal(linkHandler.preprocessPath('src/file2'), null); @@ -226,7 +226,7 @@ suite('Workbench - TerminalLinkHandler', () => { test('gitDiffLinkRegex', () => { // The platform is irrelevant because the links generated by Git are the same format regardless of platform - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null!, null!, null!, null!, null!); function assertAreGoodMatches(matches: RegExpMatchArray | null) { if (matches) { From 5d2a154da6e3c0f0e019b91b0e02e17beac74995 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 16:56:26 -0800 Subject: [PATCH 35/88] Add terminal-specific tslint rule to allow vscode-xterm imports --- .../terminal/browser/terminalLinkHandler.ts | 47 +------------------ tslint.json | 7 +++ 2 files changed, 8 insertions(+), 46 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts index d0c1214879c..0c7246a7038 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts @@ -15,52 +15,7 @@ import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal' import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IFileService } from 'vs/platform/files/common/files'; - -// Since importing from vscode-xterm would be a layer breakage here the type is copied inline -// import { ILinkMatcherOptions } from 'vscode-xterm'; - -/** - * An object containing options for a link matcher. - */ -export interface ILinkMatcherOptions { - /** - * The index of the link from the regex.match(text) call. This defaults to 0 - * (for regular expressions without capture groups). - */ - matchIndex?: number; - - /** - * A callback that validates whether to create an individual link, pass - * whether the link is valid to the callback. - */ - validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; - - /** - * A callback that fires when the mouse hovers over a link for a moment. - */ - tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; - - /** - * A callback that fires when the mouse leaves a link. Note that this can - * happen even when tooltipCallback hasn't fired for the link yet. - */ - leaveCallback?: (event: MouseEvent, uri: string) => boolean | void; - - /** - * The priority of the link matcher, this defines the order in which the link - * matcher is evaluated relative to others, from highest to lowest. The - * default value is 0. - */ - priority?: number; - - /** - * A callback that fires when the mousedown and click events occur that - * determines whether a link will be activated upon click. This enables - * only activating a link when a certain modifier is held down, if not the - * mouse event will continue propagation (eg. double click to select word). - */ - willLinkActivate?: (event: MouseEvent, uri: string) => boolean; -} +import { ILinkMatcherOptions } from 'vscode-xterm'; const pathPrefix = '(\\.\\.?|\\~)'; const pathSeparatorClause = '\\/'; diff --git a/tslint.json b/tslint.json index 0383001a61b..5365738399a 100644 --- a/tslint.json +++ b/tslint.json @@ -485,6 +485,13 @@ "assert" ] }, + { + "target": "**/vs/workbench/contrib/terminal/browser/**", + "restrictions": [ + "vscode-xterm", + "**/vs/**" + ] + }, { "target": "**/vs/code/node/**", "restrictions": [ From 8afa7773d5237bcfd8602d6afb2f5a92c6c21b57 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 17:16:21 -0800 Subject: [PATCH 36/88] Remove os dep in terminalEnvironment --- .../api/node/extHostTerminalService.ts | 3 ++- .../terminal/browser/terminalService.ts | 25 +++++++++++++++++++ .../terminal/common/terminalService.ts | 9 +++++-- .../terminalProcessManager.ts | 4 ++- .../electron-browser/terminalService.ts | 13 ++-------- .../terminal/node/terminalEnvironment.ts | 5 ++-- .../test/node/terminalEnvironment.test.ts | 23 ++++++++--------- 7 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalService.ts diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 4e10c68feb2..156d7ad5c82 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import * as os from 'os'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; @@ -429,7 +430,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { // TODO: @daniel const activeWorkspaceRootUri = URI.revive(activeWorkspaceRootUriComponents); - const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, activeWorkspaceRootUri, terminalConfig.cwd); + const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, os.homedir(), activeWorkspaceRootUri, terminalConfig.cwd); // TODO: Pull in and resolve config settings // // Resolve env vars from config and shell diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts new file mode 100644 index 00000000000..060ce2863aa --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IStorageService } from 'vs/platform/storage/common/storage'; + +export abstract class TerminalService extends CommonTerminalService implements ITerminalService { + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @IPanelService panelService: IPanelService, + @IPartService partService: IPartService, + @ILifecycleService lifecycleService: ILifecycleService, + @IStorageService storageService: IStorageService + ) { + super(contextKeyService, panelService, partService, lifecycleService, storageService); + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 2af5a375481..ab3e50b1885 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -21,7 +21,9 @@ export abstract class TerminalService implements ITerminalService { protected _findWidgetVisible: IContextKey; protected _terminalContainer: HTMLElement; protected _terminalTabs: ITerminalTab[]; - protected abstract _terminalInstances: ITerminalInstance[]; + protected get _terminalInstances(): ITerminalInstance[] { + return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); + } private _findState: FindReplaceState; private _activeTabIndex: number; @@ -89,13 +91,16 @@ export abstract class TerminalService implements ITerminalService { protected abstract _showTerminalCloseConfirmation(): Promise; protected abstract _showNotEnoughSpaceToast(): void; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; - public abstract createTerminalRenderer(name: string): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance; public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; public abstract requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void; + public createTerminalRenderer(name: string): ITerminalInstance { + return this.createTerminal({ name, isRendererOnly: true }); + } + private _onBeforeShutdown(): boolean | Promise { if (this.terminalInstances.length === 0) { // No terminal instances, don't veto diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts index a3fa9af9e3d..786c7f7f2f8 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts @@ -21,6 +21,7 @@ import { Schemas } from 'vs/base/common/network'; import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { sanitizeProcessEnvironment } from 'vs/base/node/processes'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; @@ -61,6 +62,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { @IConfigurationResolverService private readonly _configurationResolverService: IConfigurationResolverService, @IWindowService private readonly _windowService: IWindowService, @IWorkspaceConfigurationService private readonly _workspaceConfigurationService: IWorkspaceConfigurationService, + @IEnvironmentService private readonly _environmentSertvice: IEnvironmentService ) { this.ptyProcessReady = new Promise(c => { this.onProcessReady(() => { @@ -110,7 +112,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { } const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); - const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, activeWorkspaceRootUri, this._configHelper.config.cwd); + const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentSertvice.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd); // Compel type system as process.env should not have any undefined entries let env: platform.IProcessEnvironment = {}; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index fbace8ec6fb..f916502d8f5 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -13,7 +13,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, TERMINAL_PANEL_ID, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; -import { TerminalService as AbstractTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; +import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; import Severity from 'vs/base/common/severity'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -30,15 +30,10 @@ import { URI } from 'vs/base/common/uri'; import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; import { coalesce } from 'vs/base/common/arrays'; -export class TerminalService extends AbstractTerminalService implements ITerminalService { +export class TerminalService extends BrowserTerminalService implements ITerminalService { private _configHelper: TerminalConfigHelper; public get configHelper(): ITerminalConfigHelper { return this._configHelper; } - protected _terminalTabs: TerminalTab[]; - protected get _terminalInstances(): ITerminalInstance[] { - return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); - } - constructor( @IContextKeyService contextKeyService: IContextKeyService, @IPanelService panelService: IPanelService, @@ -98,10 +93,6 @@ export class TerminalService extends AbstractTerminalService implements ITermina return instance; } - public createTerminalRenderer(name: string): ITerminalInstance { - return this.createTerminal({ name, isRendererOnly: true }); - } - public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); this._onInstanceCreated.fire(instance); diff --git a/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts index 612ea746d21..668ec2ef2ac 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as os from 'os'; import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; import pkg from 'vs/platform/product/node/package'; @@ -102,7 +101,7 @@ function _getLangEnvVariable(locale?: string) { return parts.join('_') + '.UTF-8'; } -export function getCwd(shell: IShellLaunchConfig, root?: Uri, customCwd?: string): string { +export function getCwd(shell: IShellLaunchConfig, userHome: string, root?: Uri, customCwd?: string): string { if (shell.cwd) { return (typeof shell.cwd === 'object') ? shell.cwd.fsPath : shell.cwd; } @@ -120,7 +119,7 @@ export function getCwd(shell: IShellLaunchConfig, root?: Uri, customCwd?: string // If there was no custom cwd or it was relative with no workspace if (!cwd) { - cwd = root ? root.fsPath : os.homedir(); + cwd = root ? root.fsPath : userHome; } return _sanitizeCwd(cwd); diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts index 0f9ecc1299a..1549d0b2e56 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import * as os from 'os'; import * as platform from 'vs/base/common/platform'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; import { URI as Uri } from 'vs/base/common/uri'; @@ -101,32 +100,32 @@ suite('Workbench - TerminalEnvironment', () => { assert.equal(Uri.file(a).fsPath, Uri.file(b).fsPath); } - test('should default to os.homedir() for an empty workspace', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, undefined, undefined), os.homedir()); + test('should default to userHome for an empty workspace', () => { + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, undefined), '/userHome/'); }); test('should use to the workspace if it exists', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, Uri.file('/foo'), undefined), '/foo'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', Uri.file('/foo'), undefined), '/foo'); }); test('should use an absolute custom cwd as is', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, undefined, '/foo'), '/foo'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, '/foo'), '/foo'); }); test('should normalize a relative custom cwd against the workspace path', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, Uri.file('/bar'), 'foo'), '/bar/foo'); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, Uri.file('/bar'), './foo'), '/bar/foo'); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, Uri.file('/bar'), '../foo'), '/foo'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', Uri.file('/bar'), 'foo'), '/bar/foo'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', Uri.file('/bar'), './foo'), '/bar/foo'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', Uri.file('/bar'), '../foo'), '/foo'); }); test('should fall back for relative a custom cwd that doesn\'t have a workspace', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, undefined, 'foo'), os.homedir()); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, undefined, './foo'), os.homedir()); - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, undefined, '../foo'), os.homedir()); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, 'foo'), '/userHome/'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, './foo'), '/userHome/'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [] }, '/userHome/', undefined, '../foo'), '/userHome/'); }); test('should ignore custom cwd when told to ignore', () => { - assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [], ignoreConfigurationCwd: true }, Uri.file('/bar'), '/foo'), '/bar'); + assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [], ignoreConfigurationCwd: true }, '/userHome/', Uri.file('/bar'), '/foo'), '/bar'); }); }); From badedf5d7d88fbb3adef5cd43c7a2cc9ad06a586 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 17:22:46 -0800 Subject: [PATCH 37/88] Move terminalEnvironment, node->common Part of #69115 --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/workbench/api/node/extHostTerminalService.ts | 5 +++-- .../terminal/{node => common}/terminalEnvironment.ts | 5 ++--- .../terminal/electron-browser/terminalPanel.ts | 2 +- .../electron-browser/terminalProcessManager.ts | 10 ++++++---- .../terminal/test/node/terminalEnvironment.test.ts | 12 ++++++------ 6 files changed, 19 insertions(+), 17 deletions(-) rename src/vs/workbench/contrib/terminal/{node => common}/terminalEnvironment.ts (96%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 7412a04e395..6d5d4e9b370 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -286,6 +286,7 @@ "./vs/workbench/contrib/terminal/common/terminal.ts", "./vs/workbench/contrib/terminal/common/terminalColorRegistry.ts", "./vs/workbench/contrib/terminal/common/terminalCommands.ts", + "./vs/workbench/contrib/terminal/common/terminalEnvironment.ts", "./vs/workbench/contrib/terminal/common/terminalMenu.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalActions.ts", @@ -295,7 +296,6 @@ "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalCommandTracker.ts", - "./vs/workbench/contrib/terminal/node/terminalEnvironment.ts", "./vs/workbench/contrib/terminal/node/terminalProcess.ts", "./vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts", "./vs/workbench/contrib/terminal/node/windowsShellHelper.ts", diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 156d7ad5c82..6f80fc77c38 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import pkg from 'vs/platform/product/node/package'; import * as os from 'os'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; +import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { Event, Emitter } from 'vs/base/common/event'; import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; @@ -451,7 +452,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { // Continue env initialization, merging in the env from the launch // config and adding keys that are needed to create the process - terminalEnvironment.addTerminalEnvironmentKeys(env, platform.locale, terminalConfig.get('setLocaleVariables')); + terminalEnvironment.addTerminalEnvironmentKeys(env, pkg.version, platform.locale, terminalConfig.get('setLocaleVariables')); // Fork the process and listen for messages this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env); diff --git a/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts similarity index 96% rename from src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts rename to src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 668ec2ef2ac..cf8e7fab850 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -5,7 +5,6 @@ import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; -import pkg from 'vs/platform/product/node/package'; import { URI as Uri } from 'vs/base/common/uri'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -50,9 +49,9 @@ function _mergeEnvironmentValue(env: ITerminalEnvironment, key: string, value: s } } -export function addTerminalEnvironmentKeys(env: ITerminalEnvironment, locale: string | undefined, setLocaleVariables: boolean): void { +export function addTerminalEnvironmentKeys(env: ITerminalEnvironment, version: string | undefined, locale: string | undefined, setLocaleVariables: boolean): void { env['TERM_PROGRAM'] = 'vscode'; - env['TERM_PROGRAM_VERSION'] = pkg.version; + env['TERM_PROGRAM_VERSION'] = version ? version : null; if (setLocaleVariables) { env['LANG'] = _getLangEnvVariable(locale); } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts index b4e7019e896..7d301112c40 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts @@ -6,7 +6,7 @@ import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; +import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { Action, IAction } from 'vs/base/common/actions'; import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts index 786c7f7f2f8..0a9923779e8 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as platform from 'vs/base/common/platform'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; +import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { ILogService } from 'vs/platform/log/common/log'; @@ -22,6 +22,7 @@ import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/commo import { sanitizeProcessEnvironment } from 'vs/base/node/processes'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IProductService } from 'vs/platform/product/common/product'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; @@ -62,7 +63,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { @IConfigurationResolverService private readonly _configurationResolverService: IConfigurationResolverService, @IWindowService private readonly _windowService: IWindowService, @IWorkspaceConfigurationService private readonly _workspaceConfigurationService: IWorkspaceConfigurationService, - @IEnvironmentService private readonly _environmentSertvice: IEnvironmentService + @IEnvironmentService private readonly _environmentService: IEnvironmentService, + @IProductService private readonly _productService: IProductService ) { this.ptyProcessReady = new Promise(c => { this.onProcessReady(() => { @@ -112,7 +114,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { } const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); - const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentSertvice.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd); + const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentService.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd); // Compel type system as process.env should not have any undefined entries let env: platform.IProcessEnvironment = {}; @@ -143,7 +145,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI'); // Adding other env keys necessary to create the process - terminalEnvironment.addTerminalEnvironmentKeys(env, platform.locale, this._configHelper.config.setLocaleVariables); + terminalEnvironment.addTerminalEnvironmentKeys(env, this._productService.version, platform.locale, this._configHelper.config.setLocaleVariables); } this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env); diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts index 1549d0b2e56..6153a741193 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import * as platform from 'vs/base/common/platform'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; +import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { URI as Uri } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; @@ -13,21 +13,21 @@ suite('Workbench - TerminalEnvironment', () => { test('addTerminalEnvironmentKeys', () => { const env = { FOO: 'bar' }; const locale = 'en-au'; - terminalEnvironment.addTerminalEnvironmentKeys(env, locale, true); + terminalEnvironment.addTerminalEnvironmentKeys(env, '1.2.3', locale, true); assert.equal(env['TERM_PROGRAM'], 'vscode'); - assert.equal(env['TERM_PROGRAM_VERSION'].search(/^\d+\.\d+\.\d+$/), 0); + assert.equal(env['TERM_PROGRAM_VERSION'], '1.2.3'); assert.equal(env['LANG'], 'en_AU.UTF-8', 'LANG is equal to the requested locale with UTF-8'); const env2 = { FOO: 'bar' }; - terminalEnvironment.addTerminalEnvironmentKeys(env2, undefined, true); + terminalEnvironment.addTerminalEnvironmentKeys(env2, '1.2.3', undefined, true); assert.equal(env2['LANG'], 'en_US.UTF-8', 'LANG is equal to en_US.UTF-8 as fallback.'); // More info on issue #14586 const env3 = { LANG: 'replace' }; - terminalEnvironment.addTerminalEnvironmentKeys(env3, undefined, true); + terminalEnvironment.addTerminalEnvironmentKeys(env3, '1.2.3', undefined, true); assert.equal(env3['LANG'], 'en_US.UTF-8', 'LANG is set to the fallback LANG'); const env4 = { LANG: 'en_US.UTF-8' }; - terminalEnvironment.addTerminalEnvironmentKeys(env3, undefined, true); + terminalEnvironment.addTerminalEnvironmentKeys(env3, '1.2.3', undefined, true); assert.equal(env4['LANG'], 'en_US.UTF-8', 'LANG is equal to the parent environment\'s LANG'); }); From 5b7bdaccdecbab4d19521369dc2d5f65cb094db4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 17:31:58 -0800 Subject: [PATCH 38/88] Move terminalActions, electron-browser->browser Part of #69115 --- src/tsconfig.strictNullChecks.json | 2 +- .../terminal/{electron-browser => browser}/terminalActions.ts | 4 ++-- .../terminal/electron-browser/terminal.contribution.ts | 2 +- .../contrib/terminal/electron-browser/terminalPanel.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/terminalActions.ts (99%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 6d5d4e9b370..19a576445ba 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -278,6 +278,7 @@ "./vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution.ts", "./vs/workbench/contrib/surveys/electron-browser/nps.contribution.ts", + "./vs/workbench/contrib/terminal/browser/terminalActions.ts", "./vs/workbench/contrib/terminal/browser/terminalFindWidget.ts", "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", "./vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts", @@ -289,7 +290,6 @@ "./vs/workbench/contrib/terminal/common/terminalEnvironment.ts", "./vs/workbench/contrib/terminal/common/terminalMenu.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", - "./vs/workbench/contrib/terminal/electron-browser/terminalActions.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts similarity index 99% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts rename to src/vs/workbench/contrib/terminal/browser/terminalActions.ts index a202076042b..ea11c54029c 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as os from 'os'; import { Action, IAction } from 'vs/base/common/actions'; import { EndOfLinePreference } from 'vs/editor/common/model'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -34,6 +33,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { isWindows } from 'vs/base/common/platform'; export const TERMINAL_PICKER_PREFIX = 'term '; @@ -659,7 +659,7 @@ export class RunSelectedTextInTerminalAction extends Action { if (selection.isEmpty()) { text = editor.getModel().getLineContent(selection.selectionStartLineNumber).trim(); } else { - const endOfLinePreference = os.EOL === '\n' ? EndOfLinePreference.LF : EndOfLinePreference.CRLF; + const endOfLinePreference = isWindows ? EndOfLinePreference.LF : EndOfLinePreference.CRLF; text = editor.getModel().getValueInRange(selection, endOfLinePreference); } instance.sendText(text, true); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index b15ee85b95b..562568064b1 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -16,7 +16,7 @@ import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KillTerminalAction, ClearSelectionTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX, MoveToLineStartTerminalAction, MoveToLineEndTerminalAction, SplitTerminalAction, SplitInActiveWorkspaceTerminalAction, FocusPreviousPaneTerminalAction, FocusNextPaneTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, ResizePaneDownTerminalAction, ScrollToPreviousCommandAction, ScrollToNextCommandAction, SelectToPreviousCommandAction, SelectToNextCommandAction, SelectToPreviousLineAction, SelectToNextLineAction, ToggleEscapeSequenceLoggingAction, SendSequenceTerminalCommand, ToggleRegexCommand, ToggleWholeWordCommand, ToggleCaseSensitiveCommand, FindNext, FindPrevious, DeleteToLineStartTerminalAction } from 'vs/workbench/contrib/terminal/electron-browser/terminalActions'; +import { ClearSelectionTerminalAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, MoveToLineStartTerminalAction, MoveToLineEndTerminalAction, SplitTerminalAction, SplitInActiveWorkspaceTerminalAction, FocusPreviousPaneTerminalAction, FocusNextPaneTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, ResizePaneDownTerminalAction, ScrollToPreviousCommandAction, ScrollToNextCommandAction, SelectToPreviousCommandAction, SelectToNextCommandAction, SelectToPreviousLineAction, SelectToNextLineAction, ToggleEscapeSequenceLoggingAction, SendSequenceTerminalCommand, ToggleRegexCommand, ToggleWholeWordCommand, ToggleCaseSensitiveCommand, FindNext, FindPrevious, DeleteToLineStartTerminalAction, TERMINAL_PICKER_PREFIX, KillTerminalAction, CopyTerminalSelectionAction, SelectAllTerminalAction, ToggleTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { TerminalService } from 'vs/workbench/contrib/terminal/electron-browser/terminalService'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts index 7d301112c40..036053299f8 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts @@ -17,7 +17,7 @@ import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/termin import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { URI } from 'vs/base/common/uri'; From 3760c273fa12e6b89274049bb546fd013ae21ec5 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 17:34:36 -0800 Subject: [PATCH 39/88] Move terminalPanel, electron-browser->browser Part of #69115 --- src/tsconfig.strictNullChecks.json | 2 +- .../terminalPanel.ts | 15 ++++++--------- .../workbench/contrib/terminal/common/terminal.ts | 1 + .../electron-browser/terminal.contribution.ts | 2 +- .../terminal/electron-browser/terminalService.ts | 2 +- src/vs/workbench/workbench.main.ts | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/terminalPanel.ts (96%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 19a576445ba..41f71cf9d5c 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -281,6 +281,7 @@ "./vs/workbench/contrib/terminal/browser/terminalActions.ts", "./vs/workbench/contrib/terminal/browser/terminalFindWidget.ts", "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", + "./vs/workbench/contrib/terminal/browser/terminalPanel.ts", "./vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts", "./vs/workbench/contrib/terminal/browser/terminalTab.ts", "./vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts", @@ -292,7 +293,6 @@ "./vs/workbench/contrib/terminal/common/terminalService.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", - "./vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalCommandTracker.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts similarity index 96% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts rename to src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 036053299f8..60286fd0e37 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -24,7 +24,6 @@ import { URI } from 'vs/base/common/uri'; import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { DataTransfers } from 'vs/base/browser/dnd'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; -import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; import { IStorageService } from 'vs/platform/storage/common/storage'; const FIND_FOCUS_CLASS = 'find-focused'; @@ -82,14 +81,12 @@ export class TerminalPanel extends Panel { if (e.affectsConfiguration('terminal.integrated.fontFamily') || e.affectsConfiguration('editor.fontFamily')) { const configHelper = this._terminalService.configHelper; - if (configHelper instanceof TerminalConfigHelper) { - if (!configHelper.configFontIsMonospace()) { - const choices: IPromptChoice[] = [{ - label: nls.localize('terminal.useMonospace', "Use 'monospace'"), - run: () => this._configurationService.updateValue('terminal.integrated.fontFamily', 'monospace'), - }]; - this._notificationService.prompt(Severity.Warning, nls.localize('terminal.monospaceOnly', "The terminal only supports monospace fonts."), choices); - } + if (!configHelper.configFontIsMonospace()) { + const choices: IPromptChoice[] = [{ + label: nls.localize('terminal.useMonospace', "Use 'monospace'"), + run: () => this._configurationService.updateValue('terminal.integrated.fontFamily', 'monospace'), + }]; + this._notificationService.prompt(Severity.Warning, nls.localize('terminal.monospaceOnly', "The terminal only supports monospace fonts."), choices); } } })); diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 5673030976d..57217bb480c 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -107,6 +107,7 @@ export interface ITerminalConfiguration { export interface ITerminalConfigHelper { config: ITerminalConfiguration; + configFontIsMonospace(): boolean; getFont(): ITerminalFont; /** * Merges the default shell path and args into the provided launch configuration diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index 562568064b1..e703212b0b4 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -28,7 +28,7 @@ import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/qu import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { TerminalPanel } from 'vs/workbench/contrib/terminal/electron-browser/terminalPanel'; +import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 1914cf4af95..aa6c650d924 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -18,7 +18,7 @@ import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-bro import Severity from 'vs/base/common/severity'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; -import { TerminalPanel } from 'vs/workbench/contrib/terminal/electron-browser/terminalPanel'; +import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 7a1ce54df5f..84ed6ce8f02 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -154,7 +154,7 @@ import 'vs/workbench/contrib/output/browser/outputPanel'; // Terminal import 'vs/workbench/contrib/terminal/electron-browser/terminal.contribution'; import 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; -import 'vs/workbench/contrib/terminal/electron-browser/terminalPanel'; +import 'vs/workbench/contrib/terminal/browser/terminalPanel'; // Relauncher import 'vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution'; From 2675ffeaafa5b91dd2102795543cde8e8f4d6075 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 17:39:47 -0800 Subject: [PATCH 40/88] Move parts of terminalService up to common/browser --- .../terminal/browser/terminalService.ts | 44 ++++++++++++- .../terminal/common/terminalService.ts | 33 ++++++++-- .../electron-browser/terminalService.ts | 65 ++----------------- 3 files changed, 74 insertions(+), 68 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 060ce2863aa..7bf4664b9e6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -3,13 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { INotificationService } from 'vs/platform/notification/common/notification'; export abstract class TerminalService extends CommonTerminalService implements ITerminalService { @@ -18,8 +21,43 @@ export abstract class TerminalService extends CommonTerminalService implements I @IPanelService panelService: IPanelService, @IPartService partService: IPartService, @ILifecycleService lifecycleService: ILifecycleService, - @IStorageService storageService: IStorageService + @IStorageService storageService: IStorageService, + @INotificationService notificationService: INotificationService, + @IDialogService dialogService: IDialogService ) { - super(contextKeyService, panelService, partService, lifecycleService, storageService); + super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService); + } + + public focusFindWidget(): Promise { + return this.showPanel(false).then(() => { + const panel = this._panelService.getActivePanel() as TerminalPanel; + panel.focusFindWidget(); + this._findWidgetVisible.set(true); + }); + } + + public hideFindWidget(): void { + const panel = this._panelService.getActivePanel() as TerminalPanel; + if (panel && panel.getId() === TERMINAL_PANEL_ID) { + panel.hideFindWidget(); + this._findWidgetVisible.reset(); + panel.focus(); + } + } + + public findNext(): void { + const panel = this._panelService.getActivePanel() as TerminalPanel; + if (panel && panel.getId() === TERMINAL_PANEL_ID) { + panel.showFindWidget(); + panel.getFindWidget().find(false); + } + } + + public findPrevious(): void { + const panel = this._panelService.getActivePanel() as TerminalPanel; + if (panel && panel.getId() === TERMINAL_PANEL_ID) { + panel.showFindWidget(); + panel.getFindWidget().find(true); + } } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 792ffad09b7..1999fd8a6ec 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -12,6 +13,8 @@ import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfi import { IStorageService } from 'vs/platform/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; export abstract class TerminalService implements ITerminalService { public _serviceBrand: any; @@ -60,7 +63,9 @@ export abstract class TerminalService implements ITerminalService { @IPanelService protected readonly _panelService: IPanelService, @IPartService private readonly _partService: IPartService, @ILifecycleService lifecycleService: ILifecycleService, - @IStorageService protected readonly _storageService: IStorageService + @IStorageService protected readonly _storageService: IStorageService, + @INotificationService protected readonly _notificationService: INotificationService, + @IDialogService private readonly _dialogService: IDialogService ) { this._activeTabIndex = 0; this._isShuttingDown = false; @@ -88,11 +93,8 @@ export abstract class TerminalService implements ITerminalService { this.onInstancesChanged(() => updateTerminalContextKeys()); } - protected abstract _showTerminalCloseConfirmation(): Promise; - protected abstract _showNotEnoughSpaceToast(): void; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; - public abstract getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance; public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; public abstract requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void; @@ -101,6 +103,11 @@ export abstract class TerminalService implements ITerminalService { return this.createTerminal({ name, isRendererOnly: true }); } + public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance { + const activeInstance = this.getActiveInstance(); + return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); + } + private _onBeforeShutdown(): boolean | Promise { if (this.terminalInstances.length === 0) { // No terminal instances, don't veto @@ -373,4 +380,22 @@ export abstract class TerminalService implements ITerminalService { public setWorkspaceShellAllowed(isAllowed: boolean): void { this.configHelper.setWorkspaceShellAllowed(isAllowed); } + + protected _showTerminalCloseConfirmation(): Promise { + let message; + if (this.terminalInstances.length === 1) { + message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); + } else { + message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); + } + + return this._dialogService.confirm({ + message, + type: 'warning', + }).then(res => !res.confirmed); + } + + protected _showNotEnoughSpaceToast(): void { + this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); + } } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index aa6c650d924..b2739f6b45a 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -12,13 +12,12 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, TERMINAL_PANEL_ID, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; import Severity from 'vs/base/common/severity'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; -import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -43,12 +42,12 @@ export class TerminalService extends BrowserTerminalService implements ITerminal @IConfigurationService private readonly _configurationService: IConfigurationService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IQuickInputService private readonly _quickInputService: IQuickInputService, - @INotificationService private readonly _notificationService: INotificationService, - @IDialogService private readonly _dialogService: IDialogService, + @INotificationService notificationService: INotificationService, + @IDialogService dialogService: IDialogService, @IExtensionService private readonly _extensionService: IExtensionService, @IWindowService private readonly _windowService: IWindowService, ) { - super(contextKeyService, panelService, partService, lifecycleService, storageService); + super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService); this._terminalTabs = []; this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper); @@ -112,39 +111,6 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - public focusFindWidget(): Promise { - return this.showPanel(false).then(() => { - const panel = this._panelService.getActivePanel() as TerminalPanel; - panel.focusFindWidget(); - this._findWidgetVisible.set(true); - }); - } - - public hideFindWidget(): void { - const panel = this._panelService.getActivePanel() as TerminalPanel; - if (panel && panel.getId() === TERMINAL_PANEL_ID) { - panel.hideFindWidget(); - this._findWidgetVisible.reset(); - panel.focus(); - } - } - - public findNext(): void { - const panel = this._panelService.getActivePanel() as TerminalPanel; - if (panel && panel.getId() === TERMINAL_PANEL_ID) { - panel.showFindWidget(); - panel.getFindWidget().find(false); - } - } - - public findPrevious(): void { - const panel = this._panelService.getActivePanel() as TerminalPanel; - if (panel && panel.getId() === TERMINAL_PANEL_ID) { - panel.showFindWidget(); - panel.getFindWidget().find(true); - } - } - private _suggestShellChange(wasNewTerminalAction?: boolean): void { // Only suggest on Windows since $SHELL works great for macOS/Linux if (!platform.isWindows) { @@ -277,29 +243,6 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance { - const activeInstance = this.getActiveInstance(); - return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); - } - - protected _showTerminalCloseConfirmation(): Promise { - let message; - if (this.terminalInstances.length === 1) { - message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); - } else { - message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); - } - - return this._dialogService.confirm({ - message, - type: 'warning', - }).then(res => !res.confirmed); - } - - protected _showNotEnoughSpaceToast(): void { - this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); - } - public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { this._configHelper.panelContainer = panelContainer; this._terminalContainer = terminalContainer; From 1d1dbdc494a7e7821ea77c0bae5f57cd7a5c9f96 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 17:55:20 -0800 Subject: [PATCH 41/88] Move TerminalConfigHelper, electron-browser->browser Part of #69115 --- src/tsconfig.strictNullChecks.json | 2 +- .../terminalConfigHelper.ts | 8 +-- .../contrib/terminal/common/terminal.ts | 6 ++ .../terminal/common/terminalService.ts | 2 +- .../electron-browser/terminalInstance.ts | 2 +- .../electron-browser/terminalService.ts | 7 +- .../contrib/terminal/node/terminal.ts | 9 +-- .../terminalConfigHelper.test.ts | 69 ++++++++++--------- 8 files changed, 57 insertions(+), 48 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/terminalConfigHelper.ts (97%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 41f71cf9d5c..c0381030c46 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -279,6 +279,7 @@ "./vs/workbench/contrib/surveys/electron-browser/nps.contribution.ts", "./vs/workbench/contrib/terminal/browser/terminalActions.ts", + "./vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/browser/terminalFindWidget.ts", "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", "./vs/workbench/contrib/terminal/browser/terminalPanel.ts", @@ -291,7 +292,6 @@ "./vs/workbench/contrib/terminal/common/terminalEnvironment.ts", "./vs/workbench/contrib/terminal/common/terminalMenu.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", - "./vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts similarity index 97% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts rename to src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index fd82c1a61fb..91a780466ad 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -10,9 +10,8 @@ import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/ed import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ITerminalConfiguration, ITerminalConfigHelper, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalConfiguration, ITerminalConfigHelper, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; import Severity from 'vs/base/common/severity'; -import { isFedora, isUbuntu } from 'vs/workbench/contrib/terminal/node/terminal'; import { Terminal as XTermTerminal } from 'vscode-xterm'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -31,6 +30,7 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { public config: ITerminalConfiguration; public constructor( + private readonly _linuxDistro: LinuxDistro, @IConfigurationService private readonly _configurationService: IConfigurationService, @IWorkspaceConfigurationService private readonly _workspaceConfigurationService: IWorkspaceConfigurationService, @INotificationService private readonly _notificationService: INotificationService, @@ -118,10 +118,10 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { // Work around bad font on Fedora/Ubuntu if (!this.config.fontFamily) { - if (isFedora) { + if (this._linuxDistro === LinuxDistro.Fedora) { fontFamily = '\'DejaVu Sans Mono\', monospace'; } - if (isUbuntu) { + if (this._linuxDistro === LinuxDistro.Ubuntu) { fontFamily = '\'Ubuntu Mono\', monospace'; // Ubuntu mono is somehow smaller, so set fontSize a bit larger to get the same perceived size. diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 57217bb480c..a31e4c2c714 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -687,4 +687,10 @@ export interface ITerminalProcessExtHostRequest { activeWorkspaceRootUri: URI; cols: number; rows: number; +} + +export enum LinuxDistro { + Fedora, + Ubuntu, + Unknown } \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 1999fd8a6ec..88b917fbf52 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -23,7 +23,7 @@ export abstract class TerminalService implements ITerminalService { protected _terminalFocusContextKey: IContextKey; protected _findWidgetVisible: IContextKey; protected _terminalContainer: HTMLElement; - protected _terminalTabs: ITerminalTab[]; + protected _terminalTabs: ITerminalTab[] = []; protected get _terminalInstances(): ITerminalInstance[] { return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index 22f9378da7b..7341a54add6 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -30,7 +30,7 @@ import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/ter import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; -import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; +import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/electron-browser/terminalProcessManager'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/node/terminalCommandTracker'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index b2739f6b45a..483d22ccf89 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -14,10 +14,10 @@ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; -import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; +import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import Severity from 'vs/base/common/severity'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; +import { getDefaultShell, linuxDistro } from 'vs/workbench/contrib/terminal/node/terminal'; import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -49,8 +49,7 @@ export class TerminalService extends BrowserTerminalService implements ITerminal ) { super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService); - this._terminalTabs = []; - this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper); + this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro); ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => { // if the request to open files is coming in from the integrated terminal (identified though // the termProgram variable) and we are instructed to wait for editors close, wait for the diff --git a/src/vs/workbench/contrib/terminal/node/terminal.ts b/src/vs/workbench/contrib/terminal/node/terminal.ts index 73b41c24e5d..96b165c2614 100644 --- a/src/vs/workbench/contrib/terminal/node/terminal.ts +++ b/src/vs/workbench/contrib/terminal/node/terminal.ts @@ -8,6 +8,7 @@ import * as platform from 'vs/base/common/platform'; import * as processes from 'vs/base/node/processes'; import { readFile, fileExists } from 'vs/base/node/pfs'; import { Event } from 'vs/base/common/event'; +import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; /** * An interface representing a raw terminal child process, this contains a subset of the @@ -78,6 +79,7 @@ function getTerminalDefaultShellWindows(): string { return _TERMINAL_DEFAULT_SHELL_WINDOWS; } +let detectedDistro = LinuxDistro.Unknown; if (platform.isLinux) { const file = '/etc/os-release'; fileExists(file).then(exists => { @@ -87,13 +89,12 @@ if (platform.isLinux) { readFile(file).then(b => { const contents = b.toString(); if (/NAME="?Fedora"?/.test(contents)) { - isFedora = true; + detectedDistro = LinuxDistro.Fedora; } else if (/NAME="?Ubuntu"?/.test(contents)) { - isUbuntu = true; + detectedDistro = LinuxDistro.Ubuntu; } }); }); } -export let isFedora = false; -export let isUbuntu = false; \ No newline at end of file +export const linuxDistro = detectedDistro; diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalConfigHelper.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalConfigHelper.test.ts index 4ee63fee360..e0110601c82 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalConfigHelper.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalConfigHelper.test.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper'; +import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; -import { isFedora, isUbuntu } from 'vs/workbench/contrib/terminal/node/terminal'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; suite('Workbench - TerminalConfigHelper', () => { let fixture: HTMLElement; @@ -21,22 +21,24 @@ suite('Workbench - TerminalConfigHelper', () => { configurationService.setUserConfiguration('editor', { fontFamily: 'foo' }); configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: 'bar' } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().fontFamily, 'bar', 'terminal.integrated.fontFamily should be selected over editor.fontFamily'); configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: null } }); // Recreate config helper as onDidChangeConfiguration isn't implemented in TestConfigurationService - configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + configHelper = new TerminalConfigHelper(LinuxDistro.Fedora, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; - if (isFedora) { - assert.equal(configHelper.getFont().fontFamily, '\'DejaVu Sans Mono\', monospace', 'Fedora should have its font overridden when terminal.integrated.fontFamily not set'); - } else if (isUbuntu) { - assert.equal(configHelper.getFont().fontFamily, '\'Ubuntu Mono\', monospace', 'Ubuntu should have its font overridden when terminal.integrated.fontFamily not set'); - } else { - assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set'); - } + assert.equal(configHelper.getFont().fontFamily, '\'DejaVu Sans Mono\', monospace', 'Fedora should have its font overridden when terminal.integrated.fontFamily not set'); + + configHelper = new TerminalConfigHelper(LinuxDistro.Ubuntu, configurationService, null!, null!, null!); + configHelper.panelContainer = fixture; + assert.equal(configHelper.getFont().fontFamily, '\'Ubuntu Mono\', monospace', 'Ubuntu should have its font overridden when terminal.integrated.fontFamily not set'); + + configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); + configHelper.panelContainer = fixture; + assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set'); }); test('TerminalConfigHelper - getFont fontSize', function () { @@ -52,7 +54,7 @@ suite('Workbench - TerminalConfigHelper', () => { fontSize: 10 } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().fontSize, 10, 'terminal.integrated.fontSize should be selected over editor.fontSize'); @@ -65,13 +67,14 @@ suite('Workbench - TerminalConfigHelper', () => { fontSize: 0 } }); - configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + configHelper = new TerminalConfigHelper(LinuxDistro.Ubuntu, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; - if (isUbuntu) { - assert.equal(configHelper.getFont().fontSize, 8, 'The minimum terminal font size (with adjustment) should be used when terminal.integrated.fontSize less than it'); - } else { - assert.equal(configHelper.getFont().fontSize, 6, 'The minimum terminal font size should be used when terminal.integrated.fontSize less than it'); - } + assert.equal(configHelper.getFont().fontSize, 8, 'The minimum terminal font size (with adjustment) should be used when terminal.integrated.fontSize less than it'); + + configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); + configHelper.panelContainer = fixture; + assert.equal(configHelper.getFont().fontSize, 6, 'The minimum terminal font size should be used when terminal.integrated.fontSize less than it'); + configurationService.setUserConfiguration('editor', { fontFamily: 'foo' }); @@ -81,7 +84,7 @@ suite('Workbench - TerminalConfigHelper', () => { fontSize: 1500 } }); - configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().fontSize, 25, 'The maximum terminal font size should be used when terminal.integrated.fontSize more than it'); @@ -94,13 +97,13 @@ suite('Workbench - TerminalConfigHelper', () => { fontSize: null } }); - configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + configHelper = new TerminalConfigHelper(LinuxDistro.Ubuntu, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; - if (isUbuntu) { - assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize + 2, 'The default editor font size (with adjustment) should be used when terminal.integrated.fontSize is not set'); - } else { - assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when terminal.integrated.fontSize is not set'); - } + assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize + 2, 'The default editor font size (with adjustment) should be used when terminal.integrated.fontSize is not set'); + + configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); + configHelper.panelContainer = fixture; + assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when terminal.integrated.fontSize is not set'); }); test('TerminalConfigHelper - getFont lineHeight', function () { @@ -116,7 +119,7 @@ suite('Workbench - TerminalConfigHelper', () => { lineHeight: 2 } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().lineHeight, 2, 'terminal.integrated.lineHeight should be selected over editor.lineHeight'); @@ -130,7 +133,7 @@ suite('Workbench - TerminalConfigHelper', () => { lineHeight: 0 } }); - configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().lineHeight, 1, 'editor.lineHeight should be 1 when terminal.integrated.lineHeight not set'); }); @@ -143,7 +146,7 @@ suite('Workbench - TerminalConfigHelper', () => { } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.configFontIsMonospace(), true, 'monospace is monospaced'); }); @@ -155,7 +158,7 @@ suite('Workbench - TerminalConfigHelper', () => { fontFamily: 'sans-serif' } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.configFontIsMonospace(), false, 'sans-serif is not monospaced'); }); @@ -167,7 +170,7 @@ suite('Workbench - TerminalConfigHelper', () => { fontFamily: 'serif' } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.configFontIsMonospace(), false, 'serif is not monospaced'); }); @@ -183,7 +186,7 @@ suite('Workbench - TerminalConfigHelper', () => { } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.configFontIsMonospace(), true, 'monospace is monospaced'); }); @@ -199,7 +202,7 @@ suite('Workbench - TerminalConfigHelper', () => { } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.configFontIsMonospace(), false, 'sans-serif is not monospaced'); }); @@ -215,7 +218,7 @@ suite('Workbench - TerminalConfigHelper', () => { } }); - let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!); + let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!); configHelper.panelContainer = fixture; assert.equal(configHelper.configFontIsMonospace(), false, 'serif is not monospaced'); }); From b5dcee0a3185de2e019cc8127cbc5f91ab2b1b29 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 18:01:47 -0800 Subject: [PATCH 42/88] Move terminal CSS and images to browser Part of #69115 --- .../media/configure-inverse.svg | 0 .../{electron-browser => browser}/media/configure.svg | 0 .../{electron-browser => browser}/media/kill-inverse.svg | 0 .../terminal/{electron-browser => browser}/media/kill.svg | 0 .../{electron-browser => browser}/media/new-inverse.svg | 0 .../terminal/{electron-browser => browser}/media/new.svg | 0 .../{electron-browser => browser}/media/scrollbar.css | 0 .../media/split-horizontal-inverse.svg | 0 .../media/split-horizontal.svg | 0 .../{electron-browser => browser}/media/split-inverse.svg | 0 .../{electron-browser => browser}/media/split.svg | 0 .../{electron-browser => browser}/media/terminal.css | 0 .../{electron-browser => browser}/media/widgets.css | 0 .../{electron-browser => browser}/media/xterm.css | 0 .../terminal/electron-browser/terminal.contribution.ts | 8 ++++---- 15 files changed, 4 insertions(+), 4 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/configure-inverse.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/configure.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/kill-inverse.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/kill.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/new-inverse.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/new.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/scrollbar.css (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/split-horizontal-inverse.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/split-horizontal.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/split-inverse.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/split.svg (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/terminal.css (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/widgets.css (100%) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/media/xterm.css (100%) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/configure-inverse.svg b/src/vs/workbench/contrib/terminal/browser/media/configure-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/configure-inverse.svg rename to src/vs/workbench/contrib/terminal/browser/media/configure-inverse.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/configure.svg b/src/vs/workbench/contrib/terminal/browser/media/configure.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/configure.svg rename to src/vs/workbench/contrib/terminal/browser/media/configure.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/kill-inverse.svg b/src/vs/workbench/contrib/terminal/browser/media/kill-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/kill-inverse.svg rename to src/vs/workbench/contrib/terminal/browser/media/kill-inverse.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/kill.svg b/src/vs/workbench/contrib/terminal/browser/media/kill.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/kill.svg rename to src/vs/workbench/contrib/terminal/browser/media/kill.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/new-inverse.svg b/src/vs/workbench/contrib/terminal/browser/media/new-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/new-inverse.svg rename to src/vs/workbench/contrib/terminal/browser/media/new-inverse.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/new.svg b/src/vs/workbench/contrib/terminal/browser/media/new.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/new.svg rename to src/vs/workbench/contrib/terminal/browser/media/new.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/scrollbar.css b/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/scrollbar.css rename to src/vs/workbench/contrib/terminal/browser/media/scrollbar.css diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/split-horizontal-inverse.svg b/src/vs/workbench/contrib/terminal/browser/media/split-horizontal-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/split-horizontal-inverse.svg rename to src/vs/workbench/contrib/terminal/browser/media/split-horizontal-inverse.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/split-horizontal.svg b/src/vs/workbench/contrib/terminal/browser/media/split-horizontal.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/split-horizontal.svg rename to src/vs/workbench/contrib/terminal/browser/media/split-horizontal.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/split-inverse.svg b/src/vs/workbench/contrib/terminal/browser/media/split-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/split-inverse.svg rename to src/vs/workbench/contrib/terminal/browser/media/split-inverse.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/split.svg b/src/vs/workbench/contrib/terminal/browser/media/split.svg similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/split.svg rename to src/vs/workbench/contrib/terminal/browser/media/split.svg diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/terminal.css rename to src/vs/workbench/contrib/terminal/browser/media/terminal.css diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/widgets.css b/src/vs/workbench/contrib/terminal/browser/media/widgets.css similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/widgets.css rename to src/vs/workbench/contrib/terminal/browser/media/widgets.css diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/xterm.css b/src/vs/workbench/contrib/terminal/browser/media/xterm.css similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/media/xterm.css rename to src/vs/workbench/contrib/terminal/browser/media/xterm.css diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index e703212b0b4..e278b7ee47e 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/scrollbar'; -import 'vs/css!./media/terminal'; -import 'vs/css!./media/xterm'; -import 'vs/css!./media/widgets'; +import 'vs/css!../browser/media/scrollbar'; +import 'vs/css!../browser/media/terminal'; +import 'vs/css!../browser/media/xterm'; +import 'vs/css!../browser/media/widgets'; import * as nls from 'vs/nls'; import * as panel from 'vs/workbench/browser/panel'; import * as platform from 'vs/base/common/platform'; From 00f5bdb0ba79ad1d7a93815afde7486640df708e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 18:04:05 -0800 Subject: [PATCH 43/88] Move terminalCommandTracker, node->browser Part of #69115 --- src/tsconfig.strictNullChecks.json | 4 ++-- .../terminal/{node => browser}/terminalCommandTracker.ts | 0 .../contrib/terminal/electron-browser/terminalInstance.ts | 2 +- .../{node => electron-browser}/terminalCommandTracker.test.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/vs/workbench/contrib/terminal/{node => browser}/terminalCommandTracker.ts (100%) rename src/vs/workbench/contrib/terminal/test/{node => electron-browser}/terminalCommandTracker.test.ts (99%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index c0381030c46..e3974e6fdcc 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -279,6 +279,7 @@ "./vs/workbench/contrib/surveys/electron-browser/nps.contribution.ts", "./vs/workbench/contrib/terminal/browser/terminalActions.ts", + "./vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts", "./vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/browser/terminalFindWidget.ts", "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", @@ -295,14 +296,13 @@ "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", - "./vs/workbench/contrib/terminal/node/terminalCommandTracker.ts", "./vs/workbench/contrib/terminal/node/terminalProcess.ts", "./vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts", "./vs/workbench/contrib/terminal/node/windowsShellHelper.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts", + "./vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalConfigHelper.test.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts", - "./vs/workbench/contrib/terminal/test/node/terminalCommandTracker.test.ts", "./vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts", "./vs/workbench/contrib/themes/browser/themes.contribution.ts", "./vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts", diff --git a/src/vs/workbench/contrib/terminal/node/terminalCommandTracker.ts b/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts similarity index 100% rename from src/vs/workbench/contrib/terminal/node/terminalCommandTracker.ts rename to src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index 7341a54add6..dced8d25d78 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -33,7 +33,7 @@ import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/termin import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/electron-browser/terminalProcessManager'; -import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/node/terminalCommandTracker'; +import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ISearchOptions, Terminal as XTermTerminal } from 'vscode-xterm'; diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts similarity index 99% rename from src/vs/workbench/contrib/terminal/test/node/terminalCommandTracker.test.ts rename to src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts index 324781f164c..ec94ff8a518 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { Terminal, TerminalCore } from 'vscode-xterm'; -import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/node/terminalCommandTracker'; +import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; import { isWindows } from 'vs/base/common/platform'; interface TestTerminalCore extends TerminalCore { From 415c08825d9b3cdd7530ccf4e37c3b19af231888 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 18:20:50 -0800 Subject: [PATCH 44/88] Move a lot of terminalService to common/browser --- .../terminal/browser/terminalService.ts | 107 ++++++++++++++- .../terminal/common/terminalService.ts | 30 ++++- .../electron-browser/terminalService.ts | 124 ++---------------- 3 files changed, 140 insertions(+), 121 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 7bf4664b9e6..051667c8a67 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -3,16 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import * as nls from 'vs/nls'; +import * as platform from 'vs/base/common/platform'; +import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; export abstract class TerminalService extends CommonTerminalService implements ITerminalService { @@ -23,9 +30,99 @@ export abstract class TerminalService extends CommonTerminalService implements I @ILifecycleService lifecycleService: ILifecycleService, @IStorageService storageService: IStorageService, @INotificationService notificationService: INotificationService, - @IDialogService dialogService: IDialogService + @IDialogService dialogService: IDialogService, + @IInstantiationService protected readonly _instantiationService: IInstantiationService, + @IWindowService private _windowService: IWindowService, + @IExtensionService extensionService: IExtensionService, + @IFileService fileService: IFileService ) { - super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService); + super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService); + } + + protected abstract _getDefaultShell(p: platform.Platform): string; + + public createTerminal(shell: IShellLaunchConfig = {}, wasNewTerminalAction?: boolean): ITerminalInstance { + const terminalTab = this._instantiationService.createInstance(TerminalTab, + this._terminalFocusContextKey, + this.configHelper, + this._terminalContainer, + shell); + this._terminalTabs.push(terminalTab); + const instance = terminalTab.terminalInstances[0]; + terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed)); + terminalTab.addDisposable(terminalTab.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); + this._initInstanceListeners(instance); + if (this.terminalInstances.length === 1) { + // It's the first instance so it should be made active automatically + this.setActiveInstanceByIndex(0); + } + this._onInstancesChanged.fire(); + this._suggestShellChange(wasNewTerminalAction); + return instance; + } + + private _suggestShellChange(wasNewTerminalAction?: boolean): void { + // Only suggest on Windows since $SHELL works great for macOS/Linux + if (!platform.isWindows) { + return; + } + + if (this._windowService.getConfiguration().remoteAuthority) { + // Don't suggest if the opened workspace is remote + return; + } + + // Only suggest when the terminal instance is being created by an explicit user action to + // launch a terminal, as opposed to something like tasks, debug, panel restore, etc. + if (!wasNewTerminalAction) { + return; + } + + if (this._windowService.getConfiguration().remoteAuthority) { + // Don't suggest if the opened workspace is remote + return; + } + + // Don't suggest if the user has explicitly opted out + const neverSuggest = this._storageService.getBoolean(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, StorageScope.GLOBAL, false); + if (neverSuggest) { + return; + } + + // Never suggest if the setting is non-default already (ie. they set the setting manually) + if (this.configHelper.config.shell.windows !== this._getDefaultShell(platform.Platform.Windows)) { + this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL); + return; + } + + this._notificationService.prompt( + Severity.Info, + nls.localize('terminal.integrated.chooseWindowsShellInfo', "You can change the default terminal shell by selecting the customize button."), + [{ + label: nls.localize('customize', "Customize"), + run: () => { + this.selectDefaultWindowsShell().then(shell => { + if (!shell) { + return Promise.resolve(null); + } + // Launch a new instance with the newly selected shell + const instance = this.createTerminal({ + executable: shell, + args: this.configHelper.config.shellArgs.windows + }); + if (instance) { + this.setActiveInstance(instance); + } + return Promise.resolve(null); + }); + } + }, + { + label: nls.localize('never again', "Don't Show Again"), + isSecondary: true, + run: () => this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL) + }] + ); } public focusFindWidget(): Promise { diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 88b917fbf52..3d3a3baac49 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -15,6 +15,8 @@ import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; export abstract class TerminalService implements ITerminalService { public _serviceBrand: any; @@ -65,7 +67,9 @@ export abstract class TerminalService implements ITerminalService { @ILifecycleService lifecycleService: ILifecycleService, @IStorageService protected readonly _storageService: IStorageService, @INotificationService protected readonly _notificationService: INotificationService, - @IDialogService private readonly _dialogService: IDialogService + @IDialogService private readonly _dialogService: IDialogService, + @IExtensionService private readonly _extensionService: IExtensionService, + @IFileService private readonly _fileService: IFileService ) { this._activeTabIndex = 0; this._isShuttingDown = false; @@ -97,7 +101,6 @@ export abstract class TerminalService implements ITerminalService { public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; - public abstract requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void; public createTerminalRenderer(name: string): ITerminalInstance { return this.createTerminal({ name, isRendererOnly: true }); @@ -108,6 +111,16 @@ export abstract class TerminalService implements ITerminalService { return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); } + public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void { + // Ensure extension host is ready before requesting a process + this._extensionService.whenInstalledExtensionsRegistered().then(() => { + // TODO: MainThreadTerminalService is not ready at this point, fix this + setTimeout(() => { + this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows }); + }, 500); + }); + } + private _onBeforeShutdown(): boolean | Promise { if (this.terminalInstances.length === 0) { // No terminal instances, don't veto @@ -398,4 +411,17 @@ export abstract class TerminalService implements ITerminalService { protected _showNotEnoughSpaceToast(): void { this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); } + + protected _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { + if (potentialPaths.length === 0) { + return Promise.resolve(null); + } + const current = potentialPaths.shift(); + return this._fileService.existsFile(URI.file(current!)).then(exists => { + if (!exists) { + return this._validateShellPaths(label, potentialPaths); + } + return [label, current] as [string, string]; + }); + } } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 483d22ccf89..95f089ef3fd 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -12,22 +12,20 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; -import Severity from 'vs/base/common/severity'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IStorageService } from 'vs/platform/storage/common/storage'; import { getDefaultShell, linuxDistro } from 'vs/workbench/contrib/terminal/node/terminal'; -import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ipcRenderer as ipc } from 'electron'; import { IOpenFileRequest, IWindowService } from 'vs/platform/windows/common/windows'; import { TerminalInstance } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstance'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { URI } from 'vs/base/common/uri'; import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; import { coalesce } from 'vs/base/common/arrays'; +import { IFileService } from 'vs/platform/files/common/files'; export class TerminalService extends BrowserTerminalService implements ITerminalService { private _configHelper: TerminalConfigHelper; @@ -40,14 +38,15 @@ export class TerminalService extends BrowserTerminalService implements ITerminal @IStorageService storageService: IStorageService, @ILifecycleService lifecycleService: ILifecycleService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IInstantiationService instantiationService: IInstantiationService, @IQuickInputService private readonly _quickInputService: IQuickInputService, @INotificationService notificationService: INotificationService, @IDialogService dialogService: IDialogService, - @IExtensionService private readonly _extensionService: IExtensionService, - @IWindowService private readonly _windowService: IWindowService, + @IExtensionService extensionService: IExtensionService, + @IWindowService windowService: IWindowService, + @IFileService fileService: IFileService ) { - super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService); + super(contextKeyService, panelService, partService, lifecycleService, storageService, notificationService, dialogService, instantiationService, windowService, extensionService, fileService); this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro); ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => { @@ -74,104 +73,14 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - public createTerminal(shell: IShellLaunchConfig = {}, wasNewTerminalAction?: boolean): ITerminalInstance { - const terminalTab = this._instantiationService.createInstance(TerminalTab, - this._terminalFocusContextKey, - this._configHelper, - this._terminalContainer, - shell); - this._terminalTabs.push(terminalTab); - const instance = terminalTab.terminalInstances[0]; - terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed)); - terminalTab.addDisposable(terminalTab.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); - this._initInstanceListeners(instance); - if (this.terminalInstances.length === 1) { - // It's the first instance so it should be made active automatically - this.setActiveInstanceByIndex(0); - } - this._onInstancesChanged.fire(); - this._suggestShellChange(wasNewTerminalAction); - return instance; - } - public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); this._onInstanceCreated.fire(instance); return instance; } - public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void { - // Ensure extension host is ready before requesting a process - this._extensionService.whenInstalledExtensionsRegistered().then(() => { - // TODO: MainThreadTerminalService is not ready at this point, fix this - setTimeout(() => { - this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows }); - }, 500); - }); - } - - private _suggestShellChange(wasNewTerminalAction?: boolean): void { - // Only suggest on Windows since $SHELL works great for macOS/Linux - if (!platform.isWindows) { - return; - } - - if (this._windowService.getConfiguration().remoteAuthority) { - // Don't suggest if the opened workspace is remote - return; - } - - // Only suggest when the terminal instance is being created by an explicit user action to - // launch a terminal, as opposed to something like tasks, debug, panel restore, etc. - if (!wasNewTerminalAction) { - return; - } - - if (this._windowService.getConfiguration().remoteAuthority) { - // Don't suggest if the opened workspace is remote - return; - } - - // Don't suggest if the user has explicitly opted out - const neverSuggest = this._storageService.getBoolean(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, StorageScope.GLOBAL, false); - if (neverSuggest) { - return; - } - - // Never suggest if the setting is non-default already (ie. they set the setting manually) - if (this._configHelper.config.shell.windows !== getDefaultShell(platform.Platform.Windows)) { - this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL); - return; - } - - this._notificationService.prompt( - Severity.Info, - nls.localize('terminal.integrated.chooseWindowsShellInfo', "You can change the default terminal shell by selecting the customize button."), - [{ - label: nls.localize('customize', "Customize"), - run: () => { - this.selectDefaultWindowsShell().then(shell => { - if (!shell) { - return Promise.resolve(null); - } - // Launch a new instance with the newly selected shell - const instance = this.createTerminal({ - executable: shell, - args: this._configHelper.config.shellArgs.windows - }); - if (instance) { - this.setActiveInstance(instance); - } - return Promise.resolve(null); - }); - } - }, - { - label: nls.localize('never again', "Don't Show Again"), - isSecondary: true, - run: () => this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL) - }] - ); + protected _getDefaultShell(p: platform.Platform): string { + return getDefaultShell(p); } public selectDefaultWindowsShell(): Promise { @@ -229,19 +138,6 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - private _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { - if (potentialPaths.length === 0) { - return Promise.resolve(null); - } - const current = potentialPaths.shift(); - return pfs.fileExists(current!).then(exists => { - if (!exists) { - return this._validateShellPaths(label, potentialPaths); - } - return [label, current] as [string, string]; - }); - } - public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { this._configHelper.panelContainer = panelContainer; this._terminalContainer = terminalContainer; From d9af6b90a069fb18fc458e49046e0a57e812329d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 19:18:01 -0800 Subject: [PATCH 45/88] Remove execFile dep in terminal instance, unify 2 path prep functions --- .../terminal/browser/terminalFindWidget.css | 4 --- .../contrib/terminal/browser/terminalPanel.ts | 7 ++-- .../terminal/common/terminalEnvironment.ts | 29 +++++----------- .../electron-browser/terminalInstance.ts | 34 +++---------------- .../electron-browser/terminalService.ts | 4 +-- .../contrib/terminal/node/terminal.ts | 26 ++++++++++++++ .../test/node/terminalEnvironment.test.ts | 10 ------ 7 files changed, 46 insertions(+), 68 deletions(-) delete mode 100644 src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css deleted file mode 100644 index a4a092d8349..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.css +++ /dev/null @@ -1,4 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 60286fd0e37..67310672847 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -6,7 +6,6 @@ import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { Action, IAction } from 'vs/base/common/actions'; import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -281,7 +280,7 @@ export class TerminalPanel extends Panel { event.stopPropagation(); } })); - this._register(dom.addDisposableListener(this._parentDomElement, dom.EventType.DROP, (e: DragEvent) => { + this._register(dom.addDisposableListener(this._parentDomElement, dom.EventType.DROP, async (e: DragEvent) => { if (e.target === this._parentDomElement || dom.isAncestor(e.target as HTMLElement, this._parentDomElement)) { if (!e.dataTransfer) { return; @@ -303,7 +302,9 @@ export class TerminalPanel extends Panel { const terminal = this._terminalService.getActiveInstance(); if (terminal) { - terminal.sendText(terminalEnvironment.preparePathForTerminal(path), false); + return terminal.preparePathForTerminalAsync(path).then(preparedPath => { + terminal.sendText(preparedPath, false); + }); } } })); diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index cf8e7fab850..5480374bba8 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -132,26 +132,15 @@ function _sanitizeCwd(cwd: string): string { return cwd; } -/** - * Adds quotes to a path if it contains whitespaces - */ -export function preparePathForTerminal(path: string): string { - if (platform.isWindows) { - if (/\s+/.test(path)) { - return `"${path}"`; - } - return path; +export function escapeNonWindowsPath(path: string): string { + let newPath = path; + if (newPath.indexOf('\\') !== 0) { + newPath = newPath.replace(/\\/g, '\\\\'); } - path = path.replace(/(%5C|\\)/g, '\\\\'); - const charsToEscape = [ - ' ', '\'', '"', '?', ':', ';', '!', '*', '(', ')', '{', '}', '[', ']' - ]; - for (let i = 0; i < path.length; i++) { - const indexOfChar = charsToEscape.indexOf(path.charAt(i)); - if (indexOfChar >= 0) { - path = `${path.substring(0, i)}\\${path.charAt(i)}${path.substring(i + 1)}`; - i++; // Skip char due to escape char being added - } + if (!newPath && (newPath.indexOf('"') !== -1)) { + newPath = '\'' + newPath + '\''; + } else if (newPath.indexOf(' ') !== -1) { + newPath = newPath.replace(/ /g, '\\ '); } - return path; + return newPath; } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index dced8d25d78..7fe8f6286f0 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { execFile } from 'child_process'; -import * as os from 'os'; import * as path from 'vs/base/common/path'; import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -38,6 +36,8 @@ import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsSh import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ISearchOptions, Terminal as XTermTerminal } from 'vscode-xterm'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; +import { getWslPath, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -829,10 +829,8 @@ export class TerminalInstance implements ITerminalInstance { if (platform.isWindows) { // 17063 is the build number where wsl path was introduced. // Update Windows uriPath to be executed in WSL. - if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (TerminalInstance.getWindowsBuildNumber() >= 17063)) { - execFile('bash.exe', ['-c', 'echo $(wslpath ' + this._escapeNonWindowsPath(originalPath) + ')'], {}, (error, stdout, stderr) => { - c(this._escapeNonWindowsPath(stdout.trim())); - }); + if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (getWindowsBuildNumber() >= 17063)) { + c(getWslPath(originalPath)); return; } else if (hasSpace) { c('"' + originalPath + '"'); @@ -841,32 +839,10 @@ export class TerminalInstance implements ITerminalInstance { } return; } - c(this._escapeNonWindowsPath(originalPath)); + c(escapeNonWindowsPath(originalPath)); }); } - private _escapeNonWindowsPath(path: string): string { - let newPath = path; - if (newPath.indexOf('\\') !== 0) { - newPath = newPath.replace(/\\/g, '\\\\'); - } - if (!newPath && (newPath.indexOf('"') !== -1)) { - newPath = '\'' + newPath + '\''; - } else if (newPath.indexOf(' ') !== -1) { - newPath = newPath.replace(/ /g, '\\ '); - } - return newPath; - } - - public static getWindowsBuildNumber(): number { - const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); - let buildNumber: number = 0; - if (osVersion && osVersion.length === 4) { - buildNumber = parseInt(osVersion[3]); - } - return buildNumber; - } - public setVisible(visible: boolean): void { this._isVisible = visible; if (this._wrapperElement) { diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 95f089ef3fd..86451a2b64f 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -16,7 +16,7 @@ import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfi import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { getDefaultShell, linuxDistro } from 'vs/workbench/contrib/terminal/node/terminal'; +import { getDefaultShell, linuxDistro, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ipcRenderer as ipc } from 'electron'; @@ -108,7 +108,7 @@ export class TerminalService extends BrowserTerminalService implements ITerminal let useWSLexe = false; - if (TerminalInstance.getWindowsBuildNumber() >= 16299) { + if (getWindowsBuildNumber() >= 16299) { useWSLexe = true; } diff --git a/src/vs/workbench/contrib/terminal/node/terminal.ts b/src/vs/workbench/contrib/terminal/node/terminal.ts index 96b165c2614..a7b76673023 100644 --- a/src/vs/workbench/contrib/terminal/node/terminal.ts +++ b/src/vs/workbench/contrib/terminal/node/terminal.ts @@ -9,6 +9,8 @@ import * as processes from 'vs/base/node/processes'; import { readFile, fileExists } from 'vs/base/node/pfs'; import { Event } from 'vs/base/common/event'; import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; +import { execFile } from 'child_process'; +import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; /** * An interface representing a raw terminal child process, this contains a subset of the @@ -98,3 +100,27 @@ if (platform.isLinux) { } export const linuxDistro = detectedDistro; + +export function getWindowsBuildNumber(): number { + const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); + let buildNumber: number = 0; + if (osVersion && osVersion.length === 4) { + buildNumber = parseInt(osVersion[3]); + } + return buildNumber; +} + +/** + * Converts a path to a path on WSL using the wslpath utility. + * @param path The original path. + */ +export function getWslPath(path: string): Promise { + if (getWindowsBuildNumber() < 17063) { + throw new Error('wslpath does not exist on Windows build < 17063'); + } + return new Promise(c => { + execFile('bash.exe', ['-c', 'echo $(wslpath ' + escapeNonWindowsPath(path) + ')'], {}, (error, stdout, stderr) => { + c(escapeNonWindowsPath(stdout.trim())); + }); + }); +} diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts index 6153a741193..58a8af973ec 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts @@ -128,14 +128,4 @@ suite('Workbench - TerminalEnvironment', () => { assertPathsMatch(terminalEnvironment.getCwd({ executable: undefined, args: [], ignoreConfigurationCwd: true }, '/userHome/', Uri.file('/bar'), '/foo'), '/bar'); }); }); - - test('preparePathForTerminal', () => { - if (platform.isWindows) { - assert.equal(terminalEnvironment.preparePathForTerminal('C:\\foo'), 'C:\\foo'); - assert.equal(terminalEnvironment.preparePathForTerminal('C:\\foo bar'), '"C:\\foo bar"'); - return; - } - assert.equal(terminalEnvironment.preparePathForTerminal('/a/\\foo bar"\'? ;\'?? :'), '/a/\\\\foo\\ bar\\"\\\'\\?\\ \\;\\\'\\?\\?\\ \\ \\:'); - assert.equal(terminalEnvironment.preparePathForTerminal('/\\\'"?:;!*(){}[]'), '/\\\\\\\'\\"\\?\\:\\;\\!\\*\\(\\)\\{\\}\\[\\]'); - }); }); From 877f0905acceb2299720d640bd781f624688aa0c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 19:20:07 -0800 Subject: [PATCH 46/88] Move terminalProcessManager to node --- src/tsconfig.strictNullChecks.json | 2 +- .../contrib/terminal/electron-browser/terminalInstance.ts | 2 +- .../{electron-browser => node}/terminalProcessManager.ts | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => node}/terminalProcessManager.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index e3974e6fdcc..4db865ea10a 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -294,10 +294,10 @@ "./vs/workbench/contrib/terminal/common/terminalMenu.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", - "./vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalProcess.ts", "./vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts", + "./vs/workbench/contrib/terminal/node/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/windowsShellHelper.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index 7fe8f6286f0..62242b6373e 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -30,7 +30,7 @@ import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGR import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; -import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/electron-browser/terminalProcessManager'; +import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/node/terminalProcessManager'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalProcessManager.ts rename to src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts From 23fbca34b08707f2d050c3a0326acd0808415679 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 19:51:18 -0800 Subject: [PATCH 47/88] Break node dependency in TerminalInstance --- .../contrib/terminal/browser/terminal.ts | 18 +++++ .../terminal/browser/terminalActions.ts | 2 +- .../contrib/terminal/browser/terminalPanel.ts | 2 +- .../contrib/terminal/common/terminal.ts | 30 +++++---- .../terminal/common/terminalService.ts | 1 + .../electron-browser/terminal.contribution.ts | 3 + .../electron-browser/terminalInstance.ts | 66 ++----------------- .../terminalInstanceService.ts | 50 ++++++++++++++ .../electron-browser/terminalService.ts | 42 +++++++++++- .../terminal/node/windowsShellHelper.ts | 4 +- 10 files changed, 141 insertions(+), 77 deletions(-) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminal.ts create mode 100644 src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts new file mode 100644 index 00000000000..6fec000ba2d --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Terminal as XTermTerminal } from 'vscode-xterm'; +import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const ITerminalInstanceService = createDecorator('terminalInstanceService'); + +export interface ITerminalInstanceService { + _serviceBrand: any; + + getXtermConstructor(): Promise; + createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper; + createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager; +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ea11c54029c..663829a2683 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -696,7 +696,7 @@ export class RunActiveFileInTerminalAction extends Action { return Promise.resolve(undefined); } - return instance.preparePathForTerminalAsync(uri.fsPath).then(path => { + return this.terminalService.preparePathForTerminalAsync(uri.fsPath, instance.shellLaunchConfig.executable, instance.title).then(path => { instance.sendText(path, true); return this.terminalService.showPanel(); }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 67310672847..b248acd1af3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -302,7 +302,7 @@ export class TerminalPanel extends Panel { const terminal = this._terminalService.getActiveInstance(); if (terminal) { - return terminal.preparePathForTerminalAsync(path).then(preparedPath => { + return this._terminalService.preparePathForTerminalAsync(path, terminal.shellLaunchConfig.executable, terminal.title).then(preparedPath => { terminal.sendText(preparedPath, false); }); } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index a31e4c2c714..c10fdf3a012 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -13,8 +13,6 @@ import { FindReplaceState } from 'vs/editor/contrib/find/findState'; export const TERMINAL_PANEL_ID = 'workbench.panel.terminal'; -export const TERMINAL_SERVICE_ID = 'terminalService'; - /** A context key that is set when there is at least one opened integrated terminal. */ export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('terminalIsOpen', false); /** A context key that is set when the integrated terminal has focus. */ @@ -47,7 +45,7 @@ export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverM // trying to create the corressponding object on the ext host. export const EXT_HOST_CREATION_DELAY = 100; -export const ITerminalService = createDecorator(TERMINAL_SERVICE_ID); +export const ITerminalService = createDecorator('terminalService'); export const TerminalCursorStyle = { BLOCK: 'block', @@ -255,6 +253,17 @@ export interface ITerminalService { selectDefaultWindowsShell(): Promise; setWorkspaceShellAllowed(isAllowed: boolean): void; + /** + * Takes a path and returns the properly escaped path to send to the terminal. + * On Windows, this included trying to prepare the path for WSL if needed. + * + * @param executable The executable off the shellLaunchConfig + * @param title The terminal's title + * @param path The path to be escaped and formatted. + * @returns An escaped version of the path to be execuded in the terminal. + */ + preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; + requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void; } @@ -525,15 +534,6 @@ export interface ITerminalInstance { */ sendText(text: string, addNewLine: boolean): void; - /** - * Takes a path and returns the properly escaped path to send to the terminal. - * On Windows, this included trying to prepare the path for WSL if needed. - * - * @param path The path to be escaped and formatted. - * @returns An escaped version of the path to be execuded in the terminal. - */ - preparePathForTerminalAsync(path: string): Promise; - /** * Write text directly to the terminal, skipping the process if it exists. * @param text The text to write. @@ -693,4 +693,8 @@ export enum LinuxDistro { Fedora, Ubuntu, Unknown -} \ No newline at end of file +} + +export interface IWindowsShellHelper extends IDisposable { + getShellName(): Promise; +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 3d3a3baac49..859f4208b95 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -101,6 +101,7 @@ export abstract class TerminalService implements ITerminalService { public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; + public abstract preparePathForTerminalAsync(path: string, executable: string, title: string): Promise; public createTerminalRenderer(name: string): ITerminalInstance { return this.createTerminal({ name, isRendererOnly: true }); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index e278b7ee47e..a3e9ce8ad5f 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -33,6 +33,8 @@ import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/ter import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstance'; +import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService'; +import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; const quickOpenRegistry = (Registry.as(QuickOpenExtensions.Quickopen)); @@ -291,6 +293,7 @@ configurationRegistry.registerConfiguration({ }); registerSingleton(ITerminalService, TerminalService, true); +registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); (Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( TerminalPanel, diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index 62242b6373e..08845402186 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -25,19 +25,16 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; -import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; -import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/node/terminalProcessManager'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; -import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ISearchOptions, Terminal as XTermTerminal } from 'vscode-xterm'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { getWslPath, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; +import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -151,8 +148,6 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ 'workbench.action.toggleMaximizedPanel' ]; -let Terminal: typeof XTermTerminal; - export class TerminalInstance implements ITerminalInstance { private static readonly EOL_REGEX = /\r?\n/g; @@ -175,7 +170,7 @@ export class TerminalInstance implements ITerminalInstance { private _cols: number; private _rows: number; private _dimensionsOverride: ITerminalDimensions; - private _windowsShellHelper: WindowsShellHelper | undefined; + private _windowsShellHelper: IWindowsShellHelper | undefined; private _xtermReadyPromise: Promise; private _titleReadyPromise: Promise; private _titleReadyComplete: (title: string) => any; @@ -240,6 +235,7 @@ export class TerminalInstance implements ITerminalInstance { private readonly _configHelper: TerminalConfigHelper, private _container: HTMLElement, private _shellLaunchConfig: IShellLaunchConfig, + @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IKeybindingService private readonly _keybindingService: IKeybindingService, @INotificationService private readonly _notificationService: INotificationService, @@ -398,17 +394,7 @@ export class TerminalInstance implements ITerminalInstance { * Create xterm.js instance and attach data listeners. */ protected async _createXterm(): Promise { - if (!Terminal) { - Terminal = (await import('vscode-xterm')).Terminal; - // Enable xterm.js addons - Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/search/search')); - Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/webLinks/webLinks')); - Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/winptyCompat/winptyCompat')); - // Localize strings - Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line'); - Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input'); - Terminal.strings.tooMuchOutput = nls.localize('terminal.integrated.a11yTooMuchOutput', 'Too much output to announce, navigate to rows manually to read'); - } + const Terminal = await this._terminalInstanceService.getXtermConstructor(); const font = this._configHelper.getFont(undefined, true); const config = this._configHelper.config; this._xterm = new Terminal({ @@ -805,44 +791,6 @@ export class TerminalInstance implements ITerminalInstance { } } - public preparePathForTerminalAsync(originalPath: string): Promise { - return new Promise(c => { - const exe = this.shellLaunchConfig.executable; - if (!exe) { - c(originalPath); - return; - } - - const hasSpace = originalPath.indexOf(' ') !== -1; - - const pathBasename = path.basename(exe, '.exe'); - const isPowerShell = pathBasename === 'pwsh' || - this.title === 'pwsh' || - pathBasename === 'powershell' || - this.title === 'powershell'; - - if (isPowerShell && (hasSpace || originalPath.indexOf('\'') !== -1)) { - c(`& '${originalPath.replace(/'/g, '\'\'')}'`); - return; - } - - if (platform.isWindows) { - // 17063 is the build number where wsl path was introduced. - // Update Windows uriPath to be executed in WSL. - if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (getWindowsBuildNumber() >= 17063)) { - c(getWslPath(originalPath)); - return; - } else if (hasSpace) { - c('"' + originalPath + '"'); - } else { - c(originalPath); - } - return; - } - c(escapeNonWindowsPath(originalPath)); - }); - } - public setVisible(visible: boolean): void { this._isVisible = visible; if (this._wrapperElement) { @@ -907,7 +855,7 @@ export class TerminalInstance implements ITerminalInstance { } protected _createProcess(): void { - this._processManager = this._instantiationService.createInstance(TerminalProcessManager, this._id, this._configHelper); + this._processManager = this._terminalInstanceService.createTerminalProcessManager(this._id, this._configHelper); this._processManager.onProcessReady(() => this._onProcessIdReady.fire(this)); this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode)); this._processManager.onProcessData(data => this._onData.fire(data)); @@ -924,7 +872,7 @@ export class TerminalInstance implements ITerminalInstance { this._processManager.ptyProcessReady.then(() => { this._xtermReadyPromise.then(() => { if (!this._isDisposed) { - this._windowsShellHelper = new WindowsShellHelper(this._processManager!.shellProcessId, this, this._xterm); + this._terminalInstanceService.createWindowsShellHelper(this._processManager!.shellProcessId, this, this._xterm); } }); }); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts new file mode 100644 index 00000000000..727e5ab6201 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Terminal as XTermTerminal } from 'vscode-xterm'; +import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal'; +import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/node/terminalProcessManager'; + +let Terminal: typeof XTermTerminal; + +/** + * A service used by TerminalInstance that allows it to break its dependency on electron-browser and + * node layers, while at the same time avoiding a cyclic dependency on ITerminalService. + */ +export class TerminalInstanceService implements ITerminalInstanceService { + public _serviceBrand: any; + + constructor( + @IInstantiationService private readonly _instantiationService: IInstantiationService, + ) { + } + + async getXtermConstructor(): Promise { + if (!Terminal) { + Terminal = (await import('vscode-xterm')).Terminal; + // Enable xterm.js addons + Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/search/search')); + Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/webLinks/webLinks')); + Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/winptyCompat/winptyCompat')); + // Localize strings + Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line'); + Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input'); + Terminal.strings.tooMuchOutput = nls.localize('terminal.integrated.a11yTooMuchOutput', 'Too much output to announce, navigate to rows manually to read'); + } + return Terminal; + } + + createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper { + return new WindowsShellHelper(shellProcessId, instance, xterm); + } + + createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager { + return this._instantiationService.createInstance(TerminalProcessManager, id, configHelper); + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 86451a2b64f..44011e664d2 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -16,7 +16,7 @@ import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfi import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { getDefaultShell, linuxDistro, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; +import { getDefaultShell, linuxDistro, getWindowsBuildNumber, getWslPath } from 'vs/workbench/contrib/terminal/node/terminal'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ipcRenderer as ipc } from 'electron'; @@ -26,6 +26,8 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; import { coalesce } from 'vs/base/common/arrays'; import { IFileService } from 'vs/platform/files/common/files'; +import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; +import { basename } from 'vs/base/common/path'; export class TerminalService extends BrowserTerminalService implements ITerminalService { private _configHelper: TerminalConfigHelper; @@ -143,4 +145,42 @@ export class TerminalService extends BrowserTerminalService implements ITerminal this._terminalContainer = terminalContainer; this._terminalTabs.forEach(tab => tab.attachToElement(this._terminalContainer)); } + + public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { + return new Promise(c => { + const exe = executable; + if (!exe) { + c(originalPath); + return; + } + + const hasSpace = originalPath.indexOf(' ') !== -1; + + const pathBasename = basename(exe, '.exe'); + const isPowerShell = pathBasename === 'pwsh' || + title === 'pwsh' || + pathBasename === 'powershell' || + title === 'powershell'; + + if (isPowerShell && (hasSpace || originalPath.indexOf('\'') !== -1)) { + c(`& '${originalPath.replace(/'/g, '\'\'')}'`); + return; + } + + if (platform.isWindows) { + // 17063 is the build number where wsl path was introduced. + // Update Windows uriPath to be executed in WSL. + if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (getWindowsBuildNumber() >= 17063)) { + c(getWslPath(originalPath)); + return; + } else if (hasSpace) { + c('"' + originalPath + '"'); + } else { + c(originalPath); + } + return; + } + c(escapeNonWindowsPath(originalPath)); + }); + } } diff --git a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts b/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts index 80233f87d4d..d841d023695 100644 --- a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts +++ b/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts @@ -5,7 +5,7 @@ import * as platform from 'vs/base/common/platform'; import { Emitter, Event } from 'vs/base/common/event'; -import { ITerminalInstance } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalInstance, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { Terminal as XTermTerminal } from 'vscode-xterm'; import WindowsProcessTreeType = require('windows-process-tree'); @@ -24,7 +24,7 @@ const SHELL_EXECUTABLES = [ let windowsProcessTree: typeof WindowsProcessTreeType; -export class WindowsShellHelper { +export class WindowsShellHelper implements IWindowsShellHelper { private _onCheckShell: Emitter | undefined>; private _isDisposed: boolean; private _currentRequest: Promise | null; From b5a06ebb62ba322549cf2c1f1c318a6d69ebeefa Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 19:52:20 -0800 Subject: [PATCH 48/88] Move terminalInstance, electron-browser->browser Part of #69115 --- src/tsconfig.strictNullChecks.json | 2 +- .../terminal/{electron-browser => browser}/terminalInstance.ts | 0 .../contrib/terminal/electron-browser/terminal.contribution.ts | 2 +- .../contrib/terminal/electron-browser/terminalService.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/vs/workbench/contrib/terminal/{electron-browser => browser}/terminalInstance.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 4db865ea10a..b1be79b7e9f 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -282,6 +282,7 @@ "./vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts", "./vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/browser/terminalFindWidget.ts", + "./vs/workbench/contrib/terminal/browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", "./vs/workbench/contrib/terminal/browser/terminalPanel.ts", "./vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts", @@ -293,7 +294,6 @@ "./vs/workbench/contrib/terminal/common/terminalEnvironment.ts", "./vs/workbench/contrib/terminal/common/terminalMenu.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", - "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalProcess.ts", "./vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts rename to src/vs/workbench/contrib/terminal/browser/terminalInstance.ts diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index a3e9ce8ad5f..d4cec6691ce 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -32,7 +32,7 @@ import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPan import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; -import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstance'; +import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 44011e664d2..2db2dcb3272 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -21,7 +21,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ipcRenderer as ipc } from 'electron'; import { IOpenFileRequest, IWindowService } from 'vs/platform/windows/common/windows'; -import { TerminalInstance } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstance'; +import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; import { coalesce } from 'vs/base/common/arrays'; From 03f23ddbc6fb37fcaba2877281c2593d05f24065 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 19:55:42 -0800 Subject: [PATCH 49/88] Remove duplicate getWindowsBuildNumber definitions --- .../tasks/electron-browser/terminalTaskSystem.ts | 13 ++----------- .../contrib/terminal/node/terminalProcess.ts | 13 ++----------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts index bfaaf9c091a..025c9479cab 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts @@ -9,7 +9,6 @@ import * as Objects from 'vs/base/common/objects'; import * as Types from 'vs/base/common/types'; import * as Platform from 'vs/base/common/platform'; import * as Async from 'vs/base/common/async'; -import * as os from 'os'; import { IStringDictionary, values } from 'vs/base/common/collections'; import { LinkedMap, Touch } from 'vs/base/common/map'; import Severity from 'vs/base/common/severity'; @@ -42,6 +41,7 @@ import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { URI } from 'vs/base/common/uri'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { Schemas } from 'vs/base/common/network'; +import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; interface TerminalData { terminal: ITerminalInstance; @@ -745,7 +745,7 @@ export class TerminalTaskSystem implements ITaskSystem { if (!shellSpecified) { toAdd.push('-Command'); } - } else if ((basename === 'bash.exe') || (basename === 'zsh.exe') || ((basename === 'wsl.exe') && (this.getWindowsBuildNumber() < 17763))) { // See https://github.com/Microsoft/vscode/issues/67855 + } else if ((basename === 'bash.exe') || (basename === 'zsh.exe') || ((basename === 'wsl.exe') && (getWindowsBuildNumber() < 17763))) { // See https://github.com/Microsoft/vscode/issues/67855 windowsShellArgs = false; if (!shellSpecified) { toAdd.push('-c'); @@ -1213,15 +1213,6 @@ export class TerminalTaskSystem implements ITaskSystem { return result; } - private getWindowsBuildNumber(): number { - const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); - let buildNumber: number = 0; - if (osVersion && osVersion.length === 4) { - buildNumber = parseInt(osVersion[3]); - } - return buildNumber; - } - private registerLinkMatchers(terminal: ITerminalInstance, problemMatchers: ProblemMatcher[]): number[] { let result: number[] = []; /* diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index fbebae679ee..4aa6a76b158 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -9,7 +9,7 @@ import * as platform from 'vs/base/common/platform'; import * as pty from 'node-pty'; import * as fs from 'fs'; import { Event, Emitter } from 'vs/base/common/event'; -import { ITerminalChildProcess } from 'vs/workbench/contrib/terminal/node/terminal'; +import { ITerminalChildProcess, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { exec } from 'child_process'; @@ -51,7 +51,7 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { } this._initialCwd = cwd; - const useConpty = windowsEnableConpty && process.platform === 'win32' && this._getWindowsBuildNumber() >= 18309; + const useConpty = windowsEnableConpty && process.platform === 'win32' && getWindowsBuildNumber() >= 18309; const options: pty.IPtyForkOptions = { name: shellName, cwd, @@ -106,15 +106,6 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { this._onProcessTitleChanged.dispose(); } - private _getWindowsBuildNumber(): number { - const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); - let buildNumber: number = 0; - if (osVersion && osVersion.length === 4) { - buildNumber = parseInt(osVersion[3]); - } - return buildNumber; - } - private _setupTitlePolling() { // Send initial timeout async to give event listeners a chance to init setTimeout(() => { From 6d5ab922e68f689e05b39556ef9fbb1220f21db6 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 19:59:25 -0800 Subject: [PATCH 50/88] Move terminalProcessExtHostProxy, node->common --- src/tsconfig.strictNullChecks.json | 2 +- .../contrib/terminal/common/terminal.ts | 24 ++++++++++++++++++ .../terminalProcessExtHostProxy.ts | 3 +-- .../contrib/terminal/node/terminal.ts | 25 ------------------- .../contrib/terminal/node/terminalProcess.ts | 4 +-- .../terminal/node/terminalProcessManager.ts | 5 ++-- 6 files changed, 30 insertions(+), 33 deletions(-) rename src/vs/workbench/contrib/terminal/{node => common}/terminalProcessExtHostProxy.ts (96%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index b1be79b7e9f..13f40695a3c 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -293,10 +293,10 @@ "./vs/workbench/contrib/terminal/common/terminalCommands.ts", "./vs/workbench/contrib/terminal/common/terminalEnvironment.ts", "./vs/workbench/contrib/terminal/common/terminalMenu.ts", + "./vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalProcess.ts", - "./vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts", "./vs/workbench/contrib/terminal/node/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/windowsShellHelper.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts", diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index c10fdf3a012..ec0303a0ea3 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -698,3 +698,27 @@ export enum LinuxDistro { export interface IWindowsShellHelper extends IDisposable { getShellName(): Promise; } + +/** + * An interface representing a raw terminal child process, this contains a subset of the + * child_process.ChildProcess node.js interface. + */ +export interface ITerminalChildProcess { + onProcessData: Event; + onProcessExit: Event; + onProcessIdReady: Event; + onProcessTitleChanged: Event; + + /** + * Shutdown the terminal process. + * + * @param immediate When true the process will be killed immediately, otherwise the process will + * be given some time to make sure no additional data comes through. + */ + shutdown(immediate: boolean): void; + input(data: string): void; + resize(cols: number, rows: number): void; + + getInitialCwd(): Promise; + getCwd(): Promise; +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts similarity index 96% rename from src/vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts rename to src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts index 5eb61629e48..84131aa9edd 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts @@ -3,9 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalChildProcess } from 'vs/workbench/contrib/terminal/node/terminal'; import { Event, Emitter } from 'vs/base/common/event'; -import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; diff --git a/src/vs/workbench/contrib/terminal/node/terminal.ts b/src/vs/workbench/contrib/terminal/node/terminal.ts index a7b76673023..6200b9bf734 100644 --- a/src/vs/workbench/contrib/terminal/node/terminal.ts +++ b/src/vs/workbench/contrib/terminal/node/terminal.ts @@ -7,35 +7,10 @@ import * as os from 'os'; import * as platform from 'vs/base/common/platform'; import * as processes from 'vs/base/node/processes'; import { readFile, fileExists } from 'vs/base/node/pfs'; -import { Event } from 'vs/base/common/event'; import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; import { execFile } from 'child_process'; import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -/** - * An interface representing a raw terminal child process, this contains a subset of the - * child_process.ChildProcess node.js interface. - */ -export interface ITerminalChildProcess { - onProcessData: Event; - onProcessExit: Event; - onProcessIdReady: Event; - onProcessTitleChanged: Event; - - /** - * Shutdown the terminal process. - * - * @param immediate When true the process will be killed immediately, otherwise the process will - * be given some time to make sure no additional data comes through. - */ - shutdown(immediate: boolean): void; - input(data: string): void; - resize(cols: number, rows: number): void; - - getInitialCwd(): Promise; - getCwd(): Promise; -} - export function getDefaultShell(p: platform.Platform): string { if (p === platform.Platform.Windows) { if (platform.isWindows) { diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index 4aa6a76b158..3d40e7ed804 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -9,9 +9,9 @@ import * as platform from 'vs/base/common/platform'; import * as pty from 'node-pty'; import * as fs from 'fs'; import { Event, Emitter } from 'vs/base/common/event'; -import { ITerminalChildProcess, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; +import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; import { exec } from 'child_process'; export class TerminalProcess implements ITerminalChildProcess, IDisposable { diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts index 0a9923779e8..d46fcf801fc 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts @@ -6,12 +6,11 @@ import * as platform from 'vs/base/common/platform'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; import { ILogService } from 'vs/platform/log/common/log'; import { Emitter, Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { ITerminalChildProcess } from 'vs/workbench/contrib/terminal/node/terminal'; -import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/node/terminalProcessExtHostProxy'; +import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; From 437f7f67cb1f8d867a82445e3bdf97f545222675 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 20:10:07 -0800 Subject: [PATCH 51/88] Move TerminalProcessManager, node->browser --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/base/common/processes.ts | 29 ++++++++++++++++ src/vs/base/node/processes.ts | 27 --------------- src/vs/base/test/common/processes.test.ts | 33 +++++++++++++++++++ .../test/node/processes/processes.test.ts | 25 -------------- .../api/node/extHostTerminalService.ts | 2 +- .../contrib/terminal/browser/terminal.ts | 4 ++- .../terminalProcessManager.ts | 9 ++--- .../terminalInstanceService.ts | 21 ++++++++---- 9 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 src/vs/base/test/common/processes.test.ts rename src/vs/workbench/contrib/terminal/{node => browser}/terminalProcessManager.ts (96%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 13f40695a3c..8d70756d2f6 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -285,6 +285,7 @@ "./vs/workbench/contrib/terminal/browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts", "./vs/workbench/contrib/terminal/browser/terminalPanel.ts", + "./vs/workbench/contrib/terminal/browser/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts", "./vs/workbench/contrib/terminal/browser/terminalTab.ts", "./vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts", @@ -297,7 +298,6 @@ "./vs/workbench/contrib/terminal/common/terminalService.ts", "./vs/workbench/contrib/terminal/node/terminal.ts", "./vs/workbench/contrib/terminal/node/terminalProcess.ts", - "./vs/workbench/contrib/terminal/node/terminalProcessManager.ts", "./vs/workbench/contrib/terminal/node/windowsShellHelper.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts", "./vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts", diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts index 7eef74d894f..b42d8e25605 100644 --- a/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IProcessEnvironment } from 'vs/base/common/platform'; + /** * Options to be passed to the external program or shell. */ @@ -84,3 +86,30 @@ export const enum TerminateResponseCode { AccessDenied = 2, ProcessNotFound = 3, } + +/** + * Sanitizes a VS Code process environment by removing all Electron/VS Code-related values. + */ +export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve: string[]): void { + const set = preserve.reduce((set, key) => { + set[key] = true; + return set; + }, {} as Record); + const keysToRemove = [ + /^ELECTRON_.+$/, + /^GOOGLE_API_KEY$/, + /^VSCODE_.+$/, + /^SNAP(|_.*)$/ + ]; + const envKeys = Object.keys(env); + envKeys + .filter(key => !set[key]) + .forEach(envKey => { + for (let i = 0; i < keysToRemove.length; i++) { + if (envKey.search(keysToRemove[i]) !== -1) { + delete env[envKey]; + break; + } + } + }); +} diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index dfaa9042499..9836e6ccfbb 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -72,33 +72,6 @@ export function getWindowsShell(): string { return process.env['comspec'] || 'cmd.exe'; } -/** - * Sanitizes a VS Code process environment by removing all Electron/VS Code-related values. - */ -export function sanitizeProcessEnvironment(env: Platform.IProcessEnvironment, ...preserve: string[]): void { - const set = preserve.reduce((set, key) => { - set[key] = true; - return set; - }, {} as Record); - const keysToRemove = [ - /^ELECTRON_.+$/, - /^GOOGLE_API_KEY$/, - /^VSCODE_.+$/, - /^SNAP(|_.*)$/ - ]; - const envKeys = Object.keys(env); - envKeys - .filter(key => !set[key]) - .forEach(envKey => { - for (let i = 0; i < keysToRemove.length; i++) { - if (envKey.search(keysToRemove[i]) !== -1) { - delete env[envKey]; - break; - } - } - }); -} - export abstract class AbstractProcess { private cmd: string; private args: string[]; diff --git a/src/vs/base/test/common/processes.test.ts b/src/vs/base/test/common/processes.test.ts new file mode 100644 index 00000000000..cd54b6fd724 --- /dev/null +++ b/src/vs/base/test/common/processes.test.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as processes from 'vs/base/common/processes'; + +suite('Processes', () => { + test('sanitizeProcessEnvironment', () => { + let env = { + FOO: 'bar', + ELECTRON_ENABLE_STACK_DUMPING: 'x', + ELECTRON_ENABLE_LOGGING: 'x', + ELECTRON_NO_ASAR: 'x', + ELECTRON_NO_ATTACH_CONSOLE: 'x', + ELECTRON_RUN_AS_NODE: 'x', + GOOGLE_API_KEY: 'x', + VSCODE_CLI: 'x', + VSCODE_DEV: 'x', + VSCODE_IPC_HOOK: 'x', + VSCODE_LOGS: 'x', + VSCODE_NLS_CONFIG: 'x', + VSCODE_PORTABLE: 'x', + VSCODE_PID: 'x', + VSCODE_NODE_CACHED_DATA_DIR: 'x', + VSCODE_NEW_VAR: 'x' + }; + processes.sanitizeProcessEnvironment(env); + assert.equal(env['FOO'], 'bar'); + assert.equal(Object.keys(env).length, 1); + }); +}); diff --git a/src/vs/base/test/node/processes/processes.test.ts b/src/vs/base/test/node/processes/processes.test.ts index 10199cf5bf3..76719506d6e 100644 --- a/src/vs/base/test/node/processes/processes.test.ts +++ b/src/vs/base/test/node/processes/processes.test.ts @@ -84,29 +84,4 @@ suite('Processes', () => { } }); }); - - - test('sanitizeProcessEnvironment', () => { - let env = { - FOO: 'bar', - ELECTRON_ENABLE_STACK_DUMPING: 'x', - ELECTRON_ENABLE_LOGGING: 'x', - ELECTRON_NO_ASAR: 'x', - ELECTRON_NO_ATTACH_CONSOLE: 'x', - ELECTRON_RUN_AS_NODE: 'x', - GOOGLE_API_KEY: 'x', - VSCODE_CLI: 'x', - VSCODE_DEV: 'x', - VSCODE_IPC_HOOK: 'x', - VSCODE_LOGS: 'x', - VSCODE_NLS_CONFIG: 'x', - VSCODE_PORTABLE: 'x', - VSCODE_PID: 'x', - VSCODE_NODE_CACHED_DATA_DIR: 'x', - VSCODE_NEW_VAR: 'x' - }; - processes.sanitizeProcessEnvironment(env); - assert.equal(env['FOO'], 'bar'); - assert.equal(Object.keys(env).length, 1); - }); }); diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 6f80fc77c38..070d8874c22 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -16,7 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { EXT_HOST_CREATION_DELAY } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; import { timeout } from 'vs/base/common/async'; -import { sanitizeProcessEnvironment } from 'vs/base/node/processes'; +import { sanitizeProcessEnvironment } from 'vs/base/common/processes'; const RENDERER_NO_PROCESS_ID = -1; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 6fec000ba2d..23114676b64 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -4,8 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { Terminal as XTermTerminal } from 'vscode-xterm'; -import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IProcessEnvironment } from 'vs/base/common/platform'; export const ITerminalInstanceService = createDecorator('terminalInstanceService'); @@ -15,4 +16,5 @@ export interface ITerminalInstanceService { getXtermConstructor(): Promise; createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper; createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager; + createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess; } diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts similarity index 96% rename from src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts rename to src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index d46fcf801fc..18d6d58d78b 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -12,16 +12,16 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { Schemas } from 'vs/base/common/network'; import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; -import { sanitizeProcessEnvironment } from 'vs/base/node/processes'; +import { sanitizeProcessEnvironment } from 'vs/base/common/processes'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IProductService } from 'vs/platform/product/common/product'; +import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; @@ -63,7 +63,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { @IWindowService private readonly _windowService: IWindowService, @IWorkspaceConfigurationService private readonly _workspaceConfigurationService: IWorkspaceConfigurationService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, - @IProductService private readonly _productService: IProductService + @IProductService private readonly _productService: IProductService, + @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService ) { this.ptyProcessReady = new Promise(c => { this.onProcessReady(() => { @@ -148,7 +149,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { } this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env); - this._process = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty); + this._process = this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty); } this.processState = ProcessState.LAUNCHING; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index 727e5ab6201..d9d128e5f92 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -6,16 +6,19 @@ import * as nls from 'vs/nls'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { Terminal as XTermTerminal } from 'vscode-xterm'; -import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalProcessManager, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/node/terminalProcessManager'; +import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; +import { IProcessEnvironment } from 'vs/base/common/platform'; +import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; let Terminal: typeof XTermTerminal; /** - * A service used by TerminalInstance that allows it to break its dependency on electron-browser and - * node layers, while at the same time avoiding a cyclic dependency on ITerminalService. + * A service used by TerminalInstance (and components owned by it) that allows it to break its + * dependency on electron-browser and node layers, while at the same time avoiding a cyclic + * dependency on ITerminalService. */ export class TerminalInstanceService implements ITerminalInstanceService { public _serviceBrand: any; @@ -25,7 +28,7 @@ export class TerminalInstanceService implements ITerminalInstanceService { ) { } - async getXtermConstructor(): Promise { + public async getXtermConstructor(): Promise { if (!Terminal) { Terminal = (await import('vscode-xterm')).Terminal; // Enable xterm.js addons @@ -40,11 +43,15 @@ export class TerminalInstanceService implements ITerminalInstanceService { return Terminal; } - createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper { + public createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper { return new WindowsShellHelper(shellProcessId, instance, xterm); } - createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager { + public createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager { return this._instantiationService.createInstance(TerminalProcessManager, id, configHelper); } + + public createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess { + return new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty); + } } \ No newline at end of file From ff5ae22403cdf705734d7822c89affca78564688 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 20:22:09 -0800 Subject: [PATCH 52/88] Remove more from electron-browser/terminalService --- .../contrib/terminal/browser/terminal.ts | 4 ++ .../terminal/browser/terminalConfigHelper.ts | 5 +- .../terminal/browser/terminalService.ts | 19 +++++- .../terminal/common/terminalService.ts | 45 ++++++++++++- .../electron-browser/terminalService.ts | 67 +++++-------------- .../contrib/terminal/node/terminal.ts | 17 ----- 6 files changed, 85 insertions(+), 72 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 23114676b64..ff7f6b95f5b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -18,3 +18,7 @@ export interface ITerminalInstanceService { createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager; createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess; } + +export interface IBrowserTerminalConfigHelper extends ITerminalConfigHelper { + panelContainer: HTMLElement; +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index 91a780466ad..f4f0476caa0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -10,10 +10,11 @@ import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/ed import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ITerminalConfiguration, ITerminalConfigHelper, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalConfiguration, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; import Severity from 'vs/base/common/severity'; import { Terminal as XTermTerminal } from 'vscode-xterm'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; const MINIMUM_FONT_SIZE = 6; const MAXIMUM_FONT_SIZE = 25; @@ -22,7 +23,7 @@ const MAXIMUM_FONT_SIZE = 25; * Encapsulates terminal configuration logic, the primary purpose of this file is so that platform * specific test cases can be written. */ -export class TerminalConfigHelper implements ITerminalConfigHelper { +export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { public panelContainer: HTMLElement; private _charMeasureElement: HTMLElement; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 051667c8a67..28a01868122 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -5,9 +5,9 @@ import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; -import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -20,8 +20,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IWindowService } from 'vs/platform/windows/common/windows'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; +import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; +import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; export abstract class TerminalService extends CommonTerminalService implements ITerminalService { + protected _configHelper: IBrowserTerminalConfigHelper; constructor( @IContextKeyService contextKeyService: IContextKeyService, @@ -41,6 +44,12 @@ export abstract class TerminalService extends CommonTerminalService implements I protected abstract _getDefaultShell(p: platform.Platform): string; + public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { + const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); + this._onInstanceCreated.fire(instance); + return instance; + } + public createTerminal(shell: IShellLaunchConfig = {}, wasNewTerminalAction?: boolean): ITerminalInstance { const terminalTab = this._instantiationService.createInstance(TerminalTab, this._terminalFocusContextKey, @@ -157,4 +166,10 @@ export abstract class TerminalService extends CommonTerminalService implements I panel.getFindWidget().find(true); } } + + public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { + this._configHelper.panelContainer = panelContainer; + this._terminalContainer = terminalContainer; + this._terminalTabs.forEach(tab => tab.attachToElement(this._terminalContainer)); + } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 859f4208b95..b2d81641a84 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -17,6 +17,9 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; +import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; +import { isWindows } from 'vs/base/common/platform'; +import { basename } from 'vs/base/common/path'; export abstract class TerminalService implements ITerminalService { public _serviceBrand: any; @@ -97,11 +100,13 @@ export abstract class TerminalService implements ITerminalService { this.onInstancesChanged(() => updateTerminalContextKeys()); } + protected abstract _getWslPath(path: string): Promise; + protected abstract _getWindowsBuildNumber(): number; + public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; - public abstract preparePathForTerminalAsync(path: string, executable: string, title: string): Promise; public createTerminalRenderer(name: string): ITerminalInstance { return this.createTerminal({ name, isRendererOnly: true }); @@ -425,4 +430,42 @@ export abstract class TerminalService implements ITerminalService { return [label, current] as [string, string]; }); } + + public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { + return new Promise(c => { + const exe = executable; + if (!exe) { + c(originalPath); + return; + } + + const hasSpace = originalPath.indexOf(' ') !== -1; + + const pathBasename = basename(exe, '.exe'); + const isPowerShell = pathBasename === 'pwsh' || + title === 'pwsh' || + pathBasename === 'powershell' || + title === 'powershell'; + + if (isPowerShell && (hasSpace || originalPath.indexOf('\'') !== -1)) { + c(`& '${originalPath.replace(/'/g, '\'\'')}'`); + return; + } + + if (isWindows) { + // 17063 is the build number where wsl path was introduced. + // Update Windows uriPath to be executed in WSL. + if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (this._getWindowsBuildNumber() >= 17063)) { + c(this._getWslPath(originalPath)); + return; + } else if (hasSpace) { + c('"' + originalPath + '"'); + } else { + c(originalPath); + } + return; + } + c(escapeNonWindowsPath(originalPath)); + }); + } } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 2db2dcb3272..34dc08eec10 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -6,31 +6,29 @@ import * as nls from 'vs/nls'; import * as pfs from 'vs/base/node/pfs'; import * as platform from 'vs/base/common/platform'; -import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalService as BrowserTerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { getDefaultShell, linuxDistro, getWindowsBuildNumber, getWslPath } from 'vs/workbench/contrib/terminal/node/terminal'; +import { getDefaultShell, linuxDistro, getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ipcRenderer as ipc } from 'electron'; import { IOpenFileRequest, IWindowService } from 'vs/platform/windows/common/windows'; -import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; import { coalesce } from 'vs/base/common/arrays'; import { IFileService } from 'vs/platform/files/common/files'; import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { basename } from 'vs/base/common/path'; +import { execFile } from 'child_process'; export class TerminalService extends BrowserTerminalService implements ITerminalService { - private _configHelper: TerminalConfigHelper; public get configHelper(): ITerminalConfigHelper { return this._configHelper; } constructor( @@ -75,12 +73,6 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { - const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); - this._onInstanceCreated.fire(instance); - return instance; - } - protected _getDefaultShell(p: platform.Platform): string { return getDefaultShell(p); } @@ -140,47 +132,22 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { - this._configHelper.panelContainer = panelContainer; - this._terminalContainer = terminalContainer; - this._terminalTabs.forEach(tab => tab.attachToElement(this._terminalContainer)); + protected _getWindowsBuildNumber(): number { + return getWindowsBuildNumber(); } - public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { + /** + * Converts a path to a path on WSL using the wslpath utility. + * @param path The original path. + */ + protected _getWslPath(path: string): Promise { + if (getWindowsBuildNumber() < 17063) { + throw new Error('wslpath does not exist on Windows build < 17063'); + } return new Promise(c => { - const exe = executable; - if (!exe) { - c(originalPath); - return; - } - - const hasSpace = originalPath.indexOf(' ') !== -1; - - const pathBasename = basename(exe, '.exe'); - const isPowerShell = pathBasename === 'pwsh' || - title === 'pwsh' || - pathBasename === 'powershell' || - title === 'powershell'; - - if (isPowerShell && (hasSpace || originalPath.indexOf('\'') !== -1)) { - c(`& '${originalPath.replace(/'/g, '\'\'')}'`); - return; - } - - if (platform.isWindows) { - // 17063 is the build number where wsl path was introduced. - // Update Windows uriPath to be executed in WSL. - if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (getWindowsBuildNumber() >= 17063)) { - c(getWslPath(originalPath)); - return; - } else if (hasSpace) { - c('"' + originalPath + '"'); - } else { - c(originalPath); - } - return; - } - c(escapeNonWindowsPath(originalPath)); + execFile('bash.exe', ['-c', 'echo $(wslpath ' + escapeNonWindowsPath(path) + ')'], {}, (error, stdout, stderr) => { + c(escapeNonWindowsPath(stdout.trim())); + }); }); } } diff --git a/src/vs/workbench/contrib/terminal/node/terminal.ts b/src/vs/workbench/contrib/terminal/node/terminal.ts index 6200b9bf734..493fad0b833 100644 --- a/src/vs/workbench/contrib/terminal/node/terminal.ts +++ b/src/vs/workbench/contrib/terminal/node/terminal.ts @@ -8,8 +8,6 @@ import * as platform from 'vs/base/common/platform'; import * as processes from 'vs/base/node/processes'; import { readFile, fileExists } from 'vs/base/node/pfs'; import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; -import { execFile } from 'child_process'; -import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; export function getDefaultShell(p: platform.Platform): string { if (p === platform.Platform.Windows) { @@ -84,18 +82,3 @@ export function getWindowsBuildNumber(): number { } return buildNumber; } - -/** - * Converts a path to a path on WSL using the wslpath utility. - * @param path The original path. - */ -export function getWslPath(path: string): Promise { - if (getWindowsBuildNumber() < 17063) { - throw new Error('wslpath does not exist on Windows build < 17063'); - } - return new Promise(c => { - execFile('bash.exe', ['-c', 'echo $(wslpath ' + escapeNonWindowsPath(path) + ')'], {}, (error, stdout, stderr) => { - c(escapeNonWindowsPath(stdout.trim())); - }); - }); -} From 3a10272f1e43a8c4548d7f31704595a3831b2e41 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 4 Mar 2019 20:39:47 -0800 Subject: [PATCH 53/88] Create browser/terminal.contribution.ts --- .../terminal/browser/terminal.contribution.ts | 519 ++++++++++++++++++ .../terminal/browser/terminalFindWidget.ts | 1 - .../electron-browser/terminal.contribution.ts | 511 +---------------- src/vs/workbench/workbench.main.ts | 1 + 4 files changed, 526 insertions(+), 506 deletions(-) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts new file mode 100644 index 00000000000..a420a5355b3 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -0,0 +1,519 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import * as platform from 'vs/base/common/platform'; +import 'vs/css!./media/scrollbar'; +import 'vs/css!./media/terminal'; +import 'vs/css!./media/widgets'; +import 'vs/css!./media/xterm'; +import * as nls from 'vs/nls'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as ActionBarExtensions, IActionBarRegistry, Scope } from 'vs/workbench/browser/actions'; +import * as panel from 'vs/workbench/browser/panel'; +import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; +import { Extensions as QuickOpenExtensions, IQuickOpenRegistry, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; +import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions'; +import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; +import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; +import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle } from 'vs/workbench/contrib/terminal/common/terminal'; +import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; +import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; + +const quickOpenRegistry = (Registry.as(QuickOpenExtensions.Quickopen)); + +const inTerminalsPicker = 'inTerminalPicker'; + +quickOpenRegistry.registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + TerminalPickerHandler, + TerminalPickerHandler.ID, + TERMINAL_PICKER_PREFIX, + inTerminalsPicker, + nls.localize('quickOpen.terminal', "Show All Opened Terminals") + ) +); + +const quickOpenNavigateNextInTerminalPickerId = 'workbench.action.quickOpenNavigateNextInTerminalPicker'; +CommandsRegistry.registerCommand( + { id: quickOpenNavigateNextInTerminalPickerId, handler: getQuickNavigateHandler(quickOpenNavigateNextInTerminalPickerId, true) }); + +const quickOpenNavigatePreviousInTerminalPickerId = 'workbench.action.quickOpenNavigatePreviousInTerminalPicker'; +CommandsRegistry.registerCommand( + { id: quickOpenNavigatePreviousInTerminalPickerId, handler: getQuickNavigateHandler(quickOpenNavigatePreviousInTerminalPickerId, false) }); + + +const configurationRegistry = Registry.as(Extensions.Configuration); +configurationRegistry.registerConfiguration({ + id: 'terminal', + order: 100, + title: nls.localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"), + type: 'object', + properties: { + 'terminal.integrated.shellArgs.linux': { + markdownDescription: nls.localize('terminal.integrated.shellArgs.linux', "The command line arguments to use when on the Linux terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'array', + items: { + type: 'string' + }, + default: [] + }, + 'terminal.integrated.shellArgs.osx': { + markdownDescription: nls.localize('terminal.integrated.shellArgs.osx', "The command line arguments to use when on the macOS terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'array', + items: { + type: 'string' + }, + // Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This + // is the reason terminals on macOS typically run login shells by default which set up + // the environment. See http://unix.stackexchange.com/a/119675/115410 + default: ['-l'] + }, + 'terminal.integrated.shellArgs.windows': { + markdownDescription: nls.localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + 'anyOf': [ + { + type: 'array', + items: { + type: 'string', + markdownDescription: nls.localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).") + }, + }, + { + type: 'string', + markdownDescription: nls.localize('terminal.integrated.shellArgs.windows.string', "The command line arguments in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6) to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).") + } + ], + default: [] + }, + 'terminal.integrated.macOptionIsMeta': { + description: nls.localize('terminal.integrated.macOptionIsMeta', "Controls whether to treat the option key as the meta key in the terminal on macOS."), + type: 'boolean', + default: false + }, + 'terminal.integrated.macOptionClickForcesSelection': { + description: nls.localize('terminal.integrated.macOptionClickForcesSelection', "Controls whether to force selection when using Option+click on macOS. This will force a regular (line) selection and disallow the use of column selection mode. This enables copying and pasting using the regular terminal selection, for example, when mouse mode is enabled in tmux."), + type: 'boolean', + default: false + }, + 'terminal.integrated.copyOnSelection': { + description: nls.localize('terminal.integrated.copyOnSelection', "Controls whether text selected in the terminal will be copied to the clipboard."), + type: 'boolean', + default: false + }, + 'terminal.integrated.drawBoldTextInBrightColors': { + description: nls.localize('terminal.integrated.drawBoldTextInBrightColors', "Controls whether bold text in the terminal will always use the \"bright\" ANSI color variant."), + type: 'boolean', + default: true + }, + 'terminal.integrated.fontFamily': { + markdownDescription: nls.localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to `#editor.fontFamily#`'s value."), + type: 'string' + }, + // TODO: Support font ligatures + // 'terminal.integrated.fontLigatures': { + // 'description': nls.localize('terminal.integrated.fontLigatures', "Controls whether font ligatures are enabled in the terminal."), + // 'type': 'boolean', + // 'default': false + // }, + 'terminal.integrated.fontSize': { + description: nls.localize('terminal.integrated.fontSize', "Controls the font size in pixels of the terminal."), + type: 'number', + default: EDITOR_FONT_DEFAULTS.fontSize + }, + 'terminal.integrated.letterSpacing': { + description: nls.localize('terminal.integrated.letterSpacing', "Controls the letter spacing of the terminal, this is an integer value which represents the amount of additional pixels to add between characters."), + type: 'number', + default: DEFAULT_LETTER_SPACING + }, + 'terminal.integrated.lineHeight': { + description: nls.localize('terminal.integrated.lineHeight', "Controls the line height of the terminal, this number is multiplied by the terminal font size to get the actual line-height in pixels."), + type: 'number', + default: DEFAULT_LINE_HEIGHT + }, + 'terminal.integrated.fontWeight': { + type: 'string', + enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], + description: nls.localize('terminal.integrated.fontWeight', "The font weight to use within the terminal for non-bold text."), + default: 'normal' + }, + 'terminal.integrated.fontWeightBold': { + type: 'string', + enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], + description: nls.localize('terminal.integrated.fontWeightBold', "The font weight to use within the terminal for bold text."), + default: 'bold' + }, + 'terminal.integrated.cursorBlinking': { + description: nls.localize('terminal.integrated.cursorBlinking', "Controls whether the terminal cursor blinks."), + type: 'boolean', + default: false + }, + 'terminal.integrated.cursorStyle': { + description: nls.localize('terminal.integrated.cursorStyle', "Controls the style of terminal cursor."), + enum: [TerminalCursorStyle.BLOCK, TerminalCursorStyle.LINE, TerminalCursorStyle.UNDERLINE], + default: TerminalCursorStyle.BLOCK + }, + 'terminal.integrated.scrollback': { + description: nls.localize('terminal.integrated.scrollback', "Controls the maximum amount of lines the terminal keeps in its buffer."), + type: 'number', + default: 1000 + }, + 'terminal.integrated.setLocaleVariables': { + markdownDescription: nls.localize('terminal.integrated.setLocaleVariables', "Controls whether locale variables are set at startup of the terminal."), + type: 'boolean', + default: true + }, + 'terminal.integrated.rendererType': { + type: 'string', + enum: ['auto', 'canvas', 'dom'], + enumDescriptions: [ + nls.localize('terminal.integrated.rendererType.auto', "Let VS Code guess which renderer to use."), + nls.localize('terminal.integrated.rendererType.canvas', "Use the standard GPU/canvas-based renderer"), + nls.localize('terminal.integrated.rendererType.dom', "Use the fallback DOM-based renderer.") + ], + default: 'auto', + description: nls.localize('terminal.integrated.rendererType', "Controls how the terminal is rendered.") + }, + 'terminal.integrated.rightClickBehavior': { + type: 'string', + enum: ['default', 'copyPaste', 'selectWord'], + enumDescriptions: [ + nls.localize('terminal.integrated.rightClickBehavior.default', "Show the context menu."), + nls.localize('terminal.integrated.rightClickBehavior.copyPaste', "Copy when there is a selection, otherwise paste."), + nls.localize('terminal.integrated.rightClickBehavior.selectWord', "Select the word under the cursor and show the context menu.") + ], + default: platform.isMacintosh ? 'selectWord' : platform.isWindows ? 'copyPaste' : 'default', + description: nls.localize('terminal.integrated.rightClickBehavior', "Controls how terminal reacts to right click.") + }, + 'terminal.integrated.cwd': { + description: nls.localize('terminal.integrated.cwd', "An explicit start path where the terminal will be launched, this is used as the current working directory (cwd) for the shell process. This may be particularly useful in workspace settings if the root directory is not a convenient cwd."), + type: 'string', + default: undefined + }, + 'terminal.integrated.confirmOnExit': { + description: nls.localize('terminal.integrated.confirmOnExit', "Controls whether to confirm on exit if there are active terminal sessions."), + type: 'boolean', + default: false + }, + 'terminal.integrated.enableBell': { + description: nls.localize('terminal.integrated.enableBell', "Controls whether the terminal bell is enabled."), + type: 'boolean', + default: false + }, + 'terminal.integrated.commandsToSkipShell': { + description: nls.localize('terminal.integrated.commandsToSkipShell', "A set of command IDs whose keybindings will not be sent to the shell and instead always be handled by Code. This allows the use of keybindings that would normally be consumed by the shell to act the same as when the terminal is not focused, for example ctrl+p to launch Quick Open.\nDefault Skipped Commands:\n\n{0}", DEFAULT_COMMANDS_TO_SKIP_SHELL.sort().map(command => `- ${command}`).join('\n')), + type: 'array', + items: { + type: 'string' + }, + default: [] + }, + 'terminal.integrated.env.osx': { + markdownDescription: nls.localize('terminal.integrated.env.osx', "Object with environment variables that will be added to the VS Code process to be used by the terminal on macOS. Set to `null` to delete the environment variable."), + type: 'object', + additionalProperties: { + type: ['string', 'null'] + }, + default: {} + }, + 'terminal.integrated.env.linux': { + markdownDescription: nls.localize('terminal.integrated.env.linux', "Object with environment variables that will be added to the VS Code process to be used by the terminal on Linux. Set to `null` to delete the environment variable."), + type: 'object', + additionalProperties: { + type: ['string', 'null'] + }, + default: {} + }, + 'terminal.integrated.env.windows': { + markdownDescription: nls.localize('terminal.integrated.env.windows', "Object with environment variables that will be added to the VS Code process to be used by the terminal on Windows. Set to `null` to delete the environment variable."), + type: 'object', + additionalProperties: { + type: ['string', 'null'] + }, + default: {} + }, + 'terminal.integrated.showExitAlert': { + description: nls.localize('terminal.integrated.showExitAlert', "Controls whether to show the alert \"The terminal process terminated with exit code\" when exit code is non-zero."), + type: 'boolean', + default: true + }, + 'terminal.integrated.splitCwd': { + description: nls.localize('terminal.integrated.splitCwd', "Controls the working directory a split terminal starts with."), + type: 'string', + enum: ['workspaceRoot', 'initial', 'inherited'], + enumDescriptions: [ + nls.localize('terminal.integrated.splitCwd.workspaceRoot', "A new split terminal will use the workspace root as the working directory. In a multi-root workspace a choice for which root folder to use is offered."), + nls.localize('terminal.integrated.splitCwd.initial', "A new split terminal will use the working directory that the parent terminal started with."), + nls.localize('terminal.integrated.splitCwd.inherited', "On macOS and Linux, a new split terminal will use the working directory of the parent terminal. On Windows, this behaves the same as initial."), + ], + default: 'inherited' + }, + 'terminal.integrated.windowsEnableConpty': { + description: nls.localize('terminal.integrated.windowsEnableConpty', "Whether to use ConPTY for Windows terminal process communication (requires Windows 10 build number 18309+). Winpty will be used if this is false."), + type: 'boolean', + default: false + } + } +}); + +const registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenTermAction, QuickOpenTermAction.ID, QuickOpenTermAction.LABEL), 'Terminal: Switch Active Terminal', nls.localize('terminal', "Terminal")); +const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); +actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionTermContributor); + +(Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( + TerminalPanel, + TERMINAL_PANEL_ID, + nls.localize('terminal', "Terminal"), + 'terminal', + 40, + TERMINAL_COMMAND_ID.TOGGLE +)); + +// On mac cmd+` is reserved to cycle between windows, that's why the keybindings use WinCtrl +const category = nls.localize('terminalCategory', "Terminal"); +const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.LABEL), 'Terminal: Kill the Active Terminal Instance', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.KEY_C, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C } +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)), 'Terminal: Copy Selection', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK, + mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_BACKTICK } +}), 'Terminal: Create New Integrated Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearSelectionTerminalAction, ClearSelectionTerminalAction.ID, ClearSelectionTerminalAction.LABEL, { + primary: KeyCode.Escape, + linux: { primary: KeyCode.Escape } +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE)), 'Terminal: Escape selection', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewInActiveWorkspaceTerminalAction, CreateNewInActiveWorkspaceTerminalAction.ID, CreateNewInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (In Active Workspace)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.KEY_V, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }, + // Don't apply to Mac since cmd+v works + mac: { primary: 0 } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { + // Don't use ctrl+a by default as that would override the common go to start + // of prompt shell binding + primary: 0, + // Technically this doesn't need to be here as it will fall back to this + // behavior anyway when handed to xterm.js, having this handled by VS Code + // makes it easier for users to see how it works though. + mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_A } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select All', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunSelectedTextInTerminalAction, RunSelectedTextInTerminalAction.ID, RunSelectedTextInTerminalAction.LABEL), 'Terminal: Run Selected Text In Active Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunActiveFileInTerminalAction, RunActiveFileInTerminalAction.ID, RunActiveFileInTerminalAction.LABEL), 'Terminal: Run Active File In Active Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK, + mac: { primary: KeyMod.WinCtrl | KeyCode.US_BACKTICK } +}), 'View: Toggle Integrated Terminal', nls.localize('viewCategory', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollDownTerminalAction, ScrollDownTerminalAction.ID, ScrollDownTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Down (Line)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollDownPageTerminalAction, ScrollDownPageTerminalAction.ID, ScrollDownPageTerminalAction.LABEL, { + primary: KeyMod.Shift | KeyCode.PageDown, + mac: { primary: KeyCode.PageDown } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Down (Page)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToBottomTerminalAction, ScrollToBottomTerminalAction.ID, ScrollToBottomTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.End, + linux: { primary: KeyMod.Shift | KeyCode.End } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll to Bottom', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollUpTerminalAction, ScrollUpTerminalAction.ID, ScrollUpTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }, +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Up (Line)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollUpPageTerminalAction, ScrollUpPageTerminalAction.ID, ScrollUpPageTerminalAction.LABEL, { + primary: KeyMod.Shift | KeyCode.PageUp, + mac: { primary: KeyCode.PageUp } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Up (Page)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToTopTerminalAction, ScrollToTopTerminalAction.ID, ScrollToTopTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.Home, + linux: { primary: KeyMod.Shift | KeyCode.Home } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll to Top', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearTerminalAction, ClearTerminalAction.ID, ClearTerminalAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_K } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KeybindingWeight.WorkbenchContrib + 1), 'Terminal: Clear', category); +if (platform.isWindows) { + actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectDefaultShellWindowsTerminalAction, SelectDefaultShellWindowsTerminalAction.ID, SelectDefaultShellWindowsTerminalAction.LABEL), 'Terminal: Select Default Shell', category); +} +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(AllowWorkspaceShellTerminalCommand, AllowWorkspaceShellTerminalCommand.ID, AllowWorkspaceShellTerminalCommand.LABEL), 'Terminal: Allow Workspace Shell Configuration', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisallowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand.ID, DisallowWorkspaceShellTerminalCommand.LABEL), 'Terminal: Disallow Workspace Shell Configuration', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RenameTerminalAction, RenameTerminalAction.ID, RenameTerminalAction.LABEL), 'Terminal: Rename', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.KEY_F +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Find Widget', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.KEY_F +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Focus Find Widget', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(HideTerminalFindWidgetAction, HideTerminalFindWidgetAction.ID, HideTerminalFindWidgetAction.LABEL, { + primary: KeyCode.Escape, + secondary: [KeyMod.Shift | KeyCode.Escape] +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Hide Find Widget', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordLeftTerminalAction, DeleteWordLeftTerminalAction.ID, DeleteWordLeftTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.Backspace, + mac: { primary: KeyMod.Alt | KeyCode.Backspace } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Left', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordRightTerminalAction, DeleteWordRightTerminalAction.ID, DeleteWordRightTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.Delete, + mac: { primary: KeyMod.Alt | KeyCode.Delete } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Right', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteToLineStartTerminalAction, DeleteToLineStartTerminalAction.ID, DeleteToLineStartTerminalAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete To Line Start', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineStartTerminalAction, MoveToLineStartTerminalAction.ID, MoveToLineStartTerminalAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line Start', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineEndTerminalAction, MoveToLineEndTerminalAction.ID, MoveToLineEndTerminalAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line End', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, + secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5], + mac: { + primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5] + } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Split', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitInActiveWorkspaceTerminalAction, SplitInActiveWorkspaceTerminalAction.ID, SplitInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Split Terminal (In Active Workspace)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousPaneTerminalAction, FocusPreviousPaneTerminalAction.ID, FocusPreviousPaneTerminalAction.LABEL, { + primary: KeyMod.Alt | KeyCode.LeftArrow, + secondary: [KeyMod.Alt | KeyCode.UpArrow], + mac: { + primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.LeftArrow, + secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.UpArrow] + } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Previous Pane', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextPaneTerminalAction, FocusNextPaneTerminalAction.ID, FocusNextPaneTerminalAction.LABEL, { + primary: KeyMod.Alt | KeyCode.RightArrow, + secondary: [KeyMod.Alt | KeyCode.DownArrow], + mac: { + primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.RightArrow, + secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.DownArrow] + } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Next Pane', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneLeftTerminalAction, ResizePaneLeftTerminalAction.ID, ResizePaneLeftTerminalAction.LABEL, { + primary: 0, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow }, + mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Left', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneRightTerminalAction, ResizePaneRightTerminalAction.ID, ResizePaneRightTerminalAction.LABEL, { + primary: 0, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow }, + mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Right', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, { + primary: 0, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }, + mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Up', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, { + primary: 0, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }, + mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Down', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToPreviousCommandAction, ScrollToPreviousCommandAction.ID, ScrollToPreviousCommandAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll To Previous Command', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToNextCommandAction, ScrollToNextCommandAction.ID, ScrollToNextCommandAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll To Next Command', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousCommandAction, SelectToPreviousCommandAction.ID, SelectToPreviousCommandAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Previous Command', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextCommandAction, SelectToNextCommandAction.ID, SelectToNextCommandAction.LABEL, { + primary: 0, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { + primary: KeyMod.Alt | KeyCode.KEY_R, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find by regex'); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID_TERMINAL_FOCUS, ToggleRegexCommand.LABEL, { + primary: KeyMod.Alt | KeyCode.KEY_R, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find by regex', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { + primary: KeyMod.Alt | KeyCode.KEY_W, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find whole word'); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID_TERMINAL_FOCUS, ToggleWholeWordCommand.LABEL, { + primary: KeyMod.Alt | KeyCode.KEY_W, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find whole word', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { + primary: KeyMod.Alt | KeyCode.KEY_C, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find match case'); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID_TERMINAL_FOCUS, ToggleCaseSensitiveCommand.LABEL, { + primary: KeyMod.Alt | KeyCode.KEY_C, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find match case', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID_TERMINAL_FOCUS, FindNext.LABEL, { + primary: KeyCode.F3, + mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, { + primary: KeyCode.F3, + mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] } +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next'); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, { + primary: KeyMod.Shift | KeyCode.F3, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { + primary: KeyMod.Shift | KeyCode.F3, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous'); + + +const sendSequenceTerminalCommand = new SendSequenceTerminalCommand({ + id: SendSequenceTerminalCommand.ID, + precondition: null, + description: { + description: `Send Custom Sequence To Terminal`, + args: [{ + name: 'args', + schema: { + 'type': 'object', + 'required': ['text'], + 'properties': { + 'text': { + 'type': 'string' + } + }, + } + }] + } +}); +sendSequenceTerminalCommand.register(); + +setupTerminalCommands(); +setupTerminalMenu(); + +registerColors(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index e5a54d0ba74..db30d122c39 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./terminalFindWidget'; import { SimpleFindWidget } from 'vs/editor/contrib/find/simpleFindWidget'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index d4cec6691ce..a55b93caa40 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -3,66 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!../browser/media/scrollbar'; -import 'vs/css!../browser/media/terminal'; -import 'vs/css!../browser/media/xterm'; -import 'vs/css!../browser/media/widgets'; -import * as nls from 'vs/nls'; -import * as panel from 'vs/workbench/browser/panel'; import * as platform from 'vs/base/common/platform'; +import * as nls from 'vs/nls'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TerminalCursorStyle, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, DEFAULT_LINE_HEIGHT, DEFAULT_LETTER_SPACING, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; -import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { ClearSelectionTerminalAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, MoveToLineStartTerminalAction, MoveToLineEndTerminalAction, SplitTerminalAction, SplitInActiveWorkspaceTerminalAction, FocusPreviousPaneTerminalAction, FocusNextPaneTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, ResizePaneDownTerminalAction, ScrollToPreviousCommandAction, ScrollToNextCommandAction, SelectToPreviousCommandAction, SelectToNextCommandAction, SelectToPreviousLineAction, SelectToNextLineAction, ToggleEscapeSequenceLoggingAction, SendSequenceTerminalCommand, ToggleRegexCommand, ToggleWholeWordCommand, ToggleCaseSensitiveCommand, FindNext, FindPrevious, DeleteToLineStartTerminalAction, TERMINAL_PICKER_PREFIX, KillTerminalAction, CopyTerminalSelectionAction, SelectAllTerminalAction, ToggleTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { TerminalService } from 'vs/workbench/contrib/terminal/electron-browser/terminalService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; -import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; -import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; -import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; -import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; -import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; -import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; -import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; -import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; -import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService'; +import { Registry } from 'vs/platform/registry/common/platform'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; - -const quickOpenRegistry = (Registry.as(QuickOpenExtensions.Quickopen)); - -const inTerminalsPicker = 'inTerminalPicker'; - -quickOpenRegistry.registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - TerminalPickerHandler, - TerminalPickerHandler.ID, - TERMINAL_PICKER_PREFIX, - inTerminalsPicker, - nls.localize('quickOpen.terminal', "Show All Opened Terminals") - ) -); - -const quickOpenNavigateNextInTerminalPickerId = 'workbench.action.quickOpenNavigateNextInTerminalPicker'; -CommandsRegistry.registerCommand( - { id: quickOpenNavigateNextInTerminalPickerId, handler: getQuickNavigateHandler(quickOpenNavigateNextInTerminalPickerId, true) }); - -const quickOpenNavigatePreviousInTerminalPickerId = 'workbench.action.quickOpenNavigatePreviousInTerminalPicker'; -CommandsRegistry.registerCommand( - { id: quickOpenNavigatePreviousInTerminalPickerId, handler: getQuickNavigateHandler(quickOpenNavigatePreviousInTerminalPickerId, false) }); - - -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenTermAction, QuickOpenTermAction.ID, QuickOpenTermAction.LABEL), 'Terminal: Switch Active Terminal', nls.localize('terminal', "Terminal")); -const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); -actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionTermContributor); +import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService'; +import { TerminalService } from 'vs/workbench/contrib/terminal/electron-browser/terminalService'; +import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; const configurationRegistry = Registry.as(Extensions.Configuration); configurationRegistry.registerConfiguration({ @@ -76,467 +26,18 @@ configurationRegistry.registerConfiguration({ type: 'string', default: getDefaultShell(platform.Platform.Linux) }, - 'terminal.integrated.shellArgs.linux': { - markdownDescription: nls.localize('terminal.integrated.shellArgs.linux', "The command line arguments to use when on the Linux terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), - type: 'array', - items: { - type: 'string' - }, - default: [] - }, 'terminal.integrated.shell.osx': { markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), type: 'string', default: getDefaultShell(platform.Platform.Mac) }, - 'terminal.integrated.shellArgs.osx': { - markdownDescription: nls.localize('terminal.integrated.shellArgs.osx', "The command line arguments to use when on the macOS terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), - type: 'array', - items: { - type: 'string' - }, - // Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This - // is the reason terminals on macOS typically run login shells by default which set up - // the environment. See http://unix.stackexchange.com/a/119675/115410 - default: ['-l'] - }, 'terminal.integrated.shell.windows': { markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), type: 'string', default: getDefaultShell(platform.Platform.Windows) - }, - 'terminal.integrated.shellArgs.windows': { - markdownDescription: nls.localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), - 'anyOf': [ - { - type: 'array', - items: { - type: 'string', - markdownDescription: nls.localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).") - }, - }, - { - type: 'string', - markdownDescription: nls.localize('terminal.integrated.shellArgs.windows.string', "The command line arguments in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6) to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).") - } - ], - default: [] - }, - 'terminal.integrated.macOptionIsMeta': { - description: nls.localize('terminal.integrated.macOptionIsMeta', "Controls whether to treat the option key as the meta key in the terminal on macOS."), - type: 'boolean', - default: false - }, - 'terminal.integrated.macOptionClickForcesSelection': { - description: nls.localize('terminal.integrated.macOptionClickForcesSelection', "Controls whether to force selection when using Option+click on macOS. This will force a regular (line) selection and disallow the use of column selection mode. This enables copying and pasting using the regular terminal selection, for example, when mouse mode is enabled in tmux."), - type: 'boolean', - default: false - }, - 'terminal.integrated.copyOnSelection': { - description: nls.localize('terminal.integrated.copyOnSelection', "Controls whether text selected in the terminal will be copied to the clipboard."), - type: 'boolean', - default: false - }, - 'terminal.integrated.drawBoldTextInBrightColors': { - description: nls.localize('terminal.integrated.drawBoldTextInBrightColors', "Controls whether bold text in the terminal will always use the \"bright\" ANSI color variant."), - type: 'boolean', - default: true - }, - 'terminal.integrated.fontFamily': { - markdownDescription: nls.localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to `#editor.fontFamily#`'s value."), - type: 'string' - }, - // TODO: Support font ligatures - // 'terminal.integrated.fontLigatures': { - // 'description': nls.localize('terminal.integrated.fontLigatures', "Controls whether font ligatures are enabled in the terminal."), - // 'type': 'boolean', - // 'default': false - // }, - 'terminal.integrated.fontSize': { - description: nls.localize('terminal.integrated.fontSize', "Controls the font size in pixels of the terminal."), - type: 'number', - default: EDITOR_FONT_DEFAULTS.fontSize - }, - 'terminal.integrated.letterSpacing': { - description: nls.localize('terminal.integrated.letterSpacing', "Controls the letter spacing of the terminal, this is an integer value which represents the amount of additional pixels to add between characters."), - type: 'number', - default: DEFAULT_LETTER_SPACING - }, - 'terminal.integrated.lineHeight': { - description: nls.localize('terminal.integrated.lineHeight', "Controls the line height of the terminal, this number is multiplied by the terminal font size to get the actual line-height in pixels."), - type: 'number', - default: DEFAULT_LINE_HEIGHT - }, - 'terminal.integrated.fontWeight': { - type: 'string', - enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], - description: nls.localize('terminal.integrated.fontWeight', "The font weight to use within the terminal for non-bold text."), - default: 'normal' - }, - 'terminal.integrated.fontWeightBold': { - type: 'string', - enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], - description: nls.localize('terminal.integrated.fontWeightBold', "The font weight to use within the terminal for bold text."), - default: 'bold' - }, - 'terminal.integrated.cursorBlinking': { - description: nls.localize('terminal.integrated.cursorBlinking', "Controls whether the terminal cursor blinks."), - type: 'boolean', - default: false - }, - 'terminal.integrated.cursorStyle': { - description: nls.localize('terminal.integrated.cursorStyle', "Controls the style of terminal cursor."), - enum: [TerminalCursorStyle.BLOCK, TerminalCursorStyle.LINE, TerminalCursorStyle.UNDERLINE], - default: TerminalCursorStyle.BLOCK - }, - 'terminal.integrated.scrollback': { - description: nls.localize('terminal.integrated.scrollback', "Controls the maximum amount of lines the terminal keeps in its buffer."), - type: 'number', - default: 1000 - }, - 'terminal.integrated.setLocaleVariables': { - markdownDescription: nls.localize('terminal.integrated.setLocaleVariables', "Controls whether locale variables are set at startup of the terminal."), - type: 'boolean', - default: true - }, - 'terminal.integrated.rendererType': { - type: 'string', - enum: ['auto', 'canvas', 'dom'], - enumDescriptions: [ - nls.localize('terminal.integrated.rendererType.auto', "Let VS Code guess which renderer to use."), - nls.localize('terminal.integrated.rendererType.canvas', "Use the standard GPU/canvas-based renderer"), - nls.localize('terminal.integrated.rendererType.dom', "Use the fallback DOM-based renderer.") - ], - default: 'auto', - description: nls.localize('terminal.integrated.rendererType', "Controls how the terminal is rendered.") - }, - 'terminal.integrated.rightClickBehavior': { - type: 'string', - enum: ['default', 'copyPaste', 'selectWord'], - enumDescriptions: [ - nls.localize('terminal.integrated.rightClickBehavior.default', "Show the context menu."), - nls.localize('terminal.integrated.rightClickBehavior.copyPaste', "Copy when there is a selection, otherwise paste."), - nls.localize('terminal.integrated.rightClickBehavior.selectWord', "Select the word under the cursor and show the context menu.") - ], - default: platform.isMacintosh ? 'selectWord' : platform.isWindows ? 'copyPaste' : 'default', - description: nls.localize('terminal.integrated.rightClickBehavior', "Controls how terminal reacts to right click.") - }, - 'terminal.integrated.cwd': { - description: nls.localize('terminal.integrated.cwd', "An explicit start path where the terminal will be launched, this is used as the current working directory (cwd) for the shell process. This may be particularly useful in workspace settings if the root directory is not a convenient cwd."), - type: 'string', - default: undefined - }, - 'terminal.integrated.confirmOnExit': { - description: nls.localize('terminal.integrated.confirmOnExit', "Controls whether to confirm on exit if there are active terminal sessions."), - type: 'boolean', - default: false - }, - 'terminal.integrated.enableBell': { - description: nls.localize('terminal.integrated.enableBell', "Controls whether the terminal bell is enabled."), - type: 'boolean', - default: false - }, - 'terminal.integrated.commandsToSkipShell': { - description: nls.localize('terminal.integrated.commandsToSkipShell', "A set of command IDs whose keybindings will not be sent to the shell and instead always be handled by Code. This allows the use of keybindings that would normally be consumed by the shell to act the same as when the terminal is not focused, for example ctrl+p to launch Quick Open.\nDefault Skipped Commands:\n\n{0}", DEFAULT_COMMANDS_TO_SKIP_SHELL.sort().map(command => `- ${command}`).join('\n')), - type: 'array', - items: { - type: 'string' - }, - default: [] - }, - 'terminal.integrated.env.osx': { - markdownDescription: nls.localize('terminal.integrated.env.osx', "Object with environment variables that will be added to the VS Code process to be used by the terminal on macOS. Set to `null` to delete the environment variable."), - type: 'object', - additionalProperties: { - type: ['string', 'null'] - }, - default: {} - }, - 'terminal.integrated.env.linux': { - markdownDescription: nls.localize('terminal.integrated.env.linux', "Object with environment variables that will be added to the VS Code process to be used by the terminal on Linux. Set to `null` to delete the environment variable."), - type: 'object', - additionalProperties: { - type: ['string', 'null'] - }, - default: {} - }, - 'terminal.integrated.env.windows': { - markdownDescription: nls.localize('terminal.integrated.env.windows', "Object with environment variables that will be added to the VS Code process to be used by the terminal on Windows. Set to `null` to delete the environment variable."), - type: 'object', - additionalProperties: { - type: ['string', 'null'] - }, - default: {} - }, - 'terminal.integrated.showExitAlert': { - description: nls.localize('terminal.integrated.showExitAlert', "Controls whether to show the alert \"The terminal process terminated with exit code\" when exit code is non-zero."), - type: 'boolean', - default: true - }, - 'terminal.integrated.splitCwd': { - description: nls.localize('terminal.integrated.splitCwd', "Controls the working directory a split terminal starts with."), - type: 'string', - enum: ['workspaceRoot', 'initial', 'inherited'], - enumDescriptions: [ - nls.localize('terminal.integrated.splitCwd.workspaceRoot', "A new split terminal will use the workspace root as the working directory. In a multi-root workspace a choice for which root folder to use is offered."), - nls.localize('terminal.integrated.splitCwd.initial', "A new split terminal will use the working directory that the parent terminal started with."), - nls.localize('terminal.integrated.splitCwd.inherited', "On macOS and Linux, a new split terminal will use the working directory of the parent terminal. On Windows, this behaves the same as initial."), - ], - default: 'inherited' - }, - 'terminal.integrated.windowsEnableConpty': { - description: nls.localize('terminal.integrated.windowsEnableConpty', "Whether to use ConPTY for Windows terminal process communication (requires Windows 10 build number 18309+). Winpty will be used if this is false."), - type: 'boolean', - default: false } } }); registerSingleton(ITerminalService, TerminalService, true); registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); - -(Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( - TerminalPanel, - TERMINAL_PANEL_ID, - nls.localize('terminal', "Terminal"), - 'terminal', - 40, - TERMINAL_COMMAND_ID.TOGGLE -)); - -// On mac cmd+` is reserved to cycle between windows, that's why the keybindings use WinCtrl -const category = nls.localize('terminalCategory', "Terminal"); -const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.LABEL), 'Terminal: Kill the Active Terminal Instance', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.KEY_C, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C } -}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)), 'Terminal: Copy Selection', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_BACKTICK } -}), 'Terminal: Create New Integrated Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearSelectionTerminalAction, ClearSelectionTerminalAction.ID, ClearSelectionTerminalAction.LABEL, { - primary: KeyCode.Escape, - linux: { primary: KeyCode.Escape } -}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE)), 'Terminal: Escape selection', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewInActiveWorkspaceTerminalAction, CreateNewInActiveWorkspaceTerminalAction.ID, CreateNewInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (In Active Workspace)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.KEY_V, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }, - // Don't apply to Mac since cmd+v works - mac: { primary: 0 } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { - // Don't use ctrl+a by default as that would override the common go to start - // of prompt shell binding - primary: 0, - // Technically this doesn't need to be here as it will fall back to this - // behavior anyway when handed to xterm.js, having this handled by VS Code - // makes it easier for users to see how it works though. - mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_A } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select All', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunSelectedTextInTerminalAction, RunSelectedTextInTerminalAction.ID, RunSelectedTextInTerminalAction.LABEL), 'Terminal: Run Selected Text In Active Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunActiveFileInTerminalAction, RunActiveFileInTerminalAction.ID, RunActiveFileInTerminalAction.LABEL), 'Terminal: Run Active File In Active Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK, - mac: { primary: KeyMod.WinCtrl | KeyCode.US_BACKTICK } -}), 'View: Toggle Integrated Terminal', nls.localize('viewCategory', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollDownTerminalAction, ScrollDownTerminalAction.ID, ScrollDownTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Down (Line)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollDownPageTerminalAction, ScrollDownPageTerminalAction.ID, ScrollDownPageTerminalAction.LABEL, { - primary: KeyMod.Shift | KeyCode.PageDown, - mac: { primary: KeyCode.PageDown } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Down (Page)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToBottomTerminalAction, ScrollToBottomTerminalAction.ID, ScrollToBottomTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.End, - linux: { primary: KeyMod.Shift | KeyCode.End } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll to Bottom', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollUpTerminalAction, ScrollUpTerminalAction.ID, ScrollUpTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }, -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Up (Line)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollUpPageTerminalAction, ScrollUpPageTerminalAction.ID, ScrollUpPageTerminalAction.LABEL, { - primary: KeyMod.Shift | KeyCode.PageUp, - mac: { primary: KeyCode.PageUp } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll Up (Page)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToTopTerminalAction, ScrollToTopTerminalAction.ID, ScrollToTopTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.Home, - linux: { primary: KeyMod.Shift | KeyCode.Home } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll to Top', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearTerminalAction, ClearTerminalAction.ID, ClearTerminalAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_K } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KeybindingWeight.WorkbenchContrib + 1), 'Terminal: Clear', category); -if (platform.isWindows) { - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectDefaultShellWindowsTerminalAction, SelectDefaultShellWindowsTerminalAction.ID, SelectDefaultShellWindowsTerminalAction.LABEL), 'Terminal: Select Default Shell', category); -} -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(AllowWorkspaceShellTerminalCommand, AllowWorkspaceShellTerminalCommand.ID, AllowWorkspaceShellTerminalCommand.LABEL), 'Terminal: Allow Workspace Shell Configuration', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisallowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand.ID, DisallowWorkspaceShellTerminalCommand.LABEL), 'Terminal: Disallow Workspace Shell Configuration', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RenameTerminalAction, RenameTerminalAction.ID, RenameTerminalAction.LABEL), 'Terminal: Rename', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.KEY_F -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Find Widget', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFindWidgetAction, FocusTerminalFindWidgetAction.ID, FocusTerminalFindWidgetAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.KEY_F -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Focus Find Widget', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(HideTerminalFindWidgetAction, HideTerminalFindWidgetAction.ID, HideTerminalFindWidgetAction.LABEL, { - primary: KeyCode.Escape, - secondary: [KeyMod.Shift | KeyCode.Escape] -}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Hide Find Widget', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordLeftTerminalAction, DeleteWordLeftTerminalAction.ID, DeleteWordLeftTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.Backspace, - mac: { primary: KeyMod.Alt | KeyCode.Backspace } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Left', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordRightTerminalAction, DeleteWordRightTerminalAction.ID, DeleteWordRightTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.Delete, - mac: { primary: KeyMod.Alt | KeyCode.Delete } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Right', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteToLineStartTerminalAction, DeleteToLineStartTerminalAction.ID, DeleteToLineStartTerminalAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete To Line Start', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineStartTerminalAction, MoveToLineStartTerminalAction.ID, MoveToLineStartTerminalAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line Start', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineEndTerminalAction, MoveToLineEndTerminalAction.ID, MoveToLineEndTerminalAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line End', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, - secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5], - mac: { - primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, - secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5] - } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Split', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitInActiveWorkspaceTerminalAction, SplitInActiveWorkspaceTerminalAction.ID, SplitInActiveWorkspaceTerminalAction.LABEL), 'Terminal: Split Terminal (In Active Workspace)', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousPaneTerminalAction, FocusPreviousPaneTerminalAction.ID, FocusPreviousPaneTerminalAction.LABEL, { - primary: KeyMod.Alt | KeyCode.LeftArrow, - secondary: [KeyMod.Alt | KeyCode.UpArrow], - mac: { - primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.LeftArrow, - secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.UpArrow] - } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Previous Pane', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextPaneTerminalAction, FocusNextPaneTerminalAction.ID, FocusNextPaneTerminalAction.LABEL, { - primary: KeyMod.Alt | KeyCode.RightArrow, - secondary: [KeyMod.Alt | KeyCode.DownArrow], - mac: { - primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.RightArrow, - secondary: [KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.DownArrow] - } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Next Pane', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneLeftTerminalAction, ResizePaneLeftTerminalAction.ID, ResizePaneLeftTerminalAction.LABEL, { - primary: 0, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow }, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Left', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneRightTerminalAction, ResizePaneRightTerminalAction.ID, ResizePaneRightTerminalAction.LABEL, { - primary: 0, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow }, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Right', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, { - primary: 0, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Up', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, { - primary: 0, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Down', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToPreviousCommandAction, ScrollToPreviousCommandAction.ID, ScrollToPreviousCommandAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll To Previous Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToNextCommandAction, ScrollToNextCommandAction.ID, ScrollToNextCommandAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Scroll To Next Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousCommandAction, SelectToPreviousCommandAction.ID, SelectToPreviousCommandAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Previous Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextCommandAction, SelectToNextCommandAction.ID, SelectToNextCommandAction.LABEL, { - primary: 0, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { - primary: KeyMod.Alt | KeyCode.KEY_R, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find by regex'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID_TERMINAL_FOCUS, ToggleRegexCommand.LABEL, { - primary: KeyMod.Alt | KeyCode.KEY_R, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find by regex', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { - primary: KeyMod.Alt | KeyCode.KEY_W, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find whole word'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID_TERMINAL_FOCUS, ToggleWholeWordCommand.LABEL, { - primary: KeyMod.Alt | KeyCode.KEY_W, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find whole word', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { - primary: KeyMod.Alt | KeyCode.KEY_C, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find match case'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID_TERMINAL_FOCUS, ToggleCaseSensitiveCommand.LABEL, { - primary: KeyMod.Alt | KeyCode.KEY_C, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find match case', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID_TERMINAL_FOCUS, FindNext.LABEL, { - primary: KeyCode.F3, - mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, { - primary: KeyCode.F3, - mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, { - primary: KeyMod.Shift | KeyCode.F3, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { - primary: KeyMod.Shift | KeyCode.F3, - mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous'); - - -const sendSequenceTerminalCommand = new SendSequenceTerminalCommand({ - id: SendSequenceTerminalCommand.ID, - precondition: null, - description: { - description: `Send Custom Sequence To Terminal`, - args: [{ - name: 'args', - schema: { - 'type': 'object', - 'required': ['text'], - 'properties': { - 'text': { - 'type': 'string' - } - }, - } - }] - } -}); -sendSequenceTerminalCommand.register(); - -setupTerminalCommands(); -setupTerminalMenu(); - -registerColors(); diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 84ed6ce8f02..69bf6bcd8ce 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -152,6 +152,7 @@ import 'vs/workbench/contrib/output/electron-browser/output.contribution'; import 'vs/workbench/contrib/output/browser/outputPanel'; // Terminal +import 'vs/workbench/contrib/terminal/browser/terminal.contribution'; import 'vs/workbench/contrib/terminal/electron-browser/terminal.contribution'; import 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; import 'vs/workbench/contrib/terminal/browser/terminalPanel'; From 31f6902afdc791513bb57f3fc4d9cf5aac2f7b8e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 09:42:23 +0100 Subject: [PATCH 54/88] exploration - auto release after build --- build/azure-pipelines/common/publish.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/build/azure-pipelines/common/publish.ts b/build/azure-pipelines/common/publish.ts index 2095c2d2532..ef17c3fd685 100644 --- a/build/azure-pipelines/common/publish.ts +++ b/build/azure-pipelines/common/publish.ts @@ -152,9 +152,13 @@ async function publish(commit: string, quality: string, platform: string, type: const queuedBy = process.env['BUILD_QUEUEDBY']!; const sourceBranch = process.env['BUILD_SOURCEBRANCH']!; - const isReleased = quality === 'insider' - && /^master$|^refs\/heads\/master$/.test(sourceBranch) - && /Project Collection Service Accounts|Microsoft.VisualStudio.Services.TFS/.test(queuedBy); + const isReleased = ( + // Insiders: nightly build from master + (quality === 'insider' && /^master$|^refs\/heads\/master$/.test(sourceBranch) && /Project Collection Service Accounts|Microsoft.VisualStudio.Services.TFS/.test(queuedBy)) || + + // Exploration: any build from electron-4.0.x branch + (quality === 'exploration' && /^electron-4.0.x$|^refs\/heads\/electron-4.0.x$/.test(sourceBranch)) + ); console.log('Publishing...'); console.log('Quality:', quality); From 3f68665c306be9a04decb12f2bbbc51b5317190a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 09:39:45 +0100 Subject: [PATCH 55/88] strict null - contrib/outline --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/workbench/contrib/outline/browser/outlinePanel.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 8d70756d2f6..1c3308561b0 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -16,6 +16,7 @@ "./vs/workbench/contrib/emmet/**/*", "./vs/workbench/contrib/externalTerminal/**/*", "./vs/workbench/contrib/snippets/**/*.ts", + "./vs/workbench/contrib/outline/**/*.ts", "./vs/workbench/contrib/welcome/**/*.ts", "./vs/workbench/contrib/issue/**/*", "./vs/workbench/contrib/tasks/**/*.ts", @@ -277,7 +278,6 @@ "./vs/workbench/contrib/stats/test/workspaceStats.test.ts", "./vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution.ts", "./vs/workbench/contrib/surveys/electron-browser/nps.contribution.ts", - "./vs/workbench/contrib/terminal/browser/terminalActions.ts", "./vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts", "./vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts", diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 86d3df7c5ea..d6d2c3f39fc 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -47,6 +47,7 @@ import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirt import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { basename } from 'vs/base/common/resources'; +import { IDataSource } from 'vs/base/browser/ui/tree/tree'; class RequestState { @@ -320,7 +321,7 @@ export class OutlinePanel extends ViewletPanel { treeContainer, new OutlineVirtualDelegate(), [new OutlineGroupRenderer(), this._treeRenderer], - this._treeDataSource, + this._treeDataSource as IDataSource, { expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, @@ -342,7 +343,7 @@ export class OutlinePanel extends ViewletPanel { // feature: filter on type - keep tree and menu in sync this.disposables.push(this._tree.onDidUpdateOptions(e => { - this._outlineViewState.filterOnType = e.filterOnType; + this._outlineViewState.filterOnType = Boolean(e.filterOnType); })); // feature: expand all nodes when filtering (not when finding) @@ -355,7 +356,7 @@ export class OutlinePanel extends ViewletPanel { viewState = this._tree.getViewState(); this._tree.expandAll(); } else if (!pattern && viewState) { - this._tree.setInput(this._tree.getInput(), viewState); + this._tree.setInput(this._tree.getInput()!, viewState); viewState = undefined; } })); @@ -426,7 +427,7 @@ export class OutlinePanel extends ViewletPanel { private _showMessage(message: string) { dom.addClass(this._domNode, 'message'); - this._tree.setInput(undefined); + this._tree.setInput(undefined!); this._progressBar.stop().hide(); this._message.innerText = escape(message); } From 105f4f84fbe7770a0abcc13816525bfaf904f5b9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 09:45:28 +0100 Subject: [PATCH 56/88] more strict null --- src/tsconfig.strictNullChecks.json | 15 ++++++--------- .../services/progress/browser/progressService2.ts | 8 +++----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 1c3308561b0..bd09c3b049a 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -17,12 +17,17 @@ "./vs/workbench/contrib/externalTerminal/**/*", "./vs/workbench/contrib/snippets/**/*.ts", "./vs/workbench/contrib/outline/**/*.ts", + "./vs/workbench/contrib/performance/**/*.ts", "./vs/workbench/contrib/welcome/**/*.ts", "./vs/workbench/contrib/issue/**/*", + "./vs/workbench/contrib/splash/**/*.ts", "./vs/workbench/contrib/tasks/**/*.ts", "./vs/workbench/services/commands/**/*", "./vs/workbench/services/files/node/watcher/**/*", - "./vs/workbench/services/themes/**/*.ts" + "./vs/workbench/services/themes/**/*.ts", + "./vs/workbench/services/bulkEdit/**/*.ts", + "./vs/workbench/services/progress/**/*.ts", + "./vs/workbench/services/timer/**/*.ts" ], "files": [ "./vs/monaco.d.ts", @@ -237,9 +242,6 @@ "./vs/workbench/contrib/output/common/outputLinkComputer.ts", "./vs/workbench/contrib/output/common/outputLinkProvider.ts", "./vs/workbench/contrib/output/node/outputAppender.ts", - "./vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts", - "./vs/workbench/contrib/performance/electron-browser/startupProfiler.ts", - "./vs/workbench/contrib/performance/electron-browser/startupTimings.ts", "./vs/workbench/contrib/preferences/browser/settingsWidgets.ts", "./vs/workbench/contrib/preferences/common/smartSnippetInserter.ts", "./vs/workbench/contrib/preferences/test/common/smartSnippetInserter.test.ts", @@ -272,7 +274,6 @@ "./vs/workbench/contrib/search/test/browser/openFileHandler.test.ts", "./vs/workbench/contrib/search/test/common/searchModel.test.ts", "./vs/workbench/contrib/search/test/common/searchResult.test.ts", - "./vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts", "./vs/workbench/contrib/stats/node/stats.contribution.ts", "./vs/workbench/contrib/stats/node/workspaceStats.ts", "./vs/workbench/contrib/stats/test/workspaceStats.test.ts", @@ -313,7 +314,6 @@ "./vs/workbench/services/backup/common/backup.ts", "./vs/workbench/services/backup/node/backupFileService.ts", "./vs/workbench/services/broadcast/electron-browser/broadcastService.ts", - "./vs/workbench/services/bulkEdit/browser/bulkEditService.ts", "./vs/workbench/services/configuration/common/configuration.ts", "./vs/workbench/services/configuration/common/configurationModels.ts", "./vs/workbench/services/configuration/common/jsonEditing.ts", @@ -373,8 +373,6 @@ "./vs/workbench/services/part/common/partService.ts", "./vs/workbench/services/preferences/common/keybindingsEditorModel.ts", "./vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts", - "./vs/workbench/services/progress/browser/progressService.ts", - "./vs/workbench/services/progress/test/progressService.test.ts", "./vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts", "./vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts", "./vs/workbench/services/remote/node/remoteAgentService.ts", @@ -409,7 +407,6 @@ "./vs/workbench/services/textfile/common/textFileEditorModelManager.ts", "./vs/workbench/services/textfile/common/textfiles.ts", "./vs/workbench/services/textfile/node/textResourcePropertiesService.ts", - "./vs/workbench/services/timer/electron-browser/timerService.ts", "./vs/workbench/services/title/common/titleService.ts", "./vs/workbench/services/viewlet/browser/viewlet.ts", "./vs/workbench/services/workspace/common/workspaceEditing.ts", diff --git a/src/vs/workbench/services/progress/browser/progressService2.ts b/src/vs/workbench/services/progress/browser/progressService2.ts index f61446ca4b9..d267ae05770 100644 --- a/src/vs/workbench/services/progress/browser/progressService2.ts +++ b/src/vs/workbench/services/progress/browser/progressService2.ts @@ -39,8 +39,7 @@ export class ProgressService2 implements IProgressService2 { if (viewlet) { return this._withViewletProgress(location, task); } - console.warn(`Bad progress location: ${location}`); - return undefined; + return Promise.reject(new Error(`Bad progress location: ${location}`)); } switch (location) { @@ -55,8 +54,7 @@ export class ProgressService2 implements IProgressService2 { case ProgressLocation.Extensions: return this._withViewletProgress('workbench.view.extensions', task); default: - console.warn(`Bad progress location: ${location}`); - return undefined; + return Promise.reject(new Error(`Bad progress location: ${location}`)); } } @@ -269,4 +267,4 @@ export class ProgressService2 implements IProgressService2 { } } -registerSingleton(IProgressService2, ProgressService2, true); \ No newline at end of file +registerSingleton(IProgressService2, ProgressService2, true); From 4e3dcb718bff1a64bc2377e045c1b12eec5cc640 Mon Sep 17 00:00:00 2001 From: "Ryan A. Pavlik" Date: Tue, 5 Mar 2019 02:47:09 -0600 Subject: [PATCH 57/88] Update preferences.contribution.ts (#69807) Fix typo in spelling of Preferences. --- .../electron-browser/preferences.contribution.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts index 6d2d5ab3bc1..e9af73dc862 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts @@ -477,7 +477,7 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: OpenFolderSettingsAction.ID, title: { value: `${category}: ${OpenFolderSettingsAction.LABEL}`, original: 'Preferences: Open Folder Settings' }, - category: nls.localize('preferencesCategory', "Prefernces") + category: nls.localize('preferencesCategory', "Preferences") }, when: WorkbenchStateContext.isEqualTo('workspace') }); @@ -489,7 +489,7 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: OpenWorkspaceSettingsAction.ID, title: { value: `${category}: ${OpenWorkspaceSettingsAction.LABEL}`, original: 'Preferences: Open Workspace Settings' }, - category: nls.localize('preferencesCategory', "Prefernces") + category: nls.localize('preferencesCategory', "Preferences") }, when: WorkbenchStateContext.notEqualsTo('empty') }); @@ -799,4 +799,4 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { title: OPEN_FOLDER_SETTINGS_LABEL }, when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext) -}); \ No newline at end of file +}); From 10cd21c637ecbe267a2c5cfa53d1ea008790388a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 10:08:56 +0100 Subject: [PATCH 58/88] better error message for #68744 --- src/vs/code/electron-main/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index f89af11d2aa..d3d8f3fa86d 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -216,7 +216,7 @@ function handleStartupDataDirError(environmentService: IEnvironmentService, erro if (error.code === 'EACCES' || error.code === 'EPERM') { showStartupWarningDialog( localize('startupDataDirError', "Unable to write program user data."), - localize('startupDataDirErrorDetail', "Please make sure the directory {0} is writeable.", environmentService.userDataPath) + localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath) ); } } From 1eb6de1daf76b118eb21296afcc4afd248e6fda1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 10:00:20 +0100 Subject: [PATCH 59/88] clean up some todos --- extensions/git/src/decorationProvider.ts | 1 - extensions/git/src/repository.ts | 2 +- src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts | 1 - src/vs/workbench/contrib/outline/browser/outlinePanel.ts | 3 +-- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 97a6a41997f..9f17b20ee8e 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -20,7 +20,6 @@ class GitIgnoreDecorationProvider implements DecorationProvider { private disposables: Disposable[] = []; constructor(private model: Model) { - //todo@joh -> events when the ignore status actually changes, not only when the file changes this.onDidChangeDecorations = fireEvent(anyEvent( filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore')), model.onDidOpenRepository, diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 388a1f28043..2fac9e2a39f 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -206,7 +206,7 @@ export class Resource implements SourceControlResourceState { case Status.INDEX_ADDED: case Status.INTENT_TO_ADD: return new ThemeColor('gitDecoration.addedResourceForeground'); - case Status.INDEX_RENAMED: // todo@joh - special color? + case Status.INDEX_RENAMED: case Status.UNTRACKED: return new ThemeColor('gitDecoration.untrackedResourceForeground'); case Status.IGNORED: diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index 731a9309798..065e9e61a48 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -169,7 +169,6 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic return this._mainThreadEditors.$tryApplyWorkspaceEdit({ edits: [resourceEdit] }); } - // TODO@joh bubble this to listener? return Promise.reject(new Error('concurrent_edits')); }); } diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index d6d2c3f39fc..59dbfe4c344 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -335,8 +335,7 @@ export class OutlinePanel extends ViewletPanel { this._disposables.push(this._tree); this._disposables.push(this._outlineViewState.onDidChange(this._onDidChangeUserState, this)); - // todo@joh workaournd for the tree resetting the filter behaviour - // to something globally defined + // override the globally defined behaviour this._tree.updateOptions({ filterOnType: this._outlineViewState.filterOnType }); From de8f1b8025cb20bf03b936102aba1a7ed56163d1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 10:15:51 +0100 Subject: [PATCH 60/88] reset editor selection when explicitly cancelling snippet mode, #68512 --- .../contrib/snippet/snippetController2.ts | 10 ++++- .../snippet/test/snippetController2.test.ts | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts index febc52c54a6..42ff4261198 100644 --- a/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -193,7 +193,7 @@ export class SnippetController2 implements IEditorContribution { } } - cancel(): void { + cancel(resetSelection: boolean = false): void { this._inSnippet.reset(); this._hasPrevTabstop.reset(); this._hasNextTabstop.reset(); @@ -201,6 +201,12 @@ export class SnippetController2 implements IEditorContribution { dispose(this._session); this._session = undefined; this._modelVersionId = -1; + if (resetSelection) { + // reset selection to the primary cursor when being asked + // for. this happens when explicitly cancelling snippet mode, + // e.g. when pressing ESC + this._editor.setSelections([this._editor.getSelection()]); + } } prev(): void { @@ -257,7 +263,7 @@ registerEditorCommand(new CommandCtor({ registerEditorCommand(new CommandCtor({ id: 'leaveSnippet', precondition: SnippetController2.InSnippetMode, - handler: ctrl => ctrl.cancel(), + handler: ctrl => ctrl.cancel(true), kbOpts: { weight: KeybindingWeight.EditorContrib + 30, kbExpr: EditorContextKeys.editorTextFocus, diff --git a/src/vs/editor/contrib/snippet/test/snippetController2.test.ts b/src/vs/editor/contrib/snippet/test/snippetController2.test.ts index 668fc0b74b9..95395786fd0 100644 --- a/src/vs/editor/contrib/snippet/test/snippetController2.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetController2.test.ts @@ -361,4 +361,44 @@ suite('SnippetController2', function () { assertSelections(editor, new Selection(1, 7, 1, 7)); assertContextKeys(contextKeys, false, false, false); }); + + test('Cancelling snippet mode should discard added cursors #68512 (soft cancel)', function () { + const ctrl = new SnippetController2(editor, logService, contextKeys); + model.setValue(''); + editor.setSelection(new Selection(1, 1, 1, 1)); + + ctrl.insert('.REGION ${2:FUNCTION_NAME}\nCREATE.FUNCTION ${1:VOID} ${2:FUNCTION_NAME}(${3:})\n\t${4:}\nEND\n.ENDREGION$0'); + assertSelections(editor, new Selection(2, 17, 2, 21)); + + ctrl.next(); + assertSelections(editor, new Selection(1, 9, 1, 22), new Selection(2, 22, 2, 35)); + assertContextKeys(contextKeys, true, true, true); + + editor.setSelections([new Selection(1, 22, 1, 22), new Selection(2, 35, 2, 35)]); + assertContextKeys(contextKeys, true, true, true); + + editor.setSelections([new Selection(2, 1, 2, 1), new Selection(2, 36, 2, 36)]); + assertContextKeys(contextKeys, false, false, false); + assertSelections(editor, new Selection(2, 1, 2, 1), new Selection(2, 36, 2, 36)); + }); + + test('Cancelling snippet mode should discard added cursors #68512 (hard cancel)', function () { + const ctrl = new SnippetController2(editor, logService, contextKeys); + model.setValue(''); + editor.setSelection(new Selection(1, 1, 1, 1)); + + ctrl.insert('.REGION ${2:FUNCTION_NAME}\nCREATE.FUNCTION ${1:VOID} ${2:FUNCTION_NAME}(${3:})\n\t${4:}\nEND\n.ENDREGION$0'); + assertSelections(editor, new Selection(2, 17, 2, 21)); + + ctrl.next(); + assertSelections(editor, new Selection(1, 9, 1, 22), new Selection(2, 22, 2, 35)); + assertContextKeys(contextKeys, true, true, true); + + editor.setSelections([new Selection(1, 22, 1, 22), new Selection(2, 35, 2, 35)]); + assertContextKeys(contextKeys, true, true, true); + + ctrl.cancel(true); + assertContextKeys(contextKeys, false, false, false); + assertSelections(editor, new Selection(1, 22, 1, 22)); + }); }); From 3d3450cc95c5bfbee5e07366ca70969df5d665e8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 5 Mar 2019 10:26:36 +0100 Subject: [PATCH 61/88] Fix #68546 --- .../node/configurationService.ts | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 1e90cfd6285..b71054c6318 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { ResourceMap } from 'vs/base/common/map'; import { equals, deepClone } from 'vs/base/common/objects'; import { Disposable } from 'vs/base/common/lifecycle'; -import { Queue } from 'vs/base/common/async'; +import { Queue, Barrier } from 'vs/base/common/async'; import { writeFile } from 'vs/base/node/pfs'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -35,14 +35,14 @@ import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import { localize } from 'vs/nls'; import { isEqual, dirname } from 'vs/base/common/resources'; import { mark } from 'vs/base/common/performance'; +import { Schemas } from 'vs/base/common/network'; export class WorkspaceService extends Disposable implements IWorkspaceConfigurationService, IWorkspaceContextService { public _serviceBrand: any; private workspace: Workspace; - private resolvePromise: Promise; - private resolveCallback: () => void; + private completeWorkspaceBarrier: Barrier; private _configuration: Configuration; private defaultConfiguration: DefaultConfigurationModel; private userConfiguration: UserConfiguration; @@ -70,7 +70,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat constructor(private environmentService: IEnvironmentService, private workspaceSettingsRootFolder: string = FOLDER_CONFIG_FOLDER_NAME) { super(); - this.resolvePromise = new Promise(c => this.resolveCallback = c); + this.completeWorkspaceBarrier = new Barrier(); this.defaultConfiguration = new DefaultConfigurationModel(); this.userConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath)); this.workspaceConfiguration = this._register(new WorkspaceConfiguration(environmentService)); @@ -86,7 +86,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat // Workspace Context Service Impl public getCompleteWorkspace(): Promise { - return this.resolvePromise.then(() => this.getWorkspace()); + return this.completeWorkspaceBarrier.wait().then(() => this.getWorkspace()); } public getWorkspace(): Workspace { @@ -304,7 +304,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat for (const workspaceFolder of changedWorkspaceFolders) { this.onWorkspaceFolderConfigurationChanged(workspaceFolder); } - this.resolveCallback(); + this.releaseWorkspaceBarrier(); }); } @@ -331,7 +331,11 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat const workspaceConfigPath = workspaceIdentifier.configPath; const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), dirname(workspaceConfigPath)); const workspaceId = workspaceIdentifier.id; - return new Workspace(workspaceId, workspaceFolders, workspaceConfigPath); + const workspace = new Workspace(workspaceId, workspaceFolders, workspaceConfigPath); + if (workspace.configuration.scheme === Schemas.file) { + this.releaseWorkspaceBarrier(); // Release barrier as workspace is complete because it is from disk. + } + return workspace; }); } @@ -345,11 +349,21 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat configuredFolders = [{ uri: folder.toString() }]; } - return Promise.resolve(new Workspace(singleFolder.id, toWorkspaceFolders(configuredFolders))); + const workspace = new Workspace(singleFolder.id, toWorkspaceFolders(configuredFolders)); + this.releaseWorkspaceBarrier(); // Release barrier as workspace is complete because it is single folder. + return Promise.resolve(workspace); } private createEmptyWorkspace(emptyWorkspace: IEmptyWorkspaceInitializationPayload): Promise { - return Promise.resolve(new Workspace(emptyWorkspace.id)); + const workspace = new Workspace(emptyWorkspace.id); + this.releaseWorkspaceBarrier(); // Release barrier as workspace is complete because it is an empty workspace. + return Promise.resolve(workspace); + } + + private releaseWorkspaceBarrier(): void { + if (!this.completeWorkspaceBarrier.isOpen()) { + this.completeWorkspaceBarrier.open(); + } } private updateWorkspaceAndInitializeConfiguration(workspace: Workspace, postInitialisationTask: () => void): Promise { From e5d9409ab7b6cfe345af20435db423415f956bba Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 10:26:49 +0100 Subject: [PATCH 62/88] undo aria change --- src/vs/base/browser/ui/aria/aria.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/vs/base/browser/ui/aria/aria.ts b/src/vs/base/browser/ui/aria/aria.ts index d7dad9cba5c..1922450144d 100644 --- a/src/vs/base/browser/ui/aria/aria.ts +++ b/src/vs/base/browser/ui/aria/aria.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./aria'; +import * as nls from 'vs/nls'; import { isMacintosh } from 'vs/base/common/platform'; import * as dom from 'vs/base/browser/dom'; @@ -47,12 +48,29 @@ export function status(msg: string): void { } } +let repeatedTimes = 0; +let prevText: string | undefined = undefined; function insertMessage(target: HTMLElement, msg: string): void { if (!ariaContainer) { // console.warn('ARIA support needs a container. Call setARIAContainer() first.'); return; } + if (prevText === msg) { + repeatedTimes++; + } + else { + prevText = msg; + repeatedTimes = 0; + } + + + switch (repeatedTimes) { + case 0: break; + case 1: msg = nls.localize('repeated', "{0} (occurred again)", msg); break; + default: msg = nls.localize('repeatedNtimes', "{0} (occurred {1} times)", msg, repeatedTimes); break; + } + dom.clearNode(target); target.textContent = msg; From 809297c9cf762dabf296f66775a3d95238c3c15c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 10:31:31 +0100 Subject: [PATCH 63/88] only alert when inserting a suggestion make additional editor, like inserting an import statement, simplify the message that read when selecting an item --- .../editor/contrib/suggest/suggestController.ts | 7 +++++-- src/vs/editor/contrib/suggest/suggestWidget.ts | 16 +++------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 20f37c560e0..c471b0fe568 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { alert } from 'vs/base/browser/ui/aria/aria'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -291,8 +292,10 @@ export class SuggestController implements IEditorContribution { } private _alertCompletionItem({ completion: suggestion }: CompletionItem): void { - // A temporary fix for too verbose, unnecesary screen reader alerts. - // Todo: Remove calls to this empty method body. + if (isNonEmptyArray(suggestion.additionalTextEdits)) { + let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", suggestion.label, suggestion.additionalTextEdits.length); + alert(msg); + } } triggerSuggest(onlyFrom?: CompletionItemProvider[]): void { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 8de80617e8d..13e51c949d9 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -540,20 +540,10 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate Date: Tue, 5 Mar 2019 10:33:26 +0100 Subject: [PATCH 64/88] debt - IActiveTextEditorModel => IResolvedTextEditorModel --- src/vs/editor/common/services/resolverService.ts | 8 ++++++-- src/vs/editor/standalone/browser/simpleServices.ts | 6 +++--- src/vs/workbench/common/editor/textEditorModel.ts | 4 ++-- .../services/bulkEdit/browser/bulkEditService.ts | 6 +++--- .../services/configuration/node/jsonEditingService.ts | 10 +++++----- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts index 2b04d4b1218..ef65b34685e 100644 --- a/src/vs/editor/common/services/resolverService.ts +++ b/src/vs/editor/common/services/resolverService.ts @@ -18,7 +18,7 @@ export interface ITextModelService { * Provided a resource URI, it will return a model reference * which should be disposed once not needed anymore. */ - createModelReference(resource: URI): Promise>; + createModelReference(resource: URI): Promise>; /** * Registers a specific `scheme` content provider. @@ -49,6 +49,10 @@ export interface ITextEditorModel extends IEditorModel { isReadonly(): boolean; } -export interface IActiveTextEditorModel extends ITextEditorModel { +export interface IResolvedTextEditorModel extends ITextEditorModel { + + /** + * Same as ITextEditorModel#textEditorModel, but never null. + */ readonly textEditorModel: ITextModel; } diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 7c6487339f2..c76b38b22df 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -22,7 +22,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { TextEdit, WorkspaceEdit, isResourceTextEdit } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { IActiveTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IResolvedTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -44,7 +44,7 @@ import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFolde import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -export class SimpleModel implements IActiveTextEditorModel { +export class SimpleModel implements IResolvedTextEditorModel { private model: ITextModel; private readonly _onDispose: Emitter; @@ -98,7 +98,7 @@ export class SimpleEditorModelResolverService implements ITextModelService { this.editor = editor; } - public createModelReference(resource: URI): Promise> { + public createModelReference(resource: URI): Promise> { let model: ITextModel | null = withTypedEditor(this.editor, (editor) => this.findModel(editor, resource), (diffEditor) => this.findModel(diffEditor.getOriginalEditor(), resource) || this.findModel(diffEditor.getModifiedEditor(), resource) diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index b8279be7d5c..4ba0027e985 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -6,7 +6,7 @@ import { ITextModel, ITextBufferFactory } from 'vs/editor/common/model'; import { EditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; -import { ITextEditorModel, IActiveTextEditorModel } from 'vs/editor/common/services/resolverService'; +import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -135,7 +135,7 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd return null; } - isResolved(): this is IActiveTextEditorModel { + isResolved(): this is IResolvedTextEditorModel { return !!this.textEditorModelHandle; } diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index 93494c3bbc7..5137f89c2c5 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -13,7 +13,7 @@ import { Range } from 'vs/editor/common/core/range'; import { EndOfLineSequence, IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model'; import { isResourceFileEdit, isResourceTextEdit, ResourceFileEdit, ResourceTextEdit, WorkspaceEdit } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { ITextModelService, IActiveTextEditorModel } from 'vs/editor/common/services/resolverService'; +import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { localize } from 'vs/nls'; import { IFileService } from 'vs/platform/files/common/files'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -53,7 +53,7 @@ class ModelEditTask implements IDisposable { private _expectedModelVersionId: number | undefined; protected _newEol: EndOfLineSequence; - constructor(private readonly _modelReference: IReference) { + constructor(private readonly _modelReference: IReference) { this._model = this._modelReference.object.textEditorModel; this._edits = []; } @@ -115,7 +115,7 @@ class EditorEditTask extends ModelEditTask { private _editor: ICodeEditor; - constructor(modelReference: IReference, editor: ICodeEditor) { + constructor(modelReference: IReference, editor: ICodeEditor) { super(modelReference); this._editor = editor; } diff --git a/src/vs/workbench/services/configuration/node/jsonEditingService.ts b/src/vs/workbench/services/configuration/node/jsonEditingService.ts index e8f1ab3be9b..5c08f612786 100644 --- a/src/vs/workbench/services/configuration/node/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/node/jsonEditingService.ts @@ -17,7 +17,7 @@ import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; -import { ITextModelService, IActiveTextEditorModel } from 'vs/editor/common/services/resolverService'; +import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IJSONEditingService, IJSONValue, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ITextModel } from 'vs/editor/common/model'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -84,7 +84,7 @@ export class JSONEditingService implements IJSONEditingService { return setProperty(model.getValue(), [key], value, { tabSize, insertSpaces, eol }); } - private async resolveModelReference(resource: URI): Promise> { + private async resolveModelReference(resource: URI): Promise> { const exists = await this.fileService.existsFile(resource); if (!exists) { await this.fileService.updateContent(resource, '{}', { encoding: encoding.UTF8 }); @@ -98,18 +98,18 @@ export class JSONEditingService implements IJSONEditingService { return parseErrors.length > 0; } - private resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { + private resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { return this.resolveModelReference(resource) .then(reference => { const model = reference.object.textEditorModel; if (this.hasParseErrors(model)) { - return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); + return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); } // Target cannot be dirty if not writing into buffer if (checkDirty && this.textFileService.isDirty(resource)) { - return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); + return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); } return reference; }); From e1dac9dee155604f2dc76ab20e53767691eca95e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 10:36:05 +0100 Subject: [PATCH 65/88] files - do not focus explorer when revealing folder (for #69333) --- .../workbench/contrib/files/browser/editors/textFileEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 5e1a9623ea0..c5c6bcb72ca 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -234,7 +234,7 @@ export class TextFileEditor extends BaseTextEditor { // Best we can do is to reveal the folder in the explorer if (this.contextService.isInsideWorkspace(input.getResource())) { - this.viewletService.openViewlet(VIEWLET_ID, true).then(() => { + this.viewletService.openViewlet(VIEWLET_ID).then(() => { this.explorerService.select(input.getResource(), true); }); } From 0bb3bfc4b4ffe6d94cc67fbd712b706d4250f3ff Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 10:38:07 +0100 Subject: [PATCH 66/88] strict null trouble --- src/vs/editor/contrib/snippet/snippetController2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts index 42ff4261198..3f87729b6ab 100644 --- a/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -205,7 +205,7 @@ export class SnippetController2 implements IEditorContribution { // reset selection to the primary cursor when being asked // for. this happens when explicitly cancelling snippet mode, // e.g. when pressing ESC - this._editor.setSelections([this._editor.getSelection()]); + this._editor.setSelections([this._editor.getSelection()!]); } } From 4f197a7079bf2ce1346db1739f8b89cd700d079f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 5 Mar 2019 10:41:16 +0100 Subject: [PATCH 67/88] :lipstick: --- extensions/git/src/commands.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 165895701b6..8e798b0cc77 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -649,17 +649,16 @@ export class CommandCenter { if (!(resource instanceof Resource)) { // can happen when called from a keybinding + console.log('WHAT'); resource = this.getSCMResource(); } if (resource) { - const resources = ([resource, ...resourceStates] as Resource[]) - .filter(r => r.type !== Status.DELETED && r.type !== Status.INDEX_DELETED); - - uris = resources.map(r => r.resourceUri); - } - else { - uris = [(window.activeTextEditor && window.activeTextEditor.document.uri)] as Uri[]; + uris = ([resource, ...resourceStates] as Resource[]) + .filter(r => r.type !== Status.DELETED && r.type !== Status.INDEX_DELETED) + .map(r => r.resourceUri); + } else if (window.activeTextEditor) { + uris = [window.activeTextEditor.document.uri]; } } @@ -668,6 +667,7 @@ export class CommandCenter { } const activeTextEditor = window.activeTextEditor; + for (const uri of uris) { const opts: TextDocumentShowOptions = { preserveFocus, @@ -2120,6 +2120,7 @@ export class CommandCenter { uri = uri ? uri : (window.activeTextEditor && window.activeTextEditor.document.uri); this.outputChannel.appendLine(`git.getSCMResource.uri ${uri && uri.toString()}`); + for (const r of this.model.repositories.map(r => r.root)) { this.outputChannel.appendLine(`repo root ${r}`); } From 8f0c07ac9ea547821461a1f6e90044beffe1a030 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 5 Mar 2019 10:44:22 +0100 Subject: [PATCH 68/88] Get rid of editable map, it should not be a map but just one element fixes #69531 --- .../contrib/files/browser/media/explorerviewlet.css | 4 ++-- .../contrib/files/browser/views/explorerView.ts | 4 ++-- .../workbench/contrib/files/common/explorerService.ts | 11 +++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css index a0c0f8de7f4..17b272cef79 100644 --- a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css @@ -18,8 +18,8 @@ padding-left: 4px; /* align top level twistie with `Explorer` title label */ } -.explorer-viewlet .monaco-list.highlight .explorer-item:not(.explorer-item-edited), -.explorer-viewlet .monaco-list.highlight .monaco-tl-twistie { +.explorer-viewlet .explorer-folders-view.highlight .monaco-list .explorer-item:not(.explorer-item-edited), +.explorer-viewlet .explorer-folders-view.highlight .monaco-list .monaco-tl-twistie { opacity: 0.3; } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 69a8b7bb575..94c206c6ebf 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -176,13 +176,13 @@ export class ExplorerView extends ViewletPanel { if (isEditing) { await this.tree.expand(e.parent); } else { - DOM.removeClass(this.tree.getHTMLElement(), 'highlight'); + DOM.removeClass(treeContainer, 'highlight'); } await this.refresh(e.parent); if (isEditing) { - DOM.addClass(this.tree.getHTMLElement(), 'highlight'); + DOM.addClass(treeContainer, 'highlight'); this.tree.reveal(e); } else { this.tree.domFocus(); diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index 980c9b14035..7ce193360b2 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -37,7 +37,7 @@ export class ExplorerService implements IExplorerService { private _onDidSelectItem = new Emitter<{ item?: ExplorerItem, reveal?: boolean }>(); private _onDidCopyItems = new Emitter<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>(); private disposables: IDisposable[] = []; - private editableStats = new Map(); + private editable: { stat: ExplorerItem, data: IEditableData } | undefined; private _sortOrder: SortOrder; private cutItems: ExplorerItem[] | undefined; @@ -112,11 +112,10 @@ export class ExplorerService implements IExplorerService { setEditable(stat: ExplorerItem, data: IEditableData | null): void { if (!data) { - this.editableStats.delete(stat); + this.editable = undefined; } else { - this.editableStats.set(stat, data); + this.editable = { stat, data }; } - this._onDidChangeEditable.fire(stat); } @@ -133,11 +132,11 @@ export class ExplorerService implements IExplorerService { } getEditableData(stat: ExplorerItem): IEditableData | undefined { - return this.editableStats.get(stat); + return this.editable && this.editable.stat === stat ? this.editable.data : undefined; } isEditable(stat: ExplorerItem): boolean { - return this.editableStats.has(stat); + return !!this.editable && this.editable.stat === stat; } select(resource: URI, reveal?: boolean): Promise { From 2b98f571453104e33306cb8637da8faf99d1a678 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 11:01:59 +0100 Subject: [PATCH 69/88] fix #67300 --- .../electron-browser/partsSplash.contribution.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index b8f8fbbf0a5..79dcaaae6d3 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -22,6 +22,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; class PartsSplash { @@ -29,6 +30,7 @@ class PartsSplash { private readonly _disposables: IDisposable[] = []; + private _didChangeTitleBarStyle: boolean; private _lastBaseTheme: string; private _lastBackground?: string; @@ -39,13 +41,18 @@ class PartsSplash { @IEnvironmentService private readonly _envService: IEnvironmentService, @IBroadcastService private readonly _broadcastService: IBroadcastService, @ILifecycleService lifecycleService: ILifecycleService, - @IEditorGroupsService editorGroupsService: IEditorGroupsService + @IEditorGroupsService editorGroupsService: IEditorGroupsService, + @IConfigurationService configService: IConfigurationService, ) { lifecycleService.when(LifecyclePhase.Restored).then(_ => this._removePartsSplash()); Event.debounce(Event.any( onDidChangeFullscreen, editorGroupsService.onDidLayout ), () => { }, 800)(this._savePartsSplash, this, this._disposables); + + configService.onDidChangeConfiguration(e => { + this._didChangeTitleBarStyle = e.affectsConfiguration('window.titleBarStyle'); + }, this, this._disposables); } dispose(): void { @@ -100,7 +107,7 @@ class PartsSplash { } private _shouldSaveLayoutInfo(): boolean { - return !isFullscreen() && !this._envService.isExtensionDevelopment; + return !isFullscreen() && !this._envService.isExtensionDevelopment && !this._didChangeTitleBarStyle; } private _removePartsSplash(): void { From fe2571f087a0f0039a2c767e5e81daf8e1eb0261 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 5 Mar 2019 10:43:03 +0100 Subject: [PATCH 70/88] #68546 Tests --- .../configurationService.test.ts | 64 ++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index 6d45e9d1c3d..5e78dc69c52 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -140,10 +140,66 @@ suite('WorkspaceContextService - Folder', () => { test('isCurrentWorkspace() => false', () => { assert.ok(!workspaceContextService.isCurrentWorkspace(URI.file(workspaceResource + 'abc'))); }); + + test('workspace is complete', () => workspaceContextService.getCompleteWorkspace()); }); suite('WorkspaceContextService - Workspace', () => { + let parentResource: string, testObject: WorkspaceService, instantiationService: TestInstantiationService; + + setup(() => { + return setUpWorkspace(['a', 'b']) + .then(({ parentDir, configPath }) => { + + parentResource = parentDir; + + const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); + const workspaceService = new WorkspaceService(environmentService); + + instantiationService = workbenchInstantiationService(); + instantiationService.stub(IWorkspaceContextService, workspaceService); + instantiationService.stub(IConfigurationService, workspaceService); + instantiationService.stub(IEnvironmentService, environmentService); + + return workspaceService.initialize(getWorkspaceIdentifier(configPath)).then(() => { + workspaceService.acquireInstantiationService(instantiationService); + testObject = workspaceService; + }); + }); + }); + + teardown(() => { + if (testObject) { + (testObject).dispose(); + } + if (parentResource) { + return pfs.del(parentResource, os.tmpdir()); + } + return undefined; + }); + + test('workspace folders', () => { + const actual = testObject.getWorkspace().folders; + + assert.equal(actual.length, 2); + assert.equal(path.basename(actual[0].uri.fsPath), 'a'); + assert.equal(path.basename(actual[1].uri.fsPath), 'b'); + }); + + test('getWorkbenchState()', () => { + const actual = testObject.getWorkbenchState(); + + assert.equal(actual, WorkbenchState.WORKSPACE); + }); + + + test('workspace is complete', () => testObject.getCompleteWorkspace()); + +}); + +suite('WorkspaceContextService - Workspace Editing', () => { + let parentResource: string, testObject: WorkspaceService, instantiationService: TestInstantiationService, fileChangeEvent: Emitter = new Emitter(); setup(() => { @@ -186,14 +242,6 @@ suite('WorkspaceContextService - Workspace', () => { return undefined; }); - test('workspace folders', () => { - const actual = testObject.getWorkspace().folders; - - assert.equal(actual.length, 2); - assert.equal(path.basename(actual[0].uri.fsPath), 'a'); - assert.equal(path.basename(actual[1].uri.fsPath), 'b'); - }); - test('add folders', () => { const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath); return testObject.addFolders([{ uri: URI.file(path.join(workspaceDir, 'd')) }, { uri: URI.file(path.join(workspaceDir, 'c')) }]) From 94f7ae74c556f4c5407bf9bc462e6c4721641245 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 5 Mar 2019 10:47:19 +0100 Subject: [PATCH 71/88] fixes #69529 --- extensions/git/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/git/package.json b/extensions/git/package.json index 834563c3102..f858863dd7b 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1150,6 +1150,7 @@ "%config.postCommitCommand.sync%" ], "markdownDescription": "%config.postCommitCommand%", + "scope": "resource", "default": "none" }, "git.showInlineOpenFileAction": { From 20a4f36e2517d9b56075d649beed84716ec88088 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 5 Mar 2019 11:15:42 +0100 Subject: [PATCH 72/88] add workbench/contrib/scm to strict null checks fixes #69688 --- src/tsconfig.strictNullChecks.json | 3 +- src/vs/base/browser/ui/list/list.ts | 2 +- src/vs/base/browser/ui/list/listWidget.ts | 13 ++------ .../common/editor/untitledEditorInput.ts | 14 +++----- .../common/editor/untitledEditorModel.ts | 15 ++++++--- .../scm/electron-browser/scmViewlet.ts | 32 +++++++++---------- 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index bd09c3b049a..d8bae789a91 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -15,6 +15,7 @@ "./vs/workbench/electron-browser/actions/**/*", "./vs/workbench/contrib/emmet/**/*", "./vs/workbench/contrib/externalTerminal/**/*", + "./vs/workbench/contrib/scm/**/*.ts", "./vs/workbench/contrib/snippets/**/*.ts", "./vs/workbench/contrib/outline/**/*.ts", "./vs/workbench/contrib/performance/**/*.ts", @@ -430,4 +431,4 @@ "./typings/require-monaco.d.ts", "./vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts" ] -} +} \ No newline at end of file diff --git a/src/vs/base/browser/ui/list/list.ts b/src/vs/base/browser/ui/list/list.ts index 80dea11ee4a..42097113808 100644 --- a/src/vs/base/browser/ui/list/list.ts +++ b/src/vs/base/browser/ui/list/list.ts @@ -55,7 +55,7 @@ export interface IListContextMenuEvent { browserEvent: UIEvent; element: T | undefined; index: number | undefined; - anchor: HTMLElement | { x: number; y: number; } | undefined; + anchor: HTMLElement | { x: number; y: number; }; } export interface IIdentityProvider { diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index cd7312809c6..197fcb2ab98 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1127,13 +1127,7 @@ export class List implements ISpliceable, IDisposable { .map(e => new StandardKeyboardEvent(e)) .filter(e => this.didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10)) .filter(e => { e.preventDefault(); e.stopPropagation(); return false; }) - .map(event => { - const index = this.getFocus()[0]; - const element = this.view.element(index); - const anchor = this.view.domElement(index) || undefined; - return { index, element, anchor, browserEvent: event.browserEvent }; - }) - .event; + .event as Event; const fromKeyup = Event.chain(domEvent(this.view.domNode, 'keyup')) .filter(() => { @@ -1141,14 +1135,13 @@ export class List implements ISpliceable, IDisposable { this.didJustPressContextMenuKey = false; return didJustPressContextMenuKey; }) - .filter(() => this.getFocus().length > 0) + .filter(() => this.getFocus().length > 0 && !!this.view.domElement(this.getFocus()[0])) .map(browserEvent => { const index = this.getFocus()[0]; const element = this.view.element(index); - const anchor = this.view.domElement(index) || undefined; + const anchor = this.view.domElement(index) as HTMLElement; return { index, element, anchor, browserEvent }; }) - .filter(({ anchor }) => !!anchor) .event; const fromMouse = Event.chain(this.view.onContextMenu) diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index e1800711ea6..a4fe328d79d 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -121,25 +121,21 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.labelService.getUriLabel(this.resource); } - getTitle(verbosity: Verbosity): string { + getTitle(verbosity: Verbosity): string | null { if (!this.hasAssociatedFilePath) { return this.getName(); } - let title: string | undefined; switch (verbosity) { case Verbosity.SHORT: - title = this.shortTitle; - break; + return this.shortTitle; case Verbosity.MEDIUM: - title = this.mediumTitle; - break; + return this.mediumTitle; case Verbosity.LONG: - title = this.longTitle; - break; + return this.longTitle; } - return title; + return null; } isDirty(): boolean { diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 70cfc8c48e0..4d14923cc3f 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -95,7 +95,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin return this.textEditorModel.getLanguageIdentifier().language; } - return null; + return this.modeId; } getEncoding(): string { @@ -144,7 +144,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin return this.backupFileService.resolveBackupContent(backupResource); } - return null; + return undefined; }).then(backupTextBufferFactory => { const hasBackup = !!backupTextBufferFactory; @@ -171,17 +171,24 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin // Encoding this.configuredEncoding = this.configurationService.getValue(this.resource, 'files.encoding'); + // We know for a fact there is a text editor model here + const textEditorModel = this.textEditorModel!; + // Listen to content changes - this._register(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); + this._register(textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); // Listen to mode changes - this._register(this.textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config + this._register(textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config return this; }); } private onModelContentChanged(): void { + if (!this.isResolved()) { + return; + } + this.versionId++; // mark the untitled editor as non-dirty once its content becomes empty and we do diff --git a/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts index 077334bb5ca..39eeddba79a 100644 --- a/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts @@ -84,11 +84,11 @@ class StatusBarAction extends Action { private commandService: ICommandService ) { super(`statusbaraction{${command.id}}`, command.title, '', true); - this.tooltip = command.tooltip; + this.tooltip = command.tooltip || ''; } run(): Promise { - return this.commandService.executeCommand(this.command.id, ...this.command.arguments); + return this.commandService.executeCommand(this.command.id, ...(this.command.arguments || [])); } } @@ -198,7 +198,7 @@ class ProviderRenderer implements IListRenderer if (icon) { template.decorationIcon.style.display = ''; template.decorationIcon.style.backgroundImage = `url('${icon}')`; - template.decorationIcon.title = resource.decorations.tooltip; + template.decorationIcon.title = resource.decorations.tooltip || ''; } else { template.decorationIcon.style.display = 'none'; template.decorationIcon.style.backgroundImage = ''; } - template.element.setAttribute('data-tooltip', resource.decorations.tooltip); + template.element.setAttribute('data-tooltip', resource.decorations.tooltip || ''); template.elementDisposable = combinedDisposable(disposables); } @@ -821,7 +821,7 @@ export class RepositoryPanel extends ViewletPanel { const validationDelayer = new ThrottledDelayer(200); const validate = () => { - return this.repository.input.validateInput(this.inputBox.value, this.inputBox.inputElement.selectionStart).then(result => { + return this.repository.input.validateInput(this.inputBox.value, this.inputBox.inputElement.selectionStart || 0).then(result => { if (!result) { this.inputBox.inputElement.removeAttribute('aria-invalid'); this.inputBox.hideMessage(); @@ -916,7 +916,7 @@ export class RepositoryPanel extends ViewletPanel { } } - layoutBody(height: number = this.cachedHeight, width: number = this.cachedWidth): void { + layoutBody(height: number | undefined = this.cachedHeight, width: number | undefined = this.cachedWidth): void { if (height === undefined) { return; } @@ -962,9 +962,9 @@ export class RepositoryPanel extends ViewletPanel { return this.menus.getTitleSecondaryActions(); } - getActionItem(action: IAction): IActionItem { + getActionItem(action: IAction): IActionItem | null { if (!(action instanceof MenuItemAction)) { - return undefined; + return null; } return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); @@ -1176,9 +1176,9 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle this.onSelectionChange(this.mainPanel.getSelection()); this.mainPanelDisposable = toDisposable(() => { - this.removePanels([this.mainPanel]); + this.removePanels([this.mainPanel!]); selectionChangeDisposable.dispose(); - this.mainPanel.dispose(); + this.mainPanel!.dispose(); }); } else { this.mainPanelDisposable.dispose(); @@ -1203,7 +1203,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle super.setVisible(visible); if (!visible) { - this.cachedMainPanelHeight = this.getPanelSize(this.mainPanel); + this.cachedMainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; } const start = this.getContributedViewsStartIndex(); @@ -1247,9 +1247,9 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle } } - getActionItem(action: IAction): IActionItem { + getActionItem(action: IAction): IActionItem | null { if (!(action instanceof MenuItemAction)) { - return undefined; + return null; } return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); @@ -1318,14 +1318,14 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle this.removePanels(panelsToRemove); // Restore main panel height - if (this.isVisible() && typeof this.cachedMainPanelHeight === 'number') { + if (this.mainPanel && this.isVisible() && typeof this.cachedMainPanelHeight === 'number') { this.resizePanel(this.mainPanel, this.cachedMainPanelHeight); this.cachedMainPanelHeight = undefined; } // Resize all panels equally const height = typeof this.height === 'number' ? this.height : 1000; - const mainPanelHeight = this.getPanelSize(this.mainPanel); + const mainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; const size = (height - mainPanelHeight - contributableViewsHeight) / repositories.length; for (const panel of this.repositoryPanels) { this.resizePanel(panel, size); From c145eedcea2ecb213992280b5c760bad50a324c9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 11:27:01 +0100 Subject: [PATCH 73/88] cancel requests when outline provider change, also retrigger request #69147 --- .../contrib/documentSymbols/outlineModel.ts | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index 179b23f3a11..759ea82e044 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { binarySearch, coalesceInPlace } from 'vs/base/common/arrays'; +import { binarySearch, coalesceInPlace, equals } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { first, forEach, size } from 'vs/base/common/collections'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; @@ -266,13 +266,17 @@ export class OutlineModel extends TreeElement { static _create(textModel: ITextModel, token: CancellationToken): Promise { - let result = new OutlineModel(textModel); - let promises = DocumentSymbolProviderRegistry.ordered(textModel).map((provider, index) => { + const chainedCancellation = new CancellationTokenSource(); + token.onCancellationRequested(() => chainedCancellation.cancel()); + + const result = new OutlineModel(textModel); + const provider = DocumentSymbolProviderRegistry.ordered(textModel); + const promises = provider.map((provider, index) => { let id = TreeElement.findId(`provider_${index}`, result); let group = new OutlineGroup(id, result, provider, index); - return Promise.resolve(provider.provideDocumentSymbols(result.textModel, token)).then(result => { + return Promise.resolve(provider.provideDocumentSymbols(result.textModel, chainedCancellation.token)).then(result => { for (const info of result || []) { OutlineModel._makeOutlineElement(info, group); } @@ -289,7 +293,22 @@ export class OutlineModel extends TreeElement { }); }); - return Promise.all(promises).then(() => result._compact()); + const listener = DocumentSymbolProviderRegistry.onDidChange(() => { + const newProvider = DocumentSymbolProviderRegistry.ordered(textModel); + if (!equals(newProvider, provider)) { + chainedCancellation.cancel(); + } + }); + + return Promise.all(promises).then(() => { + if (chainedCancellation.token.isCancellationRequested && !token.isCancellationRequested) { + return OutlineModel._create(textModel, token); + } else { + return result._compact(); + } + }).finally(() => { + listener.dispose(); + }); } private static _makeOutlineElement(info: DocumentSymbol, container: OutlineGroup | OutlineElement): void { From a3ce5141e38a9d0ceb5c11eff9de65be7bc5bc06 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 5 Mar 2019 11:45:52 +0100 Subject: [PATCH 74/88] remove base64 transformation in electron IPC fixes #69338 --- .../electron-browser/ipc.electron-browser.ts | 2 +- .../ipc/electron-main/ipc.electron-main.ts | 8 +++---- src/vs/base/parts/ipc/node/ipc.electron.ts | 22 ++++--------------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts b/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts index 225370373a7..055d6a54130 100644 --- a/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts +++ b/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts @@ -14,7 +14,7 @@ export class Client extends IPCClient implements IDisposable { private protocol: Protocol; private static createProtocol(): Protocol { - const onMessage = Event.fromNodeEventEmitter(ipcRenderer, 'ipc:message', (_, message: string) => message); + const onMessage = Event.fromNodeEventEmitter(ipcRenderer, 'ipc:message', (_, message: Buffer) => message); ipcRenderer.send('ipc:hello'); return new Protocol(ipcRenderer, onMessage); } diff --git a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts index 17ae7bb81b6..f7d72041911 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts @@ -11,11 +11,11 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; interface IIPCEvent { event: { sender: Electron.WebContents; }; - message: string; + message: Buffer | null; } -function createScopedOnMessageEvent(senderId: number, eventName: string): Event { - const onMessage = Event.fromNodeEventEmitter(ipcMain, eventName, (event, message: string) => ({ event, message })); +function createScopedOnMessageEvent(senderId: number, eventName: string): Event { + const onMessage = Event.fromNodeEventEmitter(ipcMain, eventName, (event, message) => ({ event, message })); const onMessageFromSender = Event.filter(onMessage, ({ event }) => event.sender.id === senderId); return Event.map(onMessageFromSender, ({ message }) => message); } @@ -38,7 +38,7 @@ export class Server extends IPCServer { const onDidClientReconnect = new Emitter(); Server.Clients.set(id, toDisposable(() => onDidClientReconnect.fire())); - const onMessage = createScopedOnMessageEvent(id, 'ipc:message'); + const onMessage = createScopedOnMessageEvent(id, 'ipc:message') as Event; const onDidClientDisconnect = Event.any(Event.signal(createScopedOnMessageEvent(id, 'ipc:disconnect')), onDidClientReconnect.event); const protocol = new Protocol(webContents, onMessage); diff --git a/src/vs/base/parts/ipc/node/ipc.electron.ts b/src/vs/base/parts/ipc/node/ipc.electron.ts index 831a27377c1..e70289747fc 100644 --- a/src/vs/base/parts/ipc/node/ipc.electron.ts +++ b/src/vs/base/parts/ipc/node/ipc.electron.ts @@ -3,33 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; -import { Event, Emitter } from 'vs/base/common/event'; - -/** - * This implementation doesn't perform well since it uses base64 encoding for buffers. - * Electron 3.0 should have suport for buffers in IPC: https://github.com/electron/electron/pull/13055 - */ +import { Event } from 'vs/base/common/event'; export interface Sender { - send(channel: string, msg: string | null): void; + send(channel: string, msg: Buffer | null): void; } export class Protocol implements IMessagePassingProtocol { - private listener: IDisposable; - - private _onMessage = new Emitter(); - get onMessage(): Event { return this._onMessage.event; } - - constructor(private sender: Sender, onMessageEvent: Event) { - onMessageEvent(msg => this._onMessage.fire(Buffer.from(msg, 'base64'))); - } + constructor(private sender: Sender, readonly onMessage: Event) { } send(message: Buffer): void { try { - this.sender.send('ipc:message', message.toString('base64')); + this.sender.send('ipc:message', message); } catch (e) { // systems are going down } @@ -37,6 +24,5 @@ export class Protocol implements IMessagePassingProtocol { dispose(): void { this.sender.send('ipc:disconnect', null); - this.listener = dispose(this.listener); } } \ No newline at end of file From 480e15ca4e755cdae84079df70eab9ca44542ac3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 5 Mar 2019 11:51:59 +0100 Subject: [PATCH 75/88] fixes #69112 --- src/tsconfig.strictNullChecks.json | 8 ++++---- .../{electron-browser => browser}/dirtydiffDecorator.ts | 0 .../{electron-browser => browser}/media/check-inverse.svg | 0 .../scm/{electron-browser => browser}/media/check.svg | 0 .../media/dirtydiffDecorator.css | 0 .../scm/{electron-browser => browser}/media/icon-dark.svg | 0 .../{electron-browser => browser}/media/icon-light.svg | 0 .../{electron-browser => browser}/media/scmViewlet.css | 0 .../scm/{electron-browser => browser}/scm.contribution.ts | 2 +- .../scm/{electron-browser => browser}/scmActivity.ts | 0 .../contrib/scm/{electron-browser => browser}/scmMenus.ts | 0 .../contrib/scm/{electron-browser => browser}/scmUtil.ts | 0 .../scm/{electron-browser => browser}/scmViewlet.ts | 0 .../test/electron-browser/colorRegistry.releaseTest.ts | 2 +- src/vs/workbench/workbench.main.ts | 4 ++-- 15 files changed, 8 insertions(+), 8 deletions(-) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/dirtydiffDecorator.ts (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/media/check-inverse.svg (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/media/check.svg (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/media/dirtydiffDecorator.css (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/media/icon-dark.svg (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/media/icon-light.svg (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/media/scmViewlet.css (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/scm.contribution.ts (98%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/scmActivity.ts (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/scmMenus.ts (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/scmUtil.ts (100%) rename src/vs/workbench/contrib/scm/{electron-browser => browser}/scmViewlet.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index d8bae789a91..7bed7f931fe 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -255,10 +255,10 @@ "./vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution.ts", "./vs/workbench/contrib/scm/common/scm.ts", "./vs/workbench/contrib/scm/common/scmService.ts", - "./vs/workbench/contrib/scm/electron-browser/dirtydiffDecorator.ts", - "./vs/workbench/contrib/scm/electron-browser/scmActivity.ts", - "./vs/workbench/contrib/scm/electron-browser/scmMenus.ts", - "./vs/workbench/contrib/scm/electron-browser/scmUtil.ts", + "./vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts", + "./vs/workbench/contrib/scm/browser/scmActivity.ts", + "./vs/workbench/contrib/scm/browser/scmMenus.ts", + "./vs/workbench/contrib/scm/browser/scmUtil.ts", "./vs/workbench/contrib/search/browser/openAnythingHandler.ts", "./vs/workbench/contrib/search/browser/openFileHandler.ts", "./vs/workbench/contrib/search/browser/openSymbolHandler.ts", diff --git a/src/vs/workbench/contrib/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/dirtydiffDecorator.ts rename to src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts diff --git a/src/vs/workbench/contrib/scm/electron-browser/media/check-inverse.svg b/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/media/check-inverse.svg rename to src/vs/workbench/contrib/scm/browser/media/check-inverse.svg diff --git a/src/vs/workbench/contrib/scm/electron-browser/media/check.svg b/src/vs/workbench/contrib/scm/browser/media/check.svg similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/media/check.svg rename to src/vs/workbench/contrib/scm/browser/media/check.svg diff --git a/src/vs/workbench/contrib/scm/electron-browser/media/dirtydiffDecorator.css b/src/vs/workbench/contrib/scm/browser/media/dirtydiffDecorator.css similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/media/dirtydiffDecorator.css rename to src/vs/workbench/contrib/scm/browser/media/dirtydiffDecorator.css diff --git a/src/vs/workbench/contrib/scm/electron-browser/media/icon-dark.svg b/src/vs/workbench/contrib/scm/browser/media/icon-dark.svg similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/media/icon-dark.svg rename to src/vs/workbench/contrib/scm/browser/media/icon-dark.svg diff --git a/src/vs/workbench/contrib/scm/electron-browser/media/icon-light.svg b/src/vs/workbench/contrib/scm/browser/media/icon-light.svg similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/media/icon-light.svg rename to src/vs/workbench/contrib/scm/browser/media/icon-light.svg diff --git a/src/vs/workbench/contrib/scm/electron-browser/media/scmViewlet.css b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/media/scmViewlet.css rename to src/vs/workbench/contrib/scm/browser/media/scmViewlet.css diff --git a/src/vs/workbench/contrib/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts similarity index 98% rename from src/vs/workbench/contrib/scm/electron-browser/scm.contribution.ts rename to src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 70258e96a6a..9172c0ab736 100644 --- a/src/vs/workbench/contrib/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -14,7 +14,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { StatusUpdater, StatusBarController } from './scmActivity'; -import { SCMViewlet } from 'vs/workbench/contrib/scm/electron-browser/scmViewlet'; +import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; diff --git a/src/vs/workbench/contrib/scm/electron-browser/scmActivity.ts b/src/vs/workbench/contrib/scm/browser/scmActivity.ts similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/scmActivity.ts rename to src/vs/workbench/contrib/scm/browser/scmActivity.ts diff --git a/src/vs/workbench/contrib/scm/electron-browser/scmMenus.ts b/src/vs/workbench/contrib/scm/browser/scmMenus.ts similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/scmMenus.ts rename to src/vs/workbench/contrib/scm/browser/scmMenus.ts diff --git a/src/vs/workbench/contrib/scm/electron-browser/scmUtil.ts b/src/vs/workbench/contrib/scm/browser/scmUtil.ts similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/scmUtil.ts rename to src/vs/workbench/contrib/scm/browser/scmUtil.ts diff --git a/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts similarity index 100% rename from src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts rename to src/vs/workbench/contrib/scm/browser/scmViewlet.ts diff --git a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts index 096e70ce7d2..1da752ea1f9 100644 --- a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts +++ b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts @@ -6,7 +6,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IColorRegistry, Extensions, ColorContribution } from 'vs/platform/theme/common/colorRegistry'; import { editorMarkerNavigationError } from 'vs/editor/contrib/gotoError/gotoErrorWidget'; -import { overviewRulerModifiedForeground } from 'vs/workbench/contrib/scm/electron-browser/dirtydiffDecorator'; +import { overviewRulerModifiedForeground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator'; import { STATUS_BAR_DEBUGGING_BACKGROUND } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { debugExceptionWidgetBackground } from 'vs/workbench/contrib/debug/browser/exceptionWidget'; import { debugToolBarBackground } from 'vs/workbench/contrib/debug/browser/debugToolbar'; diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 69bf6bcd8ce..3487d9ab09a 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -121,8 +121,8 @@ import 'vs/workbench/contrib/search/browser/searchView'; import 'vs/workbench/contrib/search/browser/openAnythingHandler'; // SCM -import 'vs/workbench/contrib/scm/electron-browser/scm.contribution'; -import 'vs/workbench/contrib/scm/electron-browser/scmViewlet'; +import 'vs/workbench/contrib/scm/browser/scm.contribution'; +import 'vs/workbench/contrib/scm/browser/scmViewlet'; // Debug import 'vs/workbench/contrib/debug/electron-browser/debug.contribution'; From 532213ed2650198c35cc52026efa6f59b055a87f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 11:55:46 +0100 Subject: [PATCH 76/88] :lipstick: --- src/vs/workbench/browser/actions.ts | 11 +-- src/vs/workbench/common/contributions.ts | 13 ++-- src/vs/workbench/common/editor.ts | 11 +-- .../workbench/electron-browser/workbench.ts | 71 +++++++++++-------- .../browser/parts/editor/baseEditor.test.ts | 2 +- .../test/common/editor/editorGroups.test.ts | 10 +-- 6 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/vs/workbench/browser/actions.ts b/src/vs/workbench/browser/actions.ts index c6355e52f00..a31b6947af2 100644 --- a/src/vs/workbench/browser/actions.ts +++ b/src/vs/workbench/browser/actions.ts @@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action, IAction } from 'vs/base/common/actions'; import { BaseActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; -import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; /** * The action bar contributor allows to add actions to an actionbar in a given context. @@ -235,7 +235,10 @@ export interface IActionBarRegistry { */ getActionBarContributors(scope: string): ActionBarContributor[]; - setInstantiationService(service: IInstantiationService): void; + /** + * Starts the registry by providing the required services. + */ + start(accessor: ServicesAccessor): void; } class ActionBarRegistry implements IActionBarRegistry { @@ -243,8 +246,8 @@ class ActionBarRegistry implements IActionBarRegistry { private actionBarContributorInstances: { [scope: string]: ActionBarContributor[] } = Object.create(null); private instantiationService: IInstantiationService; - setInstantiationService(service: IInstantiationService): void { - this.instantiationService = service; + start(accessor: ServicesAccessor): void { + this.instantiationService = accessor.get(IInstantiationService); while (this.actionBarContributorConstructors.length > 0) { const entry = this.actionBarContributorConstructors.shift()!; diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index 01a8631bf8f..e60c8dbc795 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { runWhenIdle, IdleDeadline } from 'vs/base/common/async'; @@ -34,10 +34,9 @@ export interface IWorkbenchContributionsRegistry { /** * Starts the registry by providing the required services. */ - start(instantiationService: IInstantiationService, lifecycleService: ILifecycleService): void; + start(accessor: ServicesAccessor): void; } - class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry { private instantiationService: IInstantiationService; private lifecycleService: ILifecycleService; @@ -63,12 +62,12 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry } } - start(instantiationService: IInstantiationService, lifecycleService: ILifecycleService): void { - this.instantiationService = instantiationService; - this.lifecycleService = lifecycleService; + start(accessor: ServicesAccessor): void { + this.instantiationService = accessor.get(IInstantiationService); + this.lifecycleService = accessor.get(ILifecycleService); [LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually].forEach(phase => { - this.instantiateByPhase(instantiationService, lifecycleService, phase); + this.instantiateByPhase(this.instantiationService, this.lifecycleService, phase); }); } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index bd9740edb23..6a016bc91cc 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon'; import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput } from 'vs/platform/editor/common/editor'; -import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITextModel } from 'vs/editor/common/model'; @@ -175,7 +175,10 @@ export interface IEditorInputFactoryRegistry { */ getEditorInputFactory(editorInputId: string): IEditorInputFactory; - setInstantiationService(service: IInstantiationService): void; + /** + * Starts the registry by providing the required services. + */ + start(accessor: ServicesAccessor): void; } export interface IEditorInputFactory { @@ -1034,8 +1037,8 @@ class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { private editorInputFactoryConstructors: { [editorInputId: string]: IConstructorSignature0 } = Object.create(null); private editorInputFactoryInstances: { [editorInputId: string]: IEditorInputFactory } = Object.create(null); - setInstantiationService(service: IInstantiationService): void { - this.instantiationService = service; + start(accessor: ServicesAccessor): void { + this.instantiationService = accessor.get(IInstantiationService); for (let key in this.editorInputFactoryConstructors) { const element = this.editorInputFactoryConstructors[key]; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index d293d8e11b0..b79377cfcbe 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -311,11 +311,14 @@ export class Workbench extends Disposable implements IPartService { readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), getZoomLevel())); // Create Workbench Container - this.createWorkbench(); + this.createWorkbenchContainer(); // Services this.initServices(this.serviceCollection); + // Registries + this.startRegistries(); + // Context Keys this._register(this.instantiationService.createInstance(WorkbenchContextKeysHandler)); @@ -343,7 +346,7 @@ export class Workbench extends Disposable implements IPartService { return this.restoreParts().then(() => this.whenStarted(), error => this.whenStarted(error)); } - private createWorkbench(): void { + private createWorkbenchContainer(): void { this.workbench = document.createElement('div'); const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac'; @@ -415,8 +418,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService, undefined, true)); // Remote Resolver - const remoteAuthorityResolverService = new RemoteAuthorityResolverService(); - serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); + serviceCollection.set(IRemoteAuthorityResolverService, new SyncDescriptor(RemoteAuthorityResolverService, undefined, true)); // Remote Agent const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService); @@ -552,15 +554,18 @@ export class Workbench extends Disposable implements IPartService { remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService)); } - // Set the some services to registries that have been created eagerly - Registry.as(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService); - Registry.as(WorkbenchExtensions.Workbench).start(this.instantiationService, this.lifecycleService); - Registry.as(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService); - // TODO@Sandeep debt around cyclic dependencies this.configurationService.acquireInstantiationService(this.instantiationService); } + private startRegistries(): void { + this.instantiationService.invokeFunction(accessor => { + Registry.as(ActionBarExtensions.Actionbar).start(accessor); + Registry.as(WorkbenchExtensions.Workbench).start(accessor); + Registry.as(EditorExtensions.EditorInputFactories).start(accessor); + }); + } + private hasInitialFilesToOpen(): boolean { return !!( (this.configuration.filesToCreate && this.configuration.filesToCreate.length > 0) || @@ -577,6 +582,25 @@ export class Workbench extends Disposable implements IPartService { this._register(this.configurationService.onDidChangeConfiguration(() => this.setFontAliasing())); } + private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto'; + private setFontAliasing() { + const aliasing = this.configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>(Settings.FONT_ALIASING); + if (this.fontAliasing === aliasing) { + return; + } + + this.fontAliasing = aliasing; + + // Remove all + const fontAliasingValues: (typeof aliasing)[] = ['antialiased', 'none', 'auto']; + removeClasses(this.workbench, ...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`)); + + // Add specific + if (fontAliasingValues.some(option => option === aliasing)) { + addClass(this.workbench, `monaco-font-aliasing-${aliasing}`); + } + } + private renderWorkbench(): void { if (this.state.sideBar.hidden) { addClass(this.workbench, 'nosidebar'); @@ -612,25 +636,6 @@ export class Workbench extends Disposable implements IPartService { this.container.appendChild(this.workbench); } - private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto'; - private setFontAliasing() { - const aliasing = this.configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>(Settings.FONT_ALIASING); - if (this.fontAliasing === aliasing) { - return; - } - - this.fontAliasing = aliasing; - - // Remove all - const fontAliasingValues: (typeof aliasing)[] = ['antialiased', 'none', 'auto']; - removeClasses(this.workbench, ...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`)); - - // Add specific - if (fontAliasingValues.some(option => option === aliasing)) { - addClass(this.workbench, `monaco-font-aliasing-${aliasing}`); - } - } - private createTitlebarPart(): void { const titlebarContainer = this.createPart(Identifiers.TITLEBAR_PART, 'contentinfo', 'titlebar'); @@ -736,14 +741,20 @@ export class Workbench extends Disposable implements IPartService { if (this.state.sideBar.viewletToRestore) { mark('willRestoreViewlet'); restorePromises.push(this.sidebarPart.openViewlet(this.state.sideBar.viewletToRestore) - .then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId())) + .then(viewlet => { + if (!viewlet) { + return this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId()); // fallback to default viewlet as needed + } + + return viewlet; + }) .then(() => mark('didRestoreViewlet'))); } // Restore Panel if (this.state.panel.panelToRestore) { mark('willRestorePanel'); - this.panelPart.openPanel(this.state.panel.panelToRestore, false); + this.panelPart.openPanel(this.state.panel.panelToRestore); mark('didRestorePanel'); } diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index b959ede3928..4f7400dbc91 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -180,7 +180,7 @@ suite('Workbench base editor', () => { }); test('Editor Input Factory', function () { - EditorInputRegistry.setInstantiationService(workbenchInstantiationService()); + workbenchInstantiationService().invokeFunction(accessor => EditorInputRegistry.start(accessor)); EditorInputRegistry.registerEditorInputFactory('myInputId', MyInputFactory); let factory = EditorInputRegistry.getEditorInputFactory('myInputId'); diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index bc186f8d331..fde39c097be 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -215,7 +215,7 @@ suite('Workbench editor groups', () => { }); test('group serialization', function () { - Registry.as(EditorExtensions.EditorInputFactories).setInstantiationService(inst()); + inst().invokeFunction(accessor => Registry.as(EditorExtensions.EditorInputFactories).start(accessor)); const group = createGroup(); const input1 = input(); @@ -1003,7 +1003,7 @@ suite('Workbench editor groups', () => { config.setUserConfiguration('workbench', { editor: { openPositioning: 'right' } }); inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); + inst.invokeFunction(accessor => Registry.as(EditorExtensions.EditorInputFactories).start(accessor)); let group = createGroup(); @@ -1037,7 +1037,7 @@ suite('Workbench editor groups', () => { config.setUserConfiguration('workbench', { editor: { openPositioning: 'right' } }); inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); + inst.invokeFunction(accessor => Registry.as(EditorExtensions.EditorInputFactories).start(accessor)); let group1 = createGroup(); @@ -1107,7 +1107,7 @@ suite('Workbench editor groups', () => { config.setUserConfiguration('workbench', { editor: { openPositioning: 'right' } }); inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); + inst.invokeFunction(accessor => Registry.as(EditorExtensions.EditorInputFactories).start(accessor)); let group = createGroup(); @@ -1151,7 +1151,7 @@ suite('Workbench editor groups', () => { config.setUserConfiguration('workbench', { editor: { openPositioning: 'right' } }); inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); + inst.invokeFunction(accessor => Registry.as(EditorExtensions.EditorInputFactories).start(accessor)); let group1 = createGroup(); let group2 = createGroup(); From 3996321aaa07d3e14fe71aa3b3a3b7f5f1261a26 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 11:59:19 +0100 Subject: [PATCH 77/88] fix compile issue --- src/vs/workbench/electron-browser/workbench.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index b79377cfcbe..9e386737a68 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -421,8 +421,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IRemoteAuthorityResolverService, new SyncDescriptor(RemoteAuthorityResolverService, undefined, true)); // Remote Agent - const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService); - serviceCollection.set(IRemoteAgentService, remoteAgentService); + serviceCollection.set(IRemoteAgentService, new SyncDescriptor(RemoteAgentService, [this.configuration])); // Extensions Management const extensionManagementChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('extensions'))); @@ -547,12 +546,14 @@ export class Workbench extends Disposable implements IPartService { } // TODO this should move somewhere else - const remoteAgentConnection = remoteAgentService.getConnection(); - if (remoteAgentConnection) { - remoteAgentConnection.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel)); - remoteAgentConnection.registerChannel('download', new DownloadServiceChannel()); - remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService)); - } + this.instantiationService.invokeFunction(accessor => { + const remoteAgentConnection = accessor.get(IRemoteAgentService).getConnection(); + if (remoteAgentConnection) { + remoteAgentConnection.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel)); + remoteAgentConnection.registerChannel('download', new DownloadServiceChannel()); + remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService)); + } + }); // TODO@Sandeep debt around cyclic dependencies this.configurationService.acquireInstantiationService(this.instantiationService); From 54da2fb645afdb5f4e155f50bf7ec6929f569620 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 12:22:41 +0100 Subject: [PATCH 78/88] :lipstick: --- .../workbench/electron-browser/workbench.ts | 101 +++++++++++------- 1 file changed, 64 insertions(+), 37 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 9e386737a68..1d3363dfb8b 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -103,6 +103,8 @@ import { WorkbenchThemeService } from 'vs/workbench/services/themes/browser/work import { IProductService } from 'vs/platform/product/common/product'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { WorkbenchContextKeysHandler } from 'vs/workbench/browser/contextkeys'; +import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; // import@node import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; @@ -190,13 +192,17 @@ export class Workbench extends Disposable implements IPartService { private editorService: EditorService; private editorGroupService: IEditorGroupsService; private contextViewService: ContextViewService; - private keybindingService: IKeybindingService; private backupFileService: IBackupFileService; private notificationService: NotificationService; - private themeService: WorkbenchThemeService; - private telemetryService: ITelemetryService; private windowService: IWindowService; private lifecycleService: LifecycleService; + private instantiationService: IInstantiationService; + private contextService: IWorkspaceContextService; + private storageService: IStorageService; + private configurationService: WorkspaceService; + private environmentService: IEnvironmentService; + private logService: ILogService; + private windowsService: IWindowsService; private titlebarPart: TitlebarPart; private activitybarPart: ActivitybarPart; @@ -215,16 +221,24 @@ export class Workbench extends Disposable implements IPartService { private container: HTMLElement, private configuration: IWindowConfiguration, private serviceCollection: ServiceCollection, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IStorageService private readonly storageService: IStorageService, - @IConfigurationService private readonly configurationService: WorkspaceService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILogService private readonly logService: ILogService, - @IWindowsService private readonly windowsService: IWindowsService + @IInstantiationService instantiationService: IInstantiationService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IStorageService storageService: IStorageService, + @IConfigurationService configurationService: WorkspaceService, + @IEnvironmentService environmentService: IEnvironmentService, + @ILogService logService: ILogService, + @IWindowsService windowsService: IWindowsService ) { super(); + this.instantiationService = instantiationService; + this.contextService = contextService; + this.storageService = storageService; + this.configurationService = configurationService; + this.environmentService = environmentService; + this.logService = logService; + this.windowsService = windowsService; + this.registerErrorHandler(); } @@ -343,7 +357,7 @@ export class Workbench extends Disposable implements IPartService { this.lifecycleService.when(LifecyclePhase.Restored).then(() => clearTimeout(timeoutHandle)); // Restore Parts - return this.restoreParts().then(() => this.whenStarted(), error => this.whenStarted(error)); + return this.restoreParts().then(() => this.instantiationService.invokeFunction(accessor => this.whenStarted(accessor)), error => this.instantiationService.invokeFunction(accessor => this.whenStarted(accessor, error))); } private createWorkbenchContainer(): void { @@ -385,6 +399,7 @@ export class Workbench extends Disposable implements IPartService { }); // Telemetry + let telemetryService: ITelemetryService; if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!productService.enableTelemetry) { const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); const config: ITelemetryServiceConfig = { @@ -393,14 +408,14 @@ export class Workbench extends Disposable implements IPartService { piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath] }; - this.telemetryService = this._register(this.instantiationService.createInstance(TelemetryService, config)); - this._register(new ErrorTelemetry(this.telemetryService)); + telemetryService = this._register(this.instantiationService.createInstance(TelemetryService, config)); + this._register(new ErrorTelemetry(telemetryService)); } else { - this.telemetryService = NullTelemetryService; + telemetryService = NullTelemetryService; } - serviceCollection.set(ITelemetryService, this.telemetryService); - this._register(configurationTelemetry(this.telemetryService, this.configurationService)); + serviceCollection.set(ITelemetryService, telemetryService); + this._register(configurationTelemetry(telemetryService, this.configurationService)); // Lifecycle this.lifecycleService = this.instantiationService.createInstance(LifecycleService); @@ -436,8 +451,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IExtensionService, new SyncDescriptor(ExtensionService)); // Theming - this.themeService = this.instantiationService.createInstance(WorkbenchThemeService, document.body); - serviceCollection.set(IWorkbenchThemeService, this.themeService); + serviceCollection.set(IWorkbenchThemeService, new SyncDescriptor(WorkbenchThemeService, [document.body])); // Commands serviceCollection.set(ICommandService, new SyncDescriptor(CommandService, undefined, true)); @@ -469,8 +483,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IContextKeyService, new SyncDescriptor(ContextKeyService)); // Keybindings - this.keybindingService = this.instantiationService.createInstance(WorkbenchKeybindingService, window); - serviceCollection.set(IKeybindingService, this.keybindingService); + serviceCollection.set(IKeybindingService, new SyncDescriptor(WorkbenchKeybindingService, [window])); // Context view service this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench); @@ -501,10 +514,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IActivityService, new SyncDescriptor(ActivityService, [this.activitybarPart, this.panelPart], true)); // File Service - const fileService = this.instantiationService.createInstance(RemoteFileService); - serviceCollection.set(IFileService, fileService); - this.configurationService.acquireFileService(fileService); - this.themeService.acquireFileService(fileService); + serviceCollection.set(IFileService, new SyncDescriptor(RemoteFileService)); // Editor and Group services this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasInitialFilesToOpen()); @@ -545,7 +555,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(contributedService.id, contributedService.descriptor); } - // TODO this should move somewhere else + // TODO@Alex TODO@Sandeep this should move somewhere else this.instantiationService.invokeFunction(accessor => { const remoteAgentConnection = accessor.get(IRemoteAgentService).getConnection(); if (remoteAgentConnection) { @@ -555,8 +565,17 @@ export class Workbench extends Disposable implements IPartService { } }); - // TODO@Sandeep debt around cyclic dependencies - this.configurationService.acquireInstantiationService(this.instantiationService); + // TODO@Sandeep TODO@Martin debt around cyclic dependencies + this.instantiationService.invokeFunction(accessor => { + const fileService = accessor.get(IFileService); + const instantiationService = accessor.get(IInstantiationService); + const themeService = accessor.get(IThemeService) as WorkbenchThemeService; + + this.configurationService.acquireFileService(fileService); + this.configurationService.acquireInstantiationService(instantiationService); + + themeService.acquireFileService(fileService); + }); } private startRegistries(): void { @@ -772,17 +791,25 @@ export class Workbench extends Disposable implements IPartService { return Promise.all(restorePromises); } - private whenStarted(error?: Error): void { + private whenStarted(accessor: ServicesAccessor, error?: Error): void { + const themeService = accessor.get(IWorkbenchThemeService); + const keybindingsService = accessor.get(IKeybindingService); + const lifecycleService = accessor.get(ILifecycleService) as LifecycleService; + const editorService = accessor.get(IEditorService); + const activityService = accessor.get(IActivityService); + const contextService = accessor.get(IWorkspaceContextService); + const telemetryService = accessor.get(ITelemetryService); + this.restored = true; // Set lifecycle phase to `Restored` - this.lifecycleService.phase = LifecyclePhase.Restored; + lifecycleService.phase = LifecyclePhase.Restored; // Set lifecycle phase to `Eventually` after a short delay and when // idle (min 2.5sec, max 5sec) setTimeout(() => { this._register(runWhenIdle(() => { - this.lifecycleService.phase = LifecyclePhase.Eventually; + lifecycleService.phase = LifecyclePhase.Eventually; }, 2500)); }, 2500); @@ -813,20 +840,20 @@ export class Workbench extends Disposable implements IPartService { "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } } */ - this.telemetryService.publicLog('workspaceLoad', { + telemetryService.publicLog('workspaceLoad', { userAgent: navigator.userAgent, windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, - emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY, + emptyWorkbench: contextService.getWorkbenchState() === WorkbenchState.EMPTY, 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, - customKeybindingsCount: this.keybindingService.customKeybindingsCount(), - theme: this.themeService.getColorTheme().id, + customKeybindingsCount: keybindingsService.customKeybindingsCount(), + theme: themeService.getColorTheme().id, language, - pinnedViewlets: this.activitybarPart.getPinnedViewletIds(), + pinnedViewlets: activityService.getPinnedViewletIds(), restoredViewlet: this.state.sideBar.viewletToRestore, - restoredEditors: this.editorService.visibleEditors.length, - startupKind: this.lifecycleService.startupKind + restoredEditors: editorService.visibleEditors.length, + startupKind: lifecycleService.startupKind }); // Telemetry: startup metrics From ef20041efe558573f442e0eccdc7b41af2430d75 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 12:24:55 +0100 Subject: [PATCH 79/88] use IWorkbenchThemeService as import --- src/vs/workbench/electron-browser/workbench.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 1d3363dfb8b..44ec80fb496 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -104,7 +104,6 @@ import { IProductService } from 'vs/platform/product/common/product'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { WorkbenchContextKeysHandler } from 'vs/workbench/browser/contextkeys'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; // import@node import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; @@ -569,7 +568,7 @@ export class Workbench extends Disposable implements IPartService { this.instantiationService.invokeFunction(accessor => { const fileService = accessor.get(IFileService); const instantiationService = accessor.get(IInstantiationService); - const themeService = accessor.get(IThemeService) as WorkbenchThemeService; + const themeService = accessor.get(IWorkbenchThemeService) as WorkbenchThemeService; this.configurationService.acquireFileService(fileService); this.configurationService.acquireInstantiationService(instantiationService); From e8e7703ab497f70677e922434393ff5be100b109 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 12:30:06 +0100 Subject: [PATCH 80/88] fix #69406 --- .../services/markerDecorationsServiceImpl.ts | 27 ++++++++++++++++--- .../services/markersDecorationService.ts | 8 +++++- .../contrib/documentSymbols/outlineModel.ts | 20 +++++++++----- .../contrib/outline/browser/outlinePanel.ts | 22 +++++++-------- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index ecf4af882d6..70748519a41 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -15,6 +15,7 @@ import { Range } from 'vs/editor/common/core/range'; import { keys } from 'vs/base/common/map'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { Schemas } from 'vs/base/common/network'; +import { Emitter, Event } from 'vs/base/common/event'; function MODEL_ID(resource: URI): string { return resource.toString(); @@ -44,12 +45,26 @@ class MarkerDecorations extends Disposable { getMarker(decoration: IModelDecoration): IMarker | undefined { return this._markersData.get(decoration.id); } + + getMarkers(): [Range, IMarker][] { + const res: [Range, IMarker][] = []; + this._markersData.forEach((marker, id) => { + let range = this.model.getDecorationRange(id); + if (range) { + res.push([range, marker]); + } + }); + return res; + } } export class MarkerDecorationsService extends Disposable implements IMarkerDecorationsService { _serviceBrand: any; + private readonly _onDidChangeMarker = new Emitter(); + readonly onDidChangeMarker: Event = this._onDidChangeMarker.event; + private readonly _markerDecorations: Map = new Map(); constructor( @@ -68,11 +83,16 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor return markerDecorations ? markerDecorations.getMarker(decoration) || null : null; } + getLiveMarkers(model: ITextModel): [Range, IMarker][] { + const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri)); + return markerDecorations ? markerDecorations.getMarkers() : []; + } + private _handleMarkerChange(changedResources: URI[]): void { changedResources.forEach((resource) => { const markerDecorations = this._markerDecorations.get(MODEL_ID(resource)); if (markerDecorations) { - this.updateDecorations(markerDecorations); + this._updateDecorations(markerDecorations); } }); } @@ -80,7 +100,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor private _onModelAdded(model: ITextModel): void { const markerDecorations = new MarkerDecorations(model); this._markerDecorations.set(MODEL_ID(model.uri), markerDecorations); - this.updateDecorations(markerDecorations); + this._updateDecorations(markerDecorations); } private _onModelRemoved(model: ITextModel): void { @@ -100,7 +120,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor } } - private updateDecorations(markerDecorations: MarkerDecorations): void { + private _updateDecorations(markerDecorations: MarkerDecorations): void { // Limit to the first 500 errors/warnings const markers = this._markerService.read({ resource: markerDecorations.model.uri, take: 500 }); let newModelDecorations: IModelDeltaDecoration[] = markers.map((marker) => { @@ -110,6 +130,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor }; }); markerDecorations.update(markers, newModelDecorations); + this._onDidChangeMarker.fire(markerDecorations.model); } private _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range { diff --git a/src/vs/editor/common/services/markersDecorationService.ts b/src/vs/editor/common/services/markersDecorationService.ts index b2424a4d312..44aa7ca2463 100644 --- a/src/vs/editor/common/services/markersDecorationService.ts +++ b/src/vs/editor/common/services/markersDecorationService.ts @@ -6,11 +6,17 @@ import { ITextModel, IModelDecoration } from 'vs/editor/common/model'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IMarker } from 'vs/platform/markers/common/markers'; +import { Event } from 'vs/base/common/event'; +import { Range } from 'vs/editor/common/core/range'; export const IMarkerDecorationsService = createDecorator('markerDecorationsService'); export interface IMarkerDecorationsService { _serviceBrand: any; + onDidChangeMarker: Event; + getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null; -} \ No newline at end of file + + getLiveMarkers(model: ITextModel): [Range, IMarker][]; +} diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index 759ea82e044..61991f8a654 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -13,7 +13,7 @@ import { IPosition } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ITextModel } from 'vs/editor/common/model'; import { DocumentSymbol, DocumentSymbolProvider, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes'; -import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers'; +import { MarkerSeverity } from 'vs/platform/markers/common/markers'; export abstract class TreeElement { @@ -86,6 +86,14 @@ export abstract class TreeElement { } } +export interface IOutlineMarker { + startLineNumber: number; + startColumn: number; + endLineNumber: number; + endColumn: number; + severity: MarkerSeverity; +} + export class OutlineElement extends TreeElement { children: { [id: string]: OutlineElement; } = Object.create(null); @@ -140,13 +148,13 @@ export class OutlineGroup extends TreeElement { return undefined; } - updateMarker(marker: IMarker[]): void { + updateMarker(marker: IOutlineMarker[]): void { for (const key in this.children) { this._updateMarker(marker, this.children[key]); } } - private _updateMarker(markers: IMarker[], item: OutlineElement): void { + private _updateMarker(markers: IOutlineMarker[], item: OutlineElement): void { item.marker = undefined; // find the proper start index to check for item/marker overlap. @@ -161,7 +169,7 @@ export class OutlineGroup extends TreeElement { start = idx; } - let myMarkers: IMarker[] = []; + let myMarkers: IOutlineMarker[] = []; let myTopSev: MarkerSeverity | undefined; for (; start < markers.length && Range.areIntersecting(item.symbol.range, markers[start]); start++) { @@ -169,7 +177,7 @@ export class OutlineGroup extends TreeElement { // and store them in a 'private' array. let marker = markers[start]; myMarkers.push(marker); - (markers as Array)[start] = undefined; + (markers as Array)[start] = undefined; if (!myTopSev || marker.severity > myTopSev) { myTopSev = marker.severity; } @@ -413,7 +421,7 @@ export class OutlineModel extends TreeElement { return TreeElement.getElementById(id, this); } - updateMarker(marker: IMarker[]): void { + updateMarker(marker: IOutlineMarker[]): void { // sort markers by start range so that we can use // outline element starts for quicker look up marker.sort(Range.compareRangesUsingStarts); diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 59dbfe4c344..a083b522f01 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -7,7 +7,6 @@ import * as dom from 'vs/base/browser/dom'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { Action, IAction, RadioGroup } from 'vs/base/common/actions'; -import { firstIndex } from 'vs/base/common/arrays'; import { createCancelablePromise, TimeoutTimer } from 'vs/base/common/async'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { Emitter } from 'vs/base/common/event'; @@ -15,7 +14,6 @@ import { defaultGenerator } from 'vs/base/common/idGenerator'; import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LRUCache } from 'vs/base/common/map'; import { escape } from 'vs/base/common/strings'; -import { URI } from 'vs/base/common/uri'; import 'vs/css!./outlinePanel'; import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; @@ -24,7 +22,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { DocumentSymbolProviderRegistry } from 'vs/editor/common/modes'; import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; -import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; +import { OutlineElement, OutlineModel, TreeElement, IOutlineMarker } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -33,7 +31,6 @@ import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { WorkbenchDataTree } from 'vs/platform/list/browser/listService'; -import { IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -48,6 +45,7 @@ import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { basename } from 'vs/base/common/resources'; import { IDataSource } from 'vs/base/browser/ui/tree/tree'; +import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; class RequestState { @@ -261,7 +259,7 @@ export class OutlinePanel extends ViewletPanel { @IThemeService private readonly _themeService: IThemeService, @IStorageService private readonly _storageService: IStorageService, @IEditorService private readonly _editorService: IEditorService, - @IMarkerService private readonly _markerService: IMarkerService, + @IMarkerDecorationsService private readonly _markerDecorationService: IMarkerDecorationsService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService, @IConfigurationService configurationService: IConfigurationService, @@ -569,21 +567,23 @@ export class OutlinePanel extends ViewletPanel { })); // feature: show markers in outline - const updateMarker = (e: URI[], ignoreEmpty?: boolean) => { + const updateMarker = (model: ITextModel, ignoreEmpty?: boolean) => { if (!this._configurationService.getValue(OutlineConfigKeys.problemsEnabled)) { return; } - if (firstIndex(e, a => a.toString() === textModel.uri.toString()) < 0) { + if (model !== textModel) { return; } - const marker = this._markerService.read({ resource: textModel.uri, severities: MarkerSeverity.Error | MarkerSeverity.Warning }); + const marker = this._markerDecorationService.getLiveMarkers(textModel).map(([range, marker]) => { + return { ...range, severity: marker.severity } as IOutlineMarker; + }); if (marker.length > 0 || !ignoreEmpty) { newModel.updateMarker(marker); this._tree.updateChildren(); } }; - updateMarker([textModel.uri], true); - this._editorDisposables.push(this._markerService.onMarkerChanged(updateMarker)); + updateMarker(textModel, true); + this._editorDisposables.push(this._markerDecorationService.onDidChangeMarker(updateMarker)); this._editorDisposables.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(OutlineConfigKeys.problemsBadges) || e.affectsConfiguration(OutlineConfigKeys.problemsColors)) { @@ -597,7 +597,7 @@ export class OutlinePanel extends ViewletPanel { newModel.updateMarker([]); this._tree.updateChildren(); } else { - updateMarker([textModel.uri], true); + updateMarker(textModel, true); } })); } From f9bda10403d717dba8da40d8c04db8e95ce4fe35 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 12:43:22 +0100 Subject: [PATCH 81/88] debt - extract a telemetry workbench contribution --- .../browser/telemetry.contribution.ts | 90 +++++++++++++++++++ .../workbench/electron-browser/workbench.ts | 57 ++---------- src/vs/workbench/workbench.main.ts | 3 + 3 files changed, 99 insertions(+), 51 deletions(-) create mode 100644 src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts diff --git a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts new file mode 100644 index 00000000000..b2ca963f342 --- /dev/null +++ b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts @@ -0,0 +1,90 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IActivityService } from 'vs/workbench/services/activity/common/activity'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { language } from 'vs/base/common/platform'; +import { Disposable } from 'vs/base/common/lifecycle'; +import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; +import { configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; + +export class TelemetryContribution extends Disposable implements IWorkbenchContribution { + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IActivityService activityService: IActivityService, + @ILifecycleService lifecycleService: ILifecycleService, + @IEditorService editorService: IEditorService, + @IKeybindingService keybindingsService: IKeybindingService, + @IWorkbenchThemeService themeService: IWorkbenchThemeService, + @IWindowService windowService: IWindowService, + @IConfigurationService configurationService: IConfigurationService, + @IViewletService viewletService: IViewletService + ) { + super(); + + const { filesToOpen, filesToCreate, filesToDiff } = windowService.getConfiguration(); + const activeViewlet = viewletService.getActiveViewlet(); + + /* __GDPR__ + "workspaceLoad" : { + "userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" }, + "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + } + */ + telemetryService.publicLog('workspaceLoad', { + userAgent: navigator.userAgent, + windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, + emptyWorkbench: contextService.getWorkbenchState() === WorkbenchState.EMPTY, + 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, + 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, + 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, + customKeybindingsCount: keybindingsService.customKeybindingsCount(), + theme: themeService.getColorTheme().id, + language, + pinnedViewlets: activityService.getPinnedViewletIds(), + restoredViewlet: activeViewlet ? activeViewlet.getId() : undefined, + restoredEditors: editorService.visibleEditors.length, + startupKind: lifecycleService.startupKind + }); + + // Error Telemetry + this._register(new ErrorTelemetry(telemetryService)); + + // Configuration Telemetry + this._register(configurationTelemetry(telemetryService, configurationService)); + + // Lifecycle + this._register(lifecycleService.onShutdown(() => this.dispose())); + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TelemetryContribution, LifecyclePhase.Restored); \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 44ec80fb496..61dc43e4a62 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -16,7 +16,7 @@ import { mark } from 'vs/base/common/performance'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; -import { isWindows, isLinux, isMacintosh, language } from 'vs/base/common/platform'; +import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, IUntitledResourceInput, IResourceDiffInput } from 'vs/workbench/common/editor'; @@ -82,8 +82,7 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { ILabelService } from 'vs/platform/label/common/label'; import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { combinedAppender, LogAppender, NullTelemetryService, configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; -import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; +import { combinedAppender, LogAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { IExtensionGalleryService, IExtensionManagementServerService, IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; @@ -356,7 +355,10 @@ export class Workbench extends Disposable implements IPartService { this.lifecycleService.when(LifecyclePhase.Restored).then(() => clearTimeout(timeoutHandle)); // Restore Parts - return this.restoreParts().then(() => this.instantiationService.invokeFunction(accessor => this.whenStarted(accessor)), error => this.instantiationService.invokeFunction(accessor => this.whenStarted(accessor, error))); + let error: Error; + return this.restoreParts() + .catch(err => error = err) + .finally(() => this.instantiationService.invokeFunction(accessor => this.whenStarted(accessor, error))); } private createWorkbenchContainer(): void { @@ -408,13 +410,11 @@ export class Workbench extends Disposable implements IPartService { }; telemetryService = this._register(this.instantiationService.createInstance(TelemetryService, config)); - this._register(new ErrorTelemetry(telemetryService)); } else { telemetryService = NullTelemetryService; } serviceCollection.set(ITelemetryService, telemetryService); - this._register(configurationTelemetry(telemetryService, this.configurationService)); // Lifecycle this.lifecycleService = this.instantiationService.createInstance(LifecycleService); @@ -791,13 +791,7 @@ export class Workbench extends Disposable implements IPartService { } private whenStarted(accessor: ServicesAccessor, error?: Error): void { - const themeService = accessor.get(IWorkbenchThemeService); - const keybindingsService = accessor.get(IKeybindingService); const lifecycleService = accessor.get(ILifecycleService) as LifecycleService; - const editorService = accessor.get(IEditorService); - const activityService = accessor.get(IActivityService); - const contextService = accessor.get(IWorkspaceContextService); - const telemetryService = accessor.get(ITelemetryService); this.restored = true; @@ -816,45 +810,6 @@ export class Workbench extends Disposable implements IPartService { onUnexpectedError(error); } - const { filesToOpen, filesToCreate, filesToDiff } = this.configuration; - - /* __GDPR__ - "workspaceLoad" : { - "userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" }, - "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - telemetryService.publicLog('workspaceLoad', { - userAgent: navigator.userAgent, - windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, - emptyWorkbench: contextService.getWorkbenchState() === WorkbenchState.EMPTY, - 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, - 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, - 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, - customKeybindingsCount: keybindingsService.customKeybindingsCount(), - theme: themeService.getColorTheme().id, - language, - pinnedViewlets: activityService.getPinnedViewletIds(), - restoredViewlet: this.state.sideBar.viewletToRestore, - restoredEditors: editorService.visibleEditors.length, - startupKind: lifecycleService.startupKind - }); - // Telemetry: startup metrics mark('didStartWorkbench'); } diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 3487d9ab09a..ceffd2a8727 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -88,6 +88,9 @@ registerSingleton(IClipboardService, ClipboardService, true); //#region --- workbench contributions +// Telemetry +import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; + // Localizations import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; From 3c209bdc83fc18fa0022015a49bc6c693dc79185 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Mar 2019 12:53:36 +0100 Subject: [PATCH 82/88] fix #65997 --- src/vs/editor/common/services/editorSimpleWorker.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index 4ef83f744a7..f5564b6f567 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -491,12 +491,15 @@ export abstract class BaseEditorSimpleWorker { return Promise.resolve(null); } + const seen: Record = Object.create(null); const suggestions: CompletionItem[] = []; const wordDefRegExp = new RegExp(wordDef, wordDefFlags); - const currentWord = model.getWordUntilPosition(position, wordDefRegExp); + const wordUntil = model.getWordUntilPosition(position, wordDefRegExp); - const seen: Record = Object.create(null); - seen[currentWord.word] = true; + const wordAt = model.getWordAtPosition(position, wordDefRegExp); + if (wordAt) { + seen[model.getValueInRange(wordAt)] = true; + } for ( let iter = model.createWordIterator(wordDefRegExp), e = iter.next(); @@ -516,10 +519,9 @@ export abstract class BaseEditorSimpleWorker { kind: CompletionItemKind.Text, label: word, insertText: word, - range: { startLineNumber: position.lineNumber, startColumn: currentWord.startColumn, endLineNumber: position.lineNumber, endColumn: currentWord.endColumn } + range: { startLineNumber: position.lineNumber, startColumn: wordUntil.startColumn, endLineNumber: position.lineNumber, endColumn: wordUntil.endColumn } }); } - return Promise.resolve({ suggestions }); } From f7f4357b9f4dc26483bf621e4dc9269469146491 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 12:56:38 +0100 Subject: [PATCH 83/88] services - sync descriptor for notification service --- src/vs/editor/common/controller/cursor.ts | 4 ++-- .../workbench/electron-browser/workbench.ts | 22 +++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 15ccc7a4e1f..81493777b1c 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import * as strings from 'vs/base/common/strings'; @@ -828,7 +827,8 @@ class CommandExecutor { try { command.getEditOperations(ctx.model, editOperationBuilder); } catch (e) { - e.friendlyMessage = nls.localize('corrupt.commands', "Unexpected exception while executing command."); + // TODO@Alex use notification service if this should be user facing + // e.friendlyMessage = nls.localize('corrupt.commands', "Unexpected exception while executing command."); onUnexpectedError(e); return { operations: [], diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 61dc43e4a62..b1e469d99db 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -191,7 +191,6 @@ export class Workbench extends Disposable implements IPartService { private editorGroupService: IEditorGroupsService; private contextViewService: ContextViewService; private backupFileService: IBackupFileService; - private notificationService: NotificationService; private windowService: IWindowService; private lifecycleService: LifecycleService; private instantiationService: IInstantiationService; @@ -281,11 +280,6 @@ export class Workbench extends Disposable implements IPartService { // Log it this.logService.error(errorMsg); - - // Show to user if friendly message provided - if (error && error.friendlyMessage && this.notificationService) { - this.notificationService.error(error.friendlyMessage); - } } startup(): void { @@ -379,8 +373,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true)); // Notifications - this.notificationService = new NotificationService(); - serviceCollection.set(INotificationService, this.notificationService); + serviceCollection.set(INotificationService, new SyncDescriptor(NotificationService, undefined, true)); // Window this.windowService = this.instantiationService.createInstance(WindowService, this.configuration); @@ -649,7 +642,7 @@ export class Workbench extends Disposable implements IPartService { this.createStatusbarPart(); // Notification Handlers - this.createNotificationsHandlers(); + this.instantiationService.invokeFunction(accessor => this.createNotificationsHandlers(accessor)); // Add Workbench to DOM this.container.appendChild(this.workbench); @@ -706,19 +699,20 @@ export class Workbench extends Disposable implements IPartService { return part; } - private createNotificationsHandlers(): void { + private createNotificationsHandlers(accessor: ServicesAccessor): void { + const notificationService = accessor.get(INotificationService) as NotificationService; // Notifications Center - this.notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench, this.notificationService.model)); + this.notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench, notificationService.model)); // Notifications Toasts - this.notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench, this.notificationService.model)); + this.notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench, notificationService.model)); // Notifications Alerts - this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model)); + this._register(this.instantiationService.createInstance(NotificationsAlerts, notificationService.model)); // Notifications Status - const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, this.notificationService.model); + const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, notificationService.model); // Eventing this._register(this.notificationsCenter.onDidChangeVisibility(() => { From c9370aeaf10450c09b6bb1f25fcc9d70ed5b48e9 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 5 Mar 2019 15:21:23 +0100 Subject: [PATCH 84/88] [css] updates service (multi-semantic selection, webpack) --- .../client/src/cssMain.ts | 42 +++++-------------- extensions/css-language-features/package.json | 2 +- .../server/build/filesFillIn.js | 5 --- .../server/extension.webpack.config.js | 10 +---- .../css-language-features/server/package.json | 4 +- .../server/src/cssServerMain.ts | 6 +-- .../css-language-features/server/yarn.lock | 38 ++++++++--------- extensions/css-language-features/yarn.lock | 28 ++++++------- 8 files changed, 51 insertions(+), 84 deletions(-) delete mode 100644 extensions/css-language-features/server/build/filesFillIn.js diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index 0312498f672..641d11f335b 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -9,8 +9,8 @@ import * as fs from 'fs'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString, workspace, TextDocument, SelectionRange, SelectionRangeKind } from 'vscode'; -import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Disposable, TextDocumentIdentifier } from 'vscode-languageclient'; +import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString, workspace, TextDocument, SelectionRange } from 'vscode'; +import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Disposable } from 'vscode-languageclient'; import { getCustomDataPathsInAllWorkspaces, getCustomDataPathsFromAllExtensions } from './customData'; // this method is called when vs code is activated @@ -83,43 +83,23 @@ export function activate(context: ExtensionContext) { context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - return Promise.all(positions.map(async position => { - const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - if (Array.isArray(rawRanges)) { - return rawRanges.map(r => { + const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); + if (Array.isArray(rawResult)) { + return rawResult.map(rawSelectionRanges => { + return rawSelectionRanges.map(selectionRange => { return { - range: client.protocol2CodeConverter.asRange(r), - kind: SelectionRangeKind.Declaration + range: client.protocol2CodeConverter.asRange(selectionRange.range), + kind: selectionRange.kind }; }); - } - return []; - })); + }); + } + return []; } })); }); }); - const selectionRangeProvider = { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { - const textDocument = TextDocumentIdentifier.create(document.uri.toString()); - return Promise.all(positions.map(async position => { - const rawRanges: Range[] = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - - return rawRanges.map(r => { - const actualRange = new Range(new Position(r.start.line, r.start.character), new Position(r.end.line, r.end.character)); - return { - range: actualRange, - kind: SelectionRangeKind.Declaration - }; - }); - })); - } - }; - documentSelector.forEach(selector => { - languages.registerSelectionRangeProvider(selector, selectionRangeProvider); - }); - function initCompletionProvider(): Disposable { const regionCompletionRegExpr = /^(\s*)(\/(\*\s*(#\w*)?)?)?$/; diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 99b022469d6..ac8a4b23c72 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -726,7 +726,7 @@ ] }, "dependencies": { - "vscode-languageclient": "^5.1.0", + "vscode-languageclient": "^5.2.1", "vscode-nls": "^4.0.0" }, "devDependencies": { diff --git a/extensions/css-language-features/server/build/filesFillIn.js b/extensions/css-language-features/server/build/filesFillIn.js deleted file mode 100644 index 906617384e0..00000000000 --- a/extensions/css-language-features/server/build/filesFillIn.js +++ /dev/null @@ -1,5 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = {}; \ No newline at end of file diff --git a/extensions/css-language-features/server/extension.webpack.config.js b/extensions/css-language-features/server/extension.webpack.config.js index 17dc2d39e34..68b850b3773 100644 --- a/extensions/css-language-features/server/extension.webpack.config.js +++ b/extensions/css-language-features/server/extension.webpack.config.js @@ -9,7 +9,6 @@ const withDefaults = require('../../shared.webpack.config'); const path = require('path'); -var webpack = require('webpack'); module.exports = withDefaults({ context: path.join(__dirname), @@ -19,12 +18,5 @@ module.exports = withDefaults({ output: { filename: 'cssServerMain.js', path: path.join(__dirname, 'dist') - }, - plugins: [ - new webpack.NormalModuleReplacementPlugin( - /[/\\]vscode-languageserver[/\\]lib[/\\]files\.js/, - require.resolve('./build/filesFillIn') - ), - new webpack.IgnorePlugin(/vertx/) - ], + } }); diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index 9bc32c0a788..71e14f56ea2 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -9,8 +9,8 @@ }, "main": "./out/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^3.0.13-next.12", - "vscode-languageserver": "^5.1.0" + "vscode-css-languageservice": "^4.0.0-next.3", + "vscode-languageserver": "^5.3.0-next.2" }, "devDependencies": { "@types/mocha": "2.2.33", diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index 3ef166f1b80..e1c78b158c1 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -335,14 +335,14 @@ connection.onFoldingRanges((params, token) => { }, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token); }); -connection.onRequest('$/textDocument/selectionRange', async (params, token) => { +connection.onRequest('$/textDocument/selectionRanges', async (params, token) => { return runSafe(() => { const document = documents.get(params.textDocument.uri); - const position: Position = params.position; + const positions: Position[] = params.positions; if (document) { const stylesheet = stylesheets.get(document); - return getLanguageService(document).getSelectionRanges(document, position, stylesheet); + return getLanguageService(document).getSelectionRanges(document, positions, stylesheet); } return Promise.resolve(null); }, null, `Error while computing selection ranges for ${params.textDocument.uri}`, token); diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index a2fa388731d..bfbcab4c931 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -229,12 +229,12 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^3.0.13-next.12: - version "3.0.13-next.12" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.13-next.12.tgz#8d20828e41bc7dcf44cdba4b2e476393780a7793" - integrity sha512-5B3NYU2DBFhbUvMuTg7kBlc9COHyr/pbR1cDzXGFwemQG8W6ERsgn+eftPHFbcug1kwBjPVSoMgtw/czKpboHQ== +vscode-css-languageservice@^4.0.0-next.3: + version "4.0.0-next.3" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.0-next.3.tgz#e9529f3b4ddf95c9a3e5dc2a6d701a38280ffa98" + integrity sha512-/xmbWpIQLw+HZ/3LsaE2drHFSNJbM9mZ8bKR5NUiu2ZUr10WbGxX0j/GDZB3LlMmdSHQGgRQ5hTM/Ic2PuBDRw== dependencies: - vscode-languageserver-types "^3.13.0" + vscode-languageserver-types "^3.14.0" vscode-nls "^4.0.0" vscode-jsonrpc@^4.0.0: @@ -242,25 +242,25 @@ vscode-jsonrpc@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== +vscode-languageserver-protocol@3.15.0-next.1: + version "3.15.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.1.tgz#1e45e224d7eef8c79b4bed75b9dcb1930d2ab8ed" + integrity sha512-LXF0d9s3vxFBxVQ4aKl/XghdEMAncGt3dh4urIYa9Is43g3MfIQL9fC44YZtP+XXOrI2rpZU8lRNN01U1V6CDg== dependencies: vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-languageserver-types "3.14.0" -vscode-languageserver-types@3.13.0, vscode-languageserver-types@^3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-languageserver-types@3.14.0, vscode-languageserver-types@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== -vscode-languageserver@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.1.0.tgz#012a28f154cc7a848c443d217894942e4c3eeb39" - integrity sha512-CIsrgx2Y5VHS317g/HwkSTWYBIQmy0DwEyZPmB2pEpVOhYFwVsYpbiJwHIIyLQsQtmRaO4eA2xM8KPjNSdXpBw== +vscode-languageserver@^5.3.0-next.2: + version "5.3.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.2.tgz#31ce4c34d68b517b400ca9e211e43f8d868b8dcc" + integrity sha512-n5onRw9naMrRHp2jnOn+ZwN1n+tTfzftWLPonjp1FWf/iCZWIlnw2TyF/Hn+SDGhLoVtoghmxhwEQaxEAfLHvw== dependencies: - vscode-languageserver-protocol "3.13.0" + vscode-languageserver-protocol "3.15.0-next.1" vscode-uri "^1.0.6" vscode-nls@^4.0.0: diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 6314214090a..385d59738dd 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -167,26 +167,26 @@ vscode-jsonrpc@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== -vscode-languageclient@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.1.0.tgz#650ab0dc9fd0daaade058a8471aaff5bc3f9580e" - integrity sha512-Z95Kps8UqD4o17HE3uCkZuvenOsxHVH46dKmaGVpGixEFZigPaVuVxLM/JWeIY9aRenoC0ZD9CK1O7L4jpffKg== +vscode-languageclient@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz#7cfc83a294c409f58cfa2b910a8cfeaad0397193" + integrity sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q== dependencies: semver "^5.5.0" - vscode-languageserver-protocol "3.13.0" + vscode-languageserver-protocol "3.14.1" -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== +vscode-languageserver-protocol@3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz#b8aab6afae2849c84a8983d39a1cf742417afe2f" + integrity sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g== dependencies: vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-languageserver-types "3.14.0" -vscode-languageserver-types@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-languageserver-types@3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== vscode-nls@^4.0.0: version "4.0.0" From 8e986b18a0bc1656cbde8c13ecb5f9b78c1bc803 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 5 Mar 2019 15:22:49 +0100 Subject: [PATCH 85/88] [html] update service (multi semantic selection, webpack) --- .../client/src/htmlMain.ts | 20 ++++---- .../html-language-features/package.json | 2 +- .../server/build/filesFillIn.js | 5 -- .../server/extension.webpack.config.js | 10 +--- .../server/package.json | 8 ++-- .../server/src/customData.ts | 4 +- .../server/src/htmlServerMain.ts | 8 ++-- .../server/src/modes/htmlMode.ts | 6 +-- .../server/src/modes/languageModes.ts | 4 +- .../html-language-features/server/yarn.lock | 48 +++++++++---------- extensions/html-language-features/yarn.lock | 28 +++++------ 11 files changed, 65 insertions(+), 78 deletions(-) delete mode 100644 extensions/html-language-features/server/build/filesFillIn.js diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 696bc074c84..27f3ad2d626 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, SelectionRange, SelectionRangeKind } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, SelectionRange } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; @@ -92,18 +92,18 @@ export function activate(context: ExtensionContext) { context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - return Promise.all(positions.map(async position => { - const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - if (Array.isArray(rawRanges)) { - return rawRanges.map(r => { + const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); + if (Array.isArray(rawResult)) { + return rawResult.map(rawSelectionRanges => { + return rawSelectionRanges.map(selectionRange => { return { - range: client.protocol2CodeConverter.asRange(r), - kind: SelectionRangeKind.Declaration + range: client.protocol2CodeConverter.asRange(selectionRange.range), + kind: selectionRange.kind }; }); - } - return []; - })); + }); + } + return []; } })); }); diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 64fe111d64b..e44dc9f7102 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -176,7 +176,7 @@ }, "dependencies": { "vscode-extension-telemetry": "0.1.1", - "vscode-languageclient": "^5.1.0", + "vscode-languageclient": "^5.2.1", "vscode-nls": "^4.0.0" }, "devDependencies": { diff --git a/extensions/html-language-features/server/build/filesFillIn.js b/extensions/html-language-features/server/build/filesFillIn.js deleted file mode 100644 index 906617384e0..00000000000 --- a/extensions/html-language-features/server/build/filesFillIn.js +++ /dev/null @@ -1,5 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = {}; \ No newline at end of file diff --git a/extensions/html-language-features/server/extension.webpack.config.js b/extensions/html-language-features/server/extension.webpack.config.js index a535ddeae9a..77b86e718b1 100644 --- a/extensions/html-language-features/server/extension.webpack.config.js +++ b/extensions/html-language-features/server/extension.webpack.config.js @@ -9,7 +9,6 @@ const withDefaults = require('../../shared.webpack.config'); const path = require('path'); -var webpack = require('webpack'); module.exports = withDefaults({ context: path.join(__dirname), @@ -22,12 +21,5 @@ module.exports = withDefaults({ }, externals: { 'typescript': 'commonjs typescript' - }, - plugins: [ - new webpack.NormalModuleReplacementPlugin( - /[/\\]vscode-languageserver[/\\]lib[/\\]files\.js/, - require.resolve('./build/filesFillIn') - ), - new webpack.IgnorePlugin(/vertx/) - ], + } }); diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index bfc23ebe0bc..b01c03a3f15 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,10 +9,10 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^3.0.13-next.10", - "vscode-html-languageservice": "^2.1.11", - "vscode-languageserver": "^5.1.0", - "vscode-languageserver-types": "^3.13.0", + "vscode-css-languageservice": "^4.0.0-next.3", + "vscode-html-languageservice": "^3.0.0-next.3", + "vscode-languageserver": "^5.3.0-next.2", + "vscode-languageserver-types": "^3.14.0", "vscode-nls": "^4.0.0", "vscode-uri": "^1.0.6" }, diff --git a/extensions/html-language-features/server/src/customData.ts b/extensions/html-language-features/server/src/customData.ts index 673e4a4ab9d..1d550eddf9f 100644 --- a/extensions/html-language-features/server/src/customData.ts +++ b/extensions/html-language-features/server/src/customData.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IHTMLDataProvider, HTMLDataProvider } from 'vscode-html-languageservice'; +import { IHTMLDataProvider, newHTMLDataProvider } from 'vscode-html-languageservice'; import * as fs from 'fs'; export function getDataProviders(dataPaths?: string[]): IHTMLDataProvider[] { @@ -18,7 +18,7 @@ export function getDataProviders(dataPaths?: string[]): IHTMLDataProvider[] { if (fs.existsSync(path)) { const htmlData = JSON.parse(fs.readFileSync(path, 'utf-8')); - providers.push(new HTMLDataProvider(`customProvider${i}`, htmlData)); + providers.push(newHTMLDataProvider(`customProvider${i}`, htmlData)); } } catch (err) { console.log(`Failed to load tag from ${path}`); diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index 43ae7d5070c..7974284bd77 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -455,15 +455,15 @@ connection.onFoldingRanges((params, token) => { }, null, `Error while computing folding regions for ${params.textDocument.uri}`, token); }); -connection.onRequest('$/textDocument/selectionRange', async (params, token) => { +connection.onRequest('$/textDocument/selectionRanges', async (params, token) => { return runSafe(() => { const document = documents.get(params.textDocument.uri); - const position: Position = params.position; + const positions: Position[] = params.positions; if (document) { const htmlMode = languageModes.getMode('html'); - if (htmlMode && htmlMode.doSelection) { - return htmlMode.doSelection(document, position); + if (htmlMode && htmlMode.getSelectionRanges) { + return htmlMode.getSelectionRanges(document, positions); } } return Promise.resolve(null); diff --git a/extensions/html-language-features/server/src/modes/htmlMode.ts b/extensions/html-language-features/server/src/modes/htmlMode.ts index 00a690f56eb..09efb996f6e 100644 --- a/extensions/html-language-features/server/src/modes/htmlMode.ts +++ b/extensions/html-language-features/server/src/modes/htmlMode.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { getLanguageModelCache } from '../languageModelCache'; -import { LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions, HTMLFormatConfiguration } from 'vscode-html-languageservice'; +import { LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions, HTMLFormatConfiguration, SelectionRange } from 'vscode-html-languageservice'; import { TextDocument, Position, Range, CompletionItem, FoldingRange } from 'vscode-languageserver-types'; import { LanguageMode, Workspace } from './languageModes'; import { getPathCompletionParticipant } from './pathCompletion'; @@ -15,8 +15,8 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace: getId() { return 'html'; }, - doSelection(document: TextDocument, position: Position): Range[] { - return htmlLanguageService.getSelectionRanges(document, position); + getSelectionRanges(document: TextDocument, positions: Position[]): SelectionRange[][] { + return htmlLanguageService.getSelectionRanges(document, positions); }, doComplete(document: TextDocument, position: Position, settings = workspace.settings) { let options = settings && settings.html && settings.html.suggest; diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index 048076ed70d..94c0b04a293 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getLanguageService as getHTMLLanguageService, DocumentContext, IHTMLDataProvider } from 'vscode-html-languageservice'; +import { getLanguageService as getHTMLLanguageService, DocumentContext, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; import { CompletionItem, Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range, Hover, DocumentHighlight, CompletionList, Position, FormattingOptions, SymbolInformation, FoldingRange @@ -31,7 +31,7 @@ export interface Workspace { export interface LanguageMode { getId(): string; - doSelection?: (document: TextDocument, position: Position) => Range[]; + getSelectionRanges?: (document: TextDocument, positions: Position[]) => SelectionRange[][]; doValidation?: (document: TextDocument, settings?: Settings) => Diagnostic[]; doComplete?: (document: TextDocument, position: Position, settings?: Settings) => CompletionList; doResolve?: (document: TextDocument, item: CompletionItem) => CompletionItem; diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 5173fd2b003..79eeb0196cb 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -229,20 +229,20 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^3.0.13-next.10: - version "3.0.13-next.10" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.13-next.10.tgz#f5822e832b06e1e91ec96c528bab83bb07251c35" - integrity sha512-zKwzo3GVhrAllYDM4afL8q1XCHixsI8tP3SyLrWGzp0Nc9P+bbjKQeC26VcaOb0dtkgfpB/vfBPf+4yOs4s/pw== +vscode-css-languageservice@^4.0.0-next.3: + version "4.0.0-next.3" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.0-next.3.tgz#e9529f3b4ddf95c9a3e5dc2a6d701a38280ffa98" + integrity sha512-/xmbWpIQLw+HZ/3LsaE2drHFSNJbM9mZ8bKR5NUiu2ZUr10WbGxX0j/GDZB3LlMmdSHQGgRQ5hTM/Ic2PuBDRw== dependencies: - vscode-languageserver-types "^3.13.0" + vscode-languageserver-types "^3.14.0" vscode-nls "^4.0.0" -vscode-html-languageservice@^2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-2.1.11.tgz#56fc25cf64793a9eaef2f571a0ecd591eaed26c1" - integrity sha512-wfENgWb7JjEhwsRHXhairumuxAGnFcMUwIut5P7SxGwNrJMDXkgfs6OUBZycQpbaXTkMEvwsKNKFqUQppW7P4g== +vscode-html-languageservice@^3.0.0-next.3: + version "3.0.0-next.3" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.0-next.3.tgz#a0230c57375deb21fadbfa0210a770ca6e06d425" + integrity sha512-vPdZ17JSr8kAAnjNjdiH4jYySaJrXqnbT3OhnGXqc51R3jnwMXV/Jf72ctXptbpiUQM3ifHnfUcxwO+34tw6Lw== dependencies: - vscode-languageserver-types "^3.13.0" + vscode-languageserver-types "^3.14.0" vscode-nls "^4.0.0" vscode-uri "^1.0.6" @@ -251,25 +251,25 @@ vscode-jsonrpc@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== +vscode-languageserver-protocol@3.15.0-next.1: + version "3.15.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.1.tgz#1e45e224d7eef8c79b4bed75b9dcb1930d2ab8ed" + integrity sha512-LXF0d9s3vxFBxVQ4aKl/XghdEMAncGt3dh4urIYa9Is43g3MfIQL9fC44YZtP+XXOrI2rpZU8lRNN01U1V6CDg== dependencies: vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-languageserver-types "3.14.0" -vscode-languageserver-types@3.13.0, vscode-languageserver-types@^3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-languageserver-types@3.14.0, vscode-languageserver-types@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== -vscode-languageserver@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.1.0.tgz#012a28f154cc7a848c443d217894942e4c3eeb39" - integrity sha512-CIsrgx2Y5VHS317g/HwkSTWYBIQmy0DwEyZPmB2pEpVOhYFwVsYpbiJwHIIyLQsQtmRaO4eA2xM8KPjNSdXpBw== +vscode-languageserver@^5.3.0-next.2: + version "5.3.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.2.tgz#31ce4c34d68b517b400ca9e211e43f8d868b8dcc" + integrity sha512-n5onRw9naMrRHp2jnOn+ZwN1n+tTfzftWLPonjp1FWf/iCZWIlnw2TyF/Hn+SDGhLoVtoghmxhwEQaxEAfLHvw== dependencies: - vscode-languageserver-protocol "3.13.0" + vscode-languageserver-protocol "3.15.0-next.1" vscode-uri "^1.0.6" vscode-nls@^4.0.0: diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index 2737f409efa..a0667775d59 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -45,26 +45,26 @@ vscode-jsonrpc@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== -vscode-languageclient@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.1.0.tgz#650ab0dc9fd0daaade058a8471aaff5bc3f9580e" - integrity sha512-Z95Kps8UqD4o17HE3uCkZuvenOsxHVH46dKmaGVpGixEFZigPaVuVxLM/JWeIY9aRenoC0ZD9CK1O7L4jpffKg== +vscode-languageclient@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz#7cfc83a294c409f58cfa2b910a8cfeaad0397193" + integrity sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q== dependencies: semver "^5.5.0" - vscode-languageserver-protocol "3.13.0" + vscode-languageserver-protocol "3.14.1" -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== +vscode-languageserver-protocol@3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz#b8aab6afae2849c84a8983d39a1cf742417afe2f" + integrity sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g== dependencies: vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-languageserver-types "3.14.0" -vscode-languageserver-types@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-languageserver-types@3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== vscode-nls@^4.0.0: version "4.0.0" From ce3f0c17d7cce900a9c6ab9053f981809e1dcd95 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 5 Mar 2019 15:27:46 +0100 Subject: [PATCH 86/88] [json] update service (webpack) --- .../json-language-features/package.json | 4 +- .../server/build/filesFillIn.js | 5 -- .../server/extension.webpack.config.js | 4 -- .../server/package.json | 6 +-- .../json-language-features/server/yarn.lock | 48 +++++++++---------- extensions/json-language-features/yarn.lock | 28 +++++------ 6 files changed, 43 insertions(+), 52 deletions(-) delete mode 100644 extensions/json-language-features/server/build/filesFillIn.js diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 47d1f7bf32d..4cd6d425a76 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -102,10 +102,10 @@ }, "dependencies": { "vscode-extension-telemetry": "0.1.1", - "vscode-languageclient": "^5.1.0", + "vscode-languageclient": "^5.2.1", "vscode-nls": "^4.0.0" }, "devDependencies": { "@types/node": "^10.12.21" } -} \ No newline at end of file +} diff --git a/extensions/json-language-features/server/build/filesFillIn.js b/extensions/json-language-features/server/build/filesFillIn.js deleted file mode 100644 index 906617384e0..00000000000 --- a/extensions/json-language-features/server/build/filesFillIn.js +++ /dev/null @@ -1,5 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -module.exports = {}; \ No newline at end of file diff --git a/extensions/json-language-features/server/extension.webpack.config.js b/extensions/json-language-features/server/extension.webpack.config.js index b31abe55f25..9c605f6b5ae 100644 --- a/extensions/json-language-features/server/extension.webpack.config.js +++ b/extensions/json-language-features/server/extension.webpack.config.js @@ -21,10 +21,6 @@ module.exports = withDefaults({ path: path.join(__dirname, 'dist') }, plugins: [ - new webpack.NormalModuleReplacementPlugin( - /[/\\]vscode-languageserver[/\\]lib[/\\]files\.js/, - require.resolve('./build/filesFillIn') - ), new webpack.IgnorePlugin(/vertx/) ], }); diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 959af9a9794..fc2323a773e 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -12,10 +12,10 @@ }, "main": "./out/jsonServerMain", "dependencies": { - "jsonc-parser": "^2.0.2", + "jsonc-parser": "^2.0.3", "request-light": "^0.2.4", - "vscode-json-languageservice": "^3.3.0-next.4", - "vscode-languageserver": "^5.1.0", + "vscode-json-languageservice": "^3.3.0-next.6", + "vscode-languageserver": "^5.3.0-next.2", "vscode-nls": "^4.0.0", "vscode-uri": "^1.0.6" }, diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 7a974ff4a2b..bb8489b6d86 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -54,10 +54,10 @@ https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" -jsonc-parser@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.2.tgz#42fcf56d70852a043fadafde51ddb4a85649978d" - integrity sha512-TSU435K5tEKh3g7bam1AFf+uZrISheoDsLlpmAo6wWZYqjsnd09lHYK1Qo+moK4Ikifev1Gdpa69g4NELKnCrQ== +jsonc-parser@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.3.tgz#6d4199ccab7f21ff5d2a4225050c54e981fb21a2" + integrity sha512-WJi9y9ABL01C8CxTKxRRQkkSpY/x2bo4Gy0WuiZGrInxQqgxQpvkBCLNcDYcHOSdhx4ODgbFcgAvfL49C+PHgQ== ms@2.0.0: version "2.0.0" @@ -73,13 +73,13 @@ request-light@^0.2.4: https-proxy-agent "^2.2.1" vscode-nls "^4.0.0" -vscode-json-languageservice@^3.3.0-next.4: - version "3.3.0-next.4" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.0-next.4.tgz#e13b2fd5665b754ee94608a506407cd12b63d64d" - integrity sha512-tD8w2SvwERj3392q34xXKA/i76WWK7YwmP9eoLdKvdfMRwXB7a0MYWPoYZD4HycwvavAlbJ2x18vP4G7+BFA+A== +vscode-json-languageservice@^3.3.0-next.6: + version "3.3.0-next.6" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.0-next.6.tgz#711f121b44ba443a89f3fb01a01c611f2547079f" + integrity sha512-i1tyLiodWc7y6lR9C4cat+OUSptj8Duk1Ybm1FaMzhNfOTFttSiwrBw1otNb+QwI65VEj7EAEBQHRLeQOWznMw== dependencies: - jsonc-parser "^2.0.2" - vscode-languageserver-types "^3.13.0" + jsonc-parser "^2.0.3" + vscode-languageserver-types "^3.14.0" vscode-nls "^4.0.0" vscode-uri "^1.0.6" @@ -88,25 +88,25 @@ vscode-jsonrpc@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== +vscode-languageserver-protocol@3.15.0-next.1: + version "3.15.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.1.tgz#1e45e224d7eef8c79b4bed75b9dcb1930d2ab8ed" + integrity sha512-LXF0d9s3vxFBxVQ4aKl/XghdEMAncGt3dh4urIYa9Is43g3MfIQL9fC44YZtP+XXOrI2rpZU8lRNN01U1V6CDg== dependencies: vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-languageserver-types "3.14.0" -vscode-languageserver-types@3.13.0, vscode-languageserver-types@^3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-languageserver-types@3.14.0, vscode-languageserver-types@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== -vscode-languageserver@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.1.0.tgz#012a28f154cc7a848c443d217894942e4c3eeb39" - integrity sha512-CIsrgx2Y5VHS317g/HwkSTWYBIQmy0DwEyZPmB2pEpVOhYFwVsYpbiJwHIIyLQsQtmRaO4eA2xM8KPjNSdXpBw== +vscode-languageserver@^5.3.0-next.2: + version "5.3.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.2.tgz#31ce4c34d68b517b400ca9e211e43f8d868b8dcc" + integrity sha512-n5onRw9naMrRHp2jnOn+ZwN1n+tTfzftWLPonjp1FWf/iCZWIlnw2TyF/Hn+SDGhLoVtoghmxhwEQaxEAfLHvw== dependencies: - vscode-languageserver-protocol "3.13.0" + vscode-languageserver-protocol "3.15.0-next.1" vscode-uri "^1.0.6" vscode-nls@^4.0.0: diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index e49fc01bd24..9315ad7e193 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -50,26 +50,26 @@ vscode-jsonrpc@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== -vscode-languageclient@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.1.0.tgz#650ab0dc9fd0daaade058a8471aaff5bc3f9580e" - integrity sha512-Z95Kps8UqD4o17HE3uCkZuvenOsxHVH46dKmaGVpGixEFZigPaVuVxLM/JWeIY9aRenoC0ZD9CK1O7L4jpffKg== +vscode-languageclient@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz#7cfc83a294c409f58cfa2b910a8cfeaad0397193" + integrity sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q== dependencies: semver "^5.5.0" - vscode-languageserver-protocol "3.13.0" + vscode-languageserver-protocol "3.14.1" -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== +vscode-languageserver-protocol@3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz#b8aab6afae2849c84a8983d39a1cf742417afe2f" + integrity sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g== dependencies: vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-languageserver-types "3.14.0" -vscode-languageserver-types@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-languageserver-types@3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== vscode-nls@^4.0.0: version "4.0.0" From f0983abe97e10cacd98f27dc4c8f219eb857e8ce Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 5 Mar 2019 15:39:36 +0100 Subject: [PATCH 87/88] Fix #69681 --- src/tsconfig.strictNullChecks.json | 1 + src/vs/workbench/common/editor.ts | 4 +- .../electron-browser/preferencesSearch.ts | 39 +----- .../preferences/browser/preferencesService.ts | 117 ++++++++++-------- .../preferences/common/preferences.ts | 16 +-- .../common/preferencesEditorInput.ts | 2 +- .../preferences/common/preferencesModels.ts | 75 +++++------ .../test/common/preferencesModel.test.ts | 10 +- 8 files changed, 130 insertions(+), 134 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 7bed7f931fe..9bdb62faf4d 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -28,6 +28,7 @@ "./vs/workbench/services/themes/**/*.ts", "./vs/workbench/services/bulkEdit/**/*.ts", "./vs/workbench/services/progress/**/*.ts", + "./vs/workbench/services/preferences/**/*.ts", "./vs/workbench/services/timer/**/*.ts" ], "files": [ diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 6a016bc91cc..eb745aa83fc 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -533,7 +533,7 @@ export class SideBySideEditorInput extends EditorInput { static readonly ID: string = 'workbench.editorinputs.sidebysideEditorInput'; - constructor(private name: string, private description: string, private _details: EditorInput, private _master: EditorInput) { + constructor(private name: string, private description: string | null, private _details: EditorInput, private _master: EditorInput) { super(); this.registerListeners(); @@ -602,7 +602,7 @@ export class SideBySideEditorInput extends EditorInput { return this.name; } - getDescription(): string { + getDescription(): string | null { return this.description; } diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts index 4edd06ce8e7..9c34a8343f5 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts @@ -23,6 +23,7 @@ import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfigura import { CancellationToken } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels'; export interface IEndpointDetails { urlBase: string; @@ -426,12 +427,12 @@ function remoteSettingToISetting(remoteSetting: IRemoteSetting): IExtensionSetti return { description: remoteSetting.description.split('\n'), descriptionIsMarkdown: false, - descriptionRanges: null, + descriptionRanges: [], key: remoteSetting.key, - keyRange: null, + keyRange: nullRange, value: remoteSetting.defaultValue, - range: null, - valueRange: null, + range: nullRange, + valueRange: nullRange, overrides: [], extensionName: remoteSetting.extensionName, extensionPublisher: remoteSetting.extensionPublisher @@ -536,16 +537,6 @@ class SettingMatches { } private toKeyRange(setting: ISetting, match: IMatch): IRange { - if (!setting.keyRange) { - // No source range? Return fake range, don't care - return { - startLineNumber: 0, - startColumn: 0, - endLineNumber: 0, - endColumn: 0, - }; - } - return { startLineNumber: setting.keyRange.startLineNumber, startColumn: setting.keyRange.startColumn + match.start, @@ -555,16 +546,6 @@ class SettingMatches { } private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { - if (!setting.keyRange) { - // No source range? Return fake range, don't care - return { - startLineNumber: 0, - startColumn: 0, - endLineNumber: 0, - endColumn: 0, - }; - } - return { startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, @@ -574,16 +555,6 @@ class SettingMatches { } private toValueRange(setting: ISetting, match: IMatch): IRange { - if (!setting.keyRange) { - // No source range? Return fake range, don't care - return { - startLineNumber: 0, - startColumn: 0, - endLineNumber: 0, - endColumn: 0, - }; - } - return { startLineNumber: setting.valueRange.startLineNumber, startColumn: setting.valueRange.startColumn + match.start + 1, diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index e5cd0c64ab7..744146bb756 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -89,10 +89,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic private readonly defaultSettingsRawResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/defaultSettings.json' }); get userSettingsResource(): URI { - return this.getEditableSettingsURI(ConfigurationTarget.USER); + return this.getEditableSettingsURI(ConfigurationTarget.USER)!; } - get workspaceSettingsResource(): URI { + get workspaceSettingsResource(): URI | null { return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); } @@ -100,11 +100,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.instantiationService.createInstance(SettingsEditor2Input); } - getFolderSettingsResource(resource: URI): URI { + getFolderSettingsResource(resource: URI): URI | null { return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); } - resolveModel(uri: URI): Promise { + resolveModel(uri: URI): Promise { if (this.isDefaultSettingsResource(uri)) { const target = this.getConfigurationTargetFromDefaultSettingsResource(uri); @@ -156,7 +156,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.createDefaultSettingsEditorModel(uri); } - if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) { + if (this.userSettingsResource.toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri); } @@ -169,7 +169,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); } - return Promise.resolve>(null); + return Promise.reject(`unknown resource: ${uri.toString()}`); } openRawDefaultSettings(): Promise { @@ -190,7 +190,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } const editorInput = this.getActiveSettingsEditorInput() || this.lastOpenedSettingsInput; - const resource = editorInput ? editorInput.master.getResource() : this.userSettingsResource; + const resource = editorInput ? editorInput.master.getResource()! : this.userSettingsResource; const target = this.getConfigurationTargetFromSettingsResource(resource); return this.openOrSwitchSettings(target, resource); } @@ -198,7 +198,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic private openSettings2(): Promise { const input = this.settingsEditor2Input; return this.editorGroupService.activeGroup.openEditor(input) - .then(() => this.editorGroupService.activeGroup.activeControl); + .then(() => this.editorGroupService.activeGroup.activeControl!); } openGlobalSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { @@ -211,14 +211,14 @@ export class PreferencesService extends Disposable implements IPreferencesServic this.openOrSwitchSettings2(ConfigurationTarget.USER, undefined, options, group); } - openWorkspaceSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { + openWorkspaceSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { jsonEditor = typeof jsonEditor === 'undefined' ? this.configurationService.getValue('workbench.settings.editor') === 'json' : jsonEditor; - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + if (!this.workspaceSettingsResource) { this.notificationService.info(nls.localize('openFolderFirst', "Open a folder first to create workspace settings")); - return Promise.resolve(null); + return Promise.reject(null); } return jsonEditor ? @@ -230,22 +230,26 @@ export class PreferencesService extends Disposable implements IPreferencesServic jsonEditor = typeof jsonEditor === 'undefined' ? this.configurationService.getValue('workbench.settings.editor') === 'json' : jsonEditor; - - return jsonEditor ? - this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder), options, group) : - this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE_FOLDER, folder, options, group); + const folderSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); + if (jsonEditor) { + if (folderSettingsUri) { + return this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, folderSettingsUri, options, group); + } + return Promise.reject(`Invalid folder URI - ${folder.toString()}`); + } + return this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE_FOLDER, folder, options, group); } switchSettings(target: ConfigurationTarget, resource: URI, jsonEditor?: boolean): Promise { if (!jsonEditor) { - return this.doOpenSettings2(target, resource).then(() => null); + return this.doOpenSettings2(target, resource).then(() => undefined); } const activeControl = this.editorService.activeControl; if (activeControl && activeControl.input instanceof PreferencesEditorInput) { - return this.doSwitchSettings(target, resource, activeControl.input, activeControl.group).then(() => null); + return this.doSwitchSettings(target, resource, activeControl.input, activeControl.group).then(() => undefined); } else { - return this.doOpenSettings(target, resource).then(() => null); + return this.doOpenSettings(target, resource).then(() => undefined); } } @@ -276,7 +280,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - return this.editorService.openEditor(this.instantiationService.createInstance(KeybindingsEditorInput), { pinned: true, revealIfOpened: true }).then(() => null); + return this.editorService.openEditor(this.instantiationService.createInstance(KeybindingsEditorInput), { pinned: true, revealIfOpened: true }).then(() => undefined); } openDefaultKeybindingsFile(): Promise { @@ -291,7 +295,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic if (codeEditor) { this.addLanguageOverrideEntry(language, settingsModel, codeEditor) .then(position => { - if (codeEditor) { + if (codeEditor && position) { codeEditor.setPosition(position); codeEditor.revealLine(position.lineNumber); codeEditor.focus(); @@ -303,8 +307,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic private openOrSwitchSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: ISettingsEditorOptions, group: IEditorGroup = this.editorGroupService.activeGroup): Promise { const editorInput = this.getActiveSettingsEditorInput(group); - if (editorInput && editorInput.master.getResource().fsPath !== resource.fsPath) { - return this.doSwitchSettings(configurationTarget, resource, editorInput, group, options); + if (editorInput) { + const editorInputResource = editorInput.master.getResource(); + if (editorInputResource && editorInputResource.fsPath !== resource.fsPath) { + return this.doSwitchSettings(configurationTarget, resource, editorInput, group, options); + } } return this.doOpenSettings(configurationTarget, resource, options, group); } @@ -335,7 +342,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return Promise.all([ this.editorService.openEditor({ resource: this.defaultSettingsRawResource, options: { pinned: true, preserveFocus: true, revealIfOpened: true }, label: nls.localize('defaultSettings', "Default Settings"), description: '' }), this.editorService.openEditor(editableSettingsEditorInput, { pinned: true, revealIfOpened: true }, sideEditorGroup.id) - ]).then(() => null); + ]).then(([defaultEditor, editor]) => editor); } else { return this.editorService.openEditor(editableSettingsEditorInput, SettingsEditorOptions.create(options), group); } @@ -374,7 +381,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic } private doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { - return this.getOrCreateEditableSettingsEditorInput(target, this.getEditableSettingsURI(target, resource)) + const settingsURI = this.getEditableSettingsURI(target, resource); + if (!settingsURI) { + return Promise.reject(`Invalid settings URI - ${resource.toString()}`); + } + return this.getOrCreateEditableSettingsEditorInput(target, settingsURI) .then(toInput => { return group.openEditor(input).then(() => { const replaceWith = new PreferencesEditorInput(this.getPreferencesEditorInputName(target, resource), toInput.getDescription(), this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(target)), toInput); @@ -382,10 +393,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic return group.replaceEditors([{ editor: input, replacement: replaceWith, - options: SettingsEditorOptions.create(options) + options: options ? SettingsEditorOptions.create(options) : undefined }]).then(() => { this.lastOpenedSettingsInput = replaceWith; - return group.activeControl; + return group.activeControl!; }); }); }); @@ -464,7 +475,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.textModelResolverService.createModelReference(settingsUri) .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); } - return Promise.resolve(null); + return Promise.reject(`unknown target: ${configurationTarget} and resource: ${resource.toString()}`); } private createDefaultSettingsEditorModel(defaultSettingsUri: URI): Promise { @@ -494,7 +505,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this._defaultUserSettingsContentModel; } - private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI { + private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI | null { switch (configurationTarget) { case ConfigurationTarget.USER: return URI.file(this.environmentService.appSettingsPath); @@ -505,8 +516,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic const workspace = this.contextService.getWorkspace(); return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); case ConfigurationTarget.WORKSPACE_FOLDER: - const folder = this.contextService.getWorkspaceFolder(resource); - return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; + if (resource) { + const folder = this.contextService.getWorkspaceFolder(resource); + return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; + } } return null; } @@ -523,7 +536,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic if (Object.keys(parse(content.value)).indexOf('settings') === -1) { return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(undefined, () => { }); } - return null; + return undefined; }); } return this.createIfNotExists(resource, emptyEditableSettingsContent).then(() => { }); @@ -557,29 +570,35 @@ export class PreferencesService extends Disposable implements IPreferencesServic ]; } - private addLanguageOverrideEntry(language: string, settingsModel: IPreferencesEditorModel, codeEditor: ICodeEditor): Promise { + private addLanguageOverrideEntry(language: string, settingsModel: IPreferencesEditorModel, codeEditor: ICodeEditor): Promise { const languageKey = `[${language}]`; let setting = settingsModel.getPreference(languageKey); const model = codeEditor.getModel(); - const configuration = this.configurationService.getValue<{ editor: { tabSize: number; insertSpaces: boolean } }>(); - const eol = model.getEOL(); - if (setting) { - if (setting.overrides.length) { - const lastSetting = setting.overrides[setting.overrides.length - 1]; - return Promise.resolve({ lineNumber: lastSetting.valueRange.endLineNumber, column: model.getLineMaxColumn(lastSetting.valueRange.endLineNumber) }); + if (model) { + const configuration = this.configurationService.getValue<{ editor: { tabSize: number; insertSpaces: boolean } }>(); + const eol = model.getEOL(); + if (setting) { + if (setting.overrides && setting.overrides.length) { + const lastSetting = setting.overrides[setting.overrides.length - 1]; + return Promise.resolve({ lineNumber: lastSetting.valueRange.endLineNumber, column: model.getLineMaxColumn(lastSetting.valueRange.endLineNumber) }); + } + return Promise.resolve({ lineNumber: setting.valueRange.startLineNumber, column: setting.valueRange.startColumn + 1 }); } - return Promise.resolve({ lineNumber: setting.valueRange.startLineNumber, column: setting.valueRange.startColumn + 1 }); + return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER) + .then(() => { + setting = settingsModel.getPreference(languageKey); + if (setting) { + let content = eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor); + let editOperation = EditOperation.insert(new Position(setting.valueRange.endLineNumber, setting.valueRange.endColumn - 1), content); + model.pushEditOperations([], [editOperation], () => []); + let lineNumber = setting.valueRange.endLineNumber + 1; + settingsModel.dispose(); + return { lineNumber, column: model.getLineMaxColumn(lineNumber) }; + } + return null; + }); } - return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER) - .then(() => { - setting = settingsModel.getPreference(languageKey); - let content = eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor); - let editOperation = EditOperation.insert(new Position(setting.valueRange.endLineNumber, setting.valueRange.endColumn - 1), content); - model.pushEditOperations([], [editOperation], () => []); - let lineNumber = setting.valueRange.endLineNumber + 1; - settingsModel.dispose(); - return { lineNumber, column: model.getLineMaxColumn(lineNumber) }; - }); + return Promise.resolve(null); } private spaces(count: number, { tabSize, insertSpaces }: { tabSize: number; insertSpaces: boolean }): string { diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index 4bf2e5500f5..b1d1d0a4a99 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -53,7 +53,7 @@ export interface ISetting { value: any; valueRange: IRange; description: string[]; - descriptionIsMarkdown: boolean; + descriptionIsMarkdown?: boolean; descriptionRanges: IRange[]; overrides?: ISetting[]; overrideOf?: ISetting; @@ -65,7 +65,7 @@ export interface ISetting { enumDescriptions?: string[]; enumDescriptionsAreMarkdown?: boolean; tags?: string[]; - validator?: (value: any) => string; + validator?: (value: any) => string | null; } export interface IExtensionSetting extends ISetting { @@ -162,11 +162,7 @@ export class SettingsEditorOptions extends EditorOptions implements ISettingsEdi folderUri?: URI; query?: string; - static create(settings: ISettingsEditorOptions): SettingsEditorOptions | null { - if (!settings) { - return null; - } - + static create(settings: ISettingsEditorOptions): SettingsEditorOptions { const options = new SettingsEditorOptions(); options.target = settings.target; @@ -195,10 +191,10 @@ export interface IPreferencesService { _serviceBrand: any; userSettingsResource: URI; - workspaceSettingsResource: URI; - getFolderSettingsResource(resource: URI): URI; + workspaceSettingsResource: URI | null; + getFolderSettingsResource(resource: URI): URI | null; - resolveModel(uri: URI): Promise; + resolveModel(uri: URI): Promise; createPreferencesEditorModel(uri: URI): Promise>; createSettings2EditorModel(): Settings2EditorModel; // TODO diff --git a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts index 4929b15f8f9..e1db37ca23b 100644 --- a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts +++ b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts @@ -22,7 +22,7 @@ export class PreferencesEditorInput extends SideBySideEditorInput { return PreferencesEditorInput.ID; } - getTitle(verbosity: Verbosity): string { + getTitle(verbosity: Verbosity): string | null { return this.master.getTitle(verbosity); } } diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index f61324585e4..1c7936e9096 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -23,6 +23,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { EditorModel } from 'vs/workbench/common/editor'; import { IFilterMetadata, IFilterResult, IGroupFilter, IKeybindingsEditorModel, ISearchResultGroup, ISetting, ISettingMatch, ISettingMatcher, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; +export const nullRange: IRange = { startLineNumber: -1, startColumn: -1, endLineNumber: -1, endColumn: -1 }; +export function isNullRange(range: IRange): boolean { return range.startLineNumber === -1 && range.startColumn === -1 && range.endLineNumber === -1 && range.endColumn === -1; } + export abstract class AbstractSettingsModel extends EditorModel { protected _currentResultGroups = new Map(); @@ -124,7 +127,7 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti constructor(reference: IReference, private _configurationTarget: ConfigurationTarget) { super(); - this.settingsModel = reference.object.textEditorModel; + this.settingsModel = reference.object.textEditorModel!; this._register(this.onDispose(() => reference.dispose())); this._register(this.settingsModel.onDidChangeContent(() => { this._settingsGroups = null; @@ -268,7 +271,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, } if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { // settings value started - const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting!.overrides![overrideSetting!.overrides!.length - 1]; if (setting) { const valueStartPosition = model.getPositionAt(offset); const valueEndPosition = model.getPositionAt(offset + length); @@ -288,7 +291,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, } const visitor: JSONVisitor = { onObjectBegin: (offset: number, length: number) => { - if (isSettingsProperty(currentProperty, previousParents)) { + if (isSettingsProperty(currentProperty!, previousParents)) { // Settings started settingsPropertyIndex = previousParents.length; const position = model.getPositionAt(offset); @@ -323,10 +326,10 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, endColumn: 0 }, value: null, - valueRange: null, - descriptionRanges: null, + valueRange: nullRange, + descriptionRanges: [], overrides: [], - overrideOf: overrideSetting + overrideOf: overrideSetting || undefined }; if (previousParents.length === settingsPropertyIndex + 1) { settings.push(setting); @@ -334,7 +337,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, overrideSetting = setting; } } else { - overrideSetting.overrides.push(setting); + overrideSetting!.overrides!.push(setting); } } }, @@ -342,7 +345,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, currentParent = previousParents.pop(); if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { // setting ended - const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting!.overrides![overrideSetting!.overrides!.length - 1]; if (setting) { const valueEndPosition = model.getPositionAt(offset + length); setting.valueRange = assign(setting.valueRange, { @@ -377,7 +380,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, currentParent = previousParents.pop(); if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { // setting value ended - const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting!.overrides![overrideSetting!.overrides!.length - 1]; if (setting) { const valueEndPosition = model.getPositionAt(offset + length); setting.valueRange = assign(setting.valueRange, { @@ -394,7 +397,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, onLiteralValue: onValue, onError: (error) => { const setting = settings[settings.length - 1]; - if (setting && (!setting.range || !setting.keyRange || !setting.valueRange)) { + if (setting && (isNullRange(setting.range) || isNullRange(setting.keyRange) || isNullRange(setting.valueRange))) { settings.pop(); } } @@ -408,8 +411,8 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, settings } ], - title: null, - titleRange: null, + title: '', + titleRange: nullRange, range }] : []; } @@ -514,13 +517,15 @@ export class DefaultSettings extends Disposable { description: setting.description, key: setting.key, value: setting.value, - range: null, - valueRange: null, + keyRange: nullRange, + range: nullRange, + valueRange: nullRange, overrides: [], scope: ConfigurationScope.RESOURCE, type: setting.type, enum: setting.enum, - enumDescriptions: setting.enumDescriptions + enumDescriptions: setting.enumDescriptions, + descriptionRanges: [] }; } return null; @@ -528,9 +533,9 @@ export class DefaultSettings extends Disposable { return { id: 'mostCommonlyUsed', - range: null, + range: nullRange, title: nls.localize('commonlyUsed', "Commonly Used"), - titleRange: null, + titleRange: nullRange, sections: [ { settings @@ -552,7 +557,7 @@ export class DefaultSettings extends Disposable { if (!settingsGroup) { settingsGroup = find(result, g => g.title === title); if (!settingsGroup) { - settingsGroup = { sections: [{ settings: [] }], id: config.id, title: title, titleRange: null, range: null, contributedByExtension: !!config.contributedByExtension }; + settingsGroup = { sections: [{ settings: [] }], id: config.id || '', title: title || '', titleRange: nullRange, range: nullRange, contributedByExtension: !!config.contributedByExtension }; result.push(settingsGroup); } } else { @@ -561,7 +566,7 @@ export class DefaultSettings extends Disposable { } if (config.properties) { if (!settingsGroup) { - settingsGroup = { sections: [{ settings: [] }], id: config.id, title: config.id, titleRange: null, range: null, contributedByExtension: !!config.contributedByExtension }; + settingsGroup = { sections: [{ settings: [] }], id: config.id || '', title: config.id || '', titleRange: nullRange, range: nullRange, contributedByExtension: !!config.contributedByExtension }; result.push(settingsGroup); } const configurationSettings: ISetting[] = []; @@ -605,9 +610,9 @@ export class DefaultSettings extends Disposable { value, description, descriptionIsMarkdown: !prop.description, - range: null, - keyRange: null, - valueRange: null, + range: nullRange, + keyRange: nullRange, + valueRange: nullRange, descriptionRanges: [], overrides, scope: prop.scope, @@ -630,9 +635,9 @@ export class DefaultSettings extends Disposable { value: overrideSettings[key], description: [], descriptionIsMarkdown: false, - range: null, - keyRange: null, - valueRange: null, + range: nullRange, + keyRange: nullRange, + valueRange: nullRange, descriptionRanges: [], overrides: [] })); @@ -691,7 +696,7 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements super(); this._register(defaultSettings.onDidChange(() => this._onDidChangeGroups.fire())); - this._model = reference.object.textEditorModel; + this._model = reference.object.textEditorModel!; this._register(this.onDispose(() => reference.dispose())); } @@ -712,7 +717,7 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return this.settingsGroups.slice(1); } - protected update(): IFilterResult { + protected update(): IFilterResult | null { if (this._model.isDisposed()) { return null; } @@ -825,10 +830,10 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements overrideOf: setting.overrideOf, tags: setting.tags, deprecationMessage: setting.deprecationMessage, - keyRange: undefined, - valueRange: undefined, + keyRange: nullRange, + valueRange: nullRange, descriptionIsMarkdown: undefined, - descriptionRanges: undefined + descriptionRanges: [] }; } @@ -852,9 +857,9 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements private getGroup(resultGroup: ISearchResultGroup): ISettingsGroup { return { id: resultGroup.id, - range: null, + range: nullRange, title: resultGroup.label, - titleRange: null, + titleRange: nullRange, sections: [ { settings: resultGroup.result.filterMatches.map(m => this.copySetting(m.setting)) @@ -899,7 +904,7 @@ class SettingsContentBuilder { this._contentByLines.push('}'); } - protected _pushGroup(group: ISettingsGroup, indent: string): ISetting { + protected _pushGroup(group: ISettingsGroup, indent: string): ISetting | null { let lastSetting: ISetting | null = null; const groupStart = this.lineCountWithOffset + 1; for (const section of group.sections) { @@ -959,7 +964,7 @@ class SettingsContentBuilder { if (setting.enumDescriptions && setting.enumDescriptions.some(desc => !!desc)) { setting.enumDescriptions.forEach((desc, i) => { - const displayEnum = escapeInvisibleChars(String(setting.enum[i])); + const displayEnum = escapeInvisibleChars(String(setting.enum![i])); const line = desc ? `${displayEnum}: ${fixSettingLink(desc)}` : displayEnum; @@ -974,7 +979,7 @@ class SettingsContentBuilder { private pushValue(setting: ISetting, preValueConent: string, indent: string): void { const valueString = JSON.stringify(setting.value, null, indent); if (valueString && (typeof setting.value === 'object')) { - if (setting.overrides.length) { + if (setting.overrides && setting.overrides.length) { this._contentByLines.push(preValueConent + ' {'); for (const subSetting of setting.overrides) { this.pushSetting(subSetting, indent + indent); diff --git a/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts b/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts index d4dae17cbc3..c428209859a 100644 --- a/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts @@ -10,7 +10,7 @@ import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/c suite('Preferences Model test', () => { class Tester { - private validator: (value: any) => string; + private validator: (value: any) => string | null; constructor(private settings: IConfigurationPropertySchema) { this.validator = createValidator(settings)!; @@ -24,8 +24,12 @@ suite('Preferences Model test', () => { assert.notEqual(this.validator(input), '', `Expected ${JSON.stringify(this.settings)} to reject \`${input}\`.`); return { withMessage: - (message) => assert(this.validator(input).indexOf(message) > -1, - `Expected error of ${JSON.stringify(this.settings)} on \`${input}\` to contain ${message}. Got ${this.validator(input)}.`) + (message) => { + const actual = this.validator(input); + assert.ok(actual); + assert(actual!.indexOf(message) > -1, + `Expected error of ${JSON.stringify(this.settings)} on \`${input}\` to contain ${message}. Got ${this.validator(input)}.`); + } }; } From c6315a3d30771ff83bb6cf56528404859f25a9e4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 5 Mar 2019 16:07:41 +0100 Subject: [PATCH 88/88] debt - more services cleanup --- src/vs/platform/lifecycle/common/lifecycle.ts | 2 +- .../workbench/electron-browser/workbench.ts | 88 ++++++++++--------- .../services/backup/node/backupFileService.ts | 67 +++++++++++++- .../backupFileService.test.ts | 22 ++++- src/vs/workbench/workbench.main.ts | 1 + 5 files changed, 134 insertions(+), 46 deletions(-) diff --git a/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts index 4879ee13e8d..18782a0d0b3 100644 --- a/src/vs/platform/lifecycle/common/lifecycle.ts +++ b/src/vs/platform/lifecycle/common/lifecycle.ts @@ -133,7 +133,7 @@ export interface ILifecycleService { /** * A flag indicating in what phase of the lifecycle we currently are. */ - readonly phase: LifecyclePhase; + phase: LifecyclePhase; /** * Fired before shutdown happens. Allows listeners to veto against the diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index b1e469d99db..0625ab7372a 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -105,8 +105,6 @@ import { WorkbenchContextKeysHandler } from 'vs/workbench/browser/contextkeys'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; // import@node -import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; -import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; @@ -190,13 +188,13 @@ export class Workbench extends Disposable implements IPartService { private editorService: EditorService; private editorGroupService: IEditorGroupsService; private contextViewService: ContextViewService; - private backupFileService: IBackupFileService; private windowService: IWindowService; - private lifecycleService: LifecycleService; + private lifecycleService: ILifecycleService; + private instantiationService: IInstantiationService; private contextService: IWorkspaceContextService; private storageService: IStorageService; - private configurationService: WorkspaceService; + private configurationService: IConfigurationService; private environmentService: IEnvironmentService; private logService: ILogService; private windowsService: IWindowsService; @@ -221,7 +219,7 @@ export class Workbench extends Disposable implements IPartService { @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IStorageService storageService: IStorageService, - @IConfigurationService configurationService: WorkspaceService, + @IConfigurationService configurationService: IConfigurationService, @IEnvironmentService environmentService: IEnvironmentService, @ILogService logService: ILogService, @IWindowsService windowsService: IWindowsService @@ -333,7 +331,7 @@ export class Workbench extends Disposable implements IPartService { this.registerLayoutListeners(); // Layout State - this.initLayoutState(); + this.instantiationService.invokeFunction(accessor => this.initLayoutState(accessor)); // Render Workbench this.renderWorkbench(); @@ -525,14 +523,6 @@ export class Workbench extends Disposable implements IPartService { // History serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService)); - // Backup File Service - if (this.configuration.backupPath) { - this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.configuration.backupPath); - } else { - this.backupFileService = new InMemoryBackupFileService(); - } - serviceCollection.set(IBackupFileService, this.backupFileService); - // Quick open service (quick open controller) this.quickOpen = this.instantiationService.createInstance(QuickOpenController); serviceCollection.set(IQuickOpenService, this.quickOpen); @@ -561,12 +551,20 @@ export class Workbench extends Disposable implements IPartService { this.instantiationService.invokeFunction(accessor => { const fileService = accessor.get(IFileService); const instantiationService = accessor.get(IInstantiationService); - const themeService = accessor.get(IWorkbenchThemeService) as WorkbenchThemeService; + const configurationService = accessor.get(IConfigurationService) as any; + const themeService = accessor.get(IWorkbenchThemeService) as any; - this.configurationService.acquireFileService(fileService); - this.configurationService.acquireInstantiationService(instantiationService); + if (typeof configurationService.acquireFileService === 'function') { + configurationService.acquireFileService(fileService); + } - themeService.acquireFileService(fileService); + if (typeof configurationService.acquireInstantiationService === 'function') { + configurationService.acquireInstantiationService(instantiationService); + } + + if (typeof themeService.acquireFileService === 'function') { + themeService.acquireFileService(fileService); + } }); } @@ -785,7 +783,7 @@ export class Workbench extends Disposable implements IPartService { } private whenStarted(accessor: ServicesAccessor, error?: Error): void { - const lifecycleService = accessor.get(ILifecycleService) as LifecycleService; + const lifecycleService = accessor.get(ILifecycleService); this.restored = true; @@ -1020,22 +1018,27 @@ export class Workbench extends Disposable implements IPartService { } } - private initLayoutState(): void { + private initLayoutState(accessor: ServicesAccessor): void { + const configurationService = accessor.get(IConfigurationService); + const storageService = accessor.get(IStorageService); + const lifecycleService = accessor.get(ILifecycleService); + const contextService = accessor.get(IWorkspaceContextService); + const environmentService = accessor.get(IEnvironmentService); // Fullscreen this.state.fullscreen = isFullscreen(); // Menubar visibility - this.state.menuBar.visibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); + this.state.menuBar.visibility = configurationService.getValue(Settings.MENUBAR_VISIBLE); // Activity bar visibility - this.state.activityBar.hidden = !this.configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); + this.state.activityBar.hidden = !configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); // Sidebar visibility - this.state.sideBar.hidden = this.storageService.getBoolean(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY); + this.state.sideBar.hidden = storageService.getBoolean(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, contextService.getWorkbenchState() === WorkbenchState.EMPTY); // Sidebar position - this.state.sideBar.position = (this.configurationService.getValue(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT; + this.state.sideBar.position = (configurationService.getValue(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT; // Sidebar viewlet if (!this.state.sideBar.hidden) { @@ -1043,8 +1046,8 @@ export class Workbench extends Disposable implements IPartService { // Only restore last viewlet if window was reloaded or we are in development mode let viewletToRestore: string; - if (!this.environmentService.isBuilt || this.lifecycleService.startupKind === StartupKind.ReloadedWindow) { - viewletToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId()); + if (!environmentService.isBuilt || lifecycleService.startupKind === StartupKind.ReloadedWindow) { + viewletToRestore = storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId()); } else { viewletToRestore = viewletRegistry.getDefaultViewletId(); } @@ -1057,13 +1060,13 @@ export class Workbench extends Disposable implements IPartService { } // Editor centered layout - this.state.editor.restoreCentered = this.storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false); + this.state.editor.restoreCentered = storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false); // Editors to open - this.state.editor.editorsToOpen = this.resolveEditorsToOpen(); + this.state.editor.editorsToOpen = this.resolveEditorsToOpen(accessor); // Panel visibility - this.state.panel.hidden = this.storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true); + this.state.panel.hidden = storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true); // Panel position this.updatePanelPosition(); @@ -1072,7 +1075,7 @@ export class Workbench extends Disposable implements IPartService { if (!this.state.panel.hidden) { const panelRegistry = Registry.as(PanelExtensions.Panels); - let panelToRestore = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); + let panelToRestore = storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); if (!panelRegistry.hasPanel(panelToRestore)) { panelToRestore = panelRegistry.getDefaultPanelId(); // fallback to default if panel is unknown } @@ -1085,19 +1088,24 @@ export class Workbench extends Disposable implements IPartService { } // Statusbar visibility - this.state.statusBar.hidden = !this.configurationService.getValue(Settings.STATUSBAR_VISIBLE); + this.state.statusBar.hidden = !configurationService.getValue(Settings.STATUSBAR_VISIBLE); // Zen mode enablement - this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); + this.state.zenMode.restore = storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && configurationService.getValue(Settings.ZEN_MODE_RESTORE); } - private resolveEditorsToOpen(): Promise | IResourceEditor[] { + private resolveEditorsToOpen(accessor: ServicesAccessor): Promise | IResourceEditor[] { + const configuration = accessor.get(IWindowService).getConfiguration(); + const configurationService = accessor.get(IConfigurationService); + const contextService = accessor.get(IWorkspaceContextService); + const editorGroupService = accessor.get(IEditorGroupsService); + const backupFileService = accessor.get(IBackupFileService); // Files to open, diff or create if (this.hasInitialFilesToOpen()) { // Files to diff is exclusive - const filesToDiff = this.toInputs(this.configuration.filesToDiff, false); + const filesToDiff = this.toInputs(configuration.filesToDiff, false); if (filesToDiff && filesToDiff.length === 2) { return [{ leftResource: filesToDiff[0].resource, @@ -1107,21 +1115,21 @@ export class Workbench extends Disposable implements IPartService { }]; } - const filesToCreate = this.toInputs(this.configuration.filesToCreate, true); - const filesToOpen = this.toInputs(this.configuration.filesToOpen, false); + const filesToCreate = this.toInputs(configuration.filesToCreate, true); + const filesToOpen = this.toInputs(configuration.filesToOpen, false); // Otherwise: Open/Create files return [...filesToOpen, ...filesToCreate]; } // Empty workbench - else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') { - const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0; + else if (contextService.getWorkbenchState() === WorkbenchState.EMPTY && configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') { + const isEmpty = editorGroupService.count === 1 && editorGroupService.activeGroup.count === 0; if (!isEmpty) { return []; // do not open any empty untitled file if we restored editors from previous session } - return this.backupFileService.hasBackups().then(hasBackups => { + return backupFileService.hasBackups().then(hasBackups => { if (hasBackups) { return []; // do not open any empty untitled file if we have backups to restore } diff --git a/src/vs/workbench/services/backup/node/backupFileService.ts b/src/vs/workbench/services/backup/node/backupFileService.ts index a089102b7f9..5eb3e0402c5 100644 --- a/src/vs/workbench/services/backup/node/backupFileService.ts +++ b/src/vs/workbench/services/backup/node/backupFileService.ts @@ -15,6 +15,8 @@ import { ITextBufferFactory } from 'vs/editor/common/model'; import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; import { keys } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export interface IBackupFilesModel { resolve(backupRoot: string): Promise; @@ -107,6 +109,63 @@ export class BackupFilesModel implements IBackupFilesModel { export class BackupFileService implements IBackupFileService { + _serviceBrand: any; + + private impl: IBackupFileService; + + constructor( + @IWindowService windowService: IWindowService, + @IFileService fileService: IFileService + ) { + const backupWorkspacePath = windowService.getConfiguration().backupPath; + if (backupWorkspacePath) { + this.impl = new BackupFileServiceImpl(backupWorkspacePath, fileService); + } else { + this.impl = new InMemoryBackupFileService(); + } + } + + initialize(backupWorkspacePath: string): void { + if (this.impl instanceof BackupFileServiceImpl) { + this.impl.initialize(backupWorkspacePath); + } + } + + hasBackups(): Promise { + return this.impl.hasBackups(); + } + + loadBackupResource(resource: Uri): Promise { + return this.impl.loadBackupResource(resource); + } + + backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { + return this.impl.backupResource(resource, content, versionId); + } + + discardResourceBackup(resource: Uri): Promise { + return this.impl.discardResourceBackup(resource); + } + + discardAllWorkspaceBackups(): Promise { + return this.impl.discardAllWorkspaceBackups(); + } + + getWorkspaceFileBackups(): Promise { + return this.impl.getWorkspaceFileBackups(); + } + + resolveBackupContent(backup: Uri): Promise { + return this.impl.resolveBackupContent(backup); + } + + toBackupResource(resource: Uri): Uri { + return this.impl.toBackupResource(resource); + } +} + +class BackupFileServiceImpl implements IBackupFileService { + private static readonly META_MARKER = '\n'; _serviceBrand: any; @@ -170,7 +229,7 @@ export class BackupFileService implements IBackupFileService { } return this.ioOperationQueues.queueFor(backupResource).queue(() => { - const preamble = `${resource.toString()}${BackupFileService.META_MARKER}`; + const preamble = `${resource.toString()}${BackupFileServiceImpl.META_MARKER}`; // Update content with value return this.fileService.updateContent(backupResource, new BackupSnapshot(content, preamble), BACKUP_FILE_UPDATE_OPTIONS).then(() => model.add(backupResource, versionId)); @@ -202,7 +261,7 @@ export class BackupFileService implements IBackupFileService { model.get().forEach(fileBackup => { readPromises.push( - readToMatchingString(fileBackup.fsPath, BackupFileService.META_MARKER, 2000, 10000).then(Uri.parse) + readToMatchingString(fileBackup.fsPath, BackupFileServiceImpl.META_MARKER, 2000, 10000).then(Uri.parse) ); }); @@ -217,7 +276,7 @@ export class BackupFileService implements IBackupFileService { let metaFound = false; const metaPreambleFilter = (chunk: string) => { if (!metaFound && chunk) { - const metaIndex = chunk.indexOf(BackupFileService.META_MARKER); + const metaIndex = chunk.indexOf(BackupFileServiceImpl.META_MARKER); if (metaIndex === -1) { return ''; // meta not yet found, return empty string } @@ -302,3 +361,5 @@ export function hashPath(resource: Uri): string { const str = resource.scheme === Schemas.file ? resource.fsPath : resource.toString(); return crypto.createHash('md5').update(str).digest('hex'); } + +registerSingleton(IBackupFileService, BackupFileService); \ No newline at end of file diff --git a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts index 5f1ea987873..d2d9a82d2c2 100644 --- a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts @@ -13,7 +13,7 @@ import { URI as Uri } from 'vs/base/common/uri'; import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel'; -import { TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestEnvironmentService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestEnvironmentService, TestStorageService, TestWindowService } from 'vs/workbench/test/workbenchTestServices'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; @@ -21,6 +21,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { DefaultEndOfLine } from 'vs/editor/common/model'; import { snapshotToString } from 'vs/platform/files/common/files'; import { Schemas } from 'vs/base/common/network'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); const backupHome = path.join(parentDir, 'Backups'); @@ -35,11 +36,28 @@ const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile)); const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile)); const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile)); +class TestBackupWindowService extends TestWindowService { + + private config: IWindowConfiguration; + + constructor(workspaceBackupPath: string) { + super(); + + this.config = Object.create(null); + this.config.backupPath = workspaceBackupPath; + } + + getConfiguration(): IWindowConfiguration { + return this.config; + } +} + class TestBackupFileService extends BackupFileService { constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) { const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))), TestEnvironmentService, new TestTextResourceConfigurationService(), new TestConfigurationService(), new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true }); + const windowService = new TestBackupWindowService(workspaceBackupPath); - super(workspaceBackupPath, fileService); + super(windowService, fileService); } public toBackupResource(resource: Uri): Uri { diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index ceffd2a8727..e06ec70c0b0 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -73,6 +73,7 @@ import 'vs/workbench/services/configuration/node/jsonEditingService'; import 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import 'vs/workbench/services/textfile/common/textFileService'; import 'vs/workbench/services/dialogs/electron-browser/dialogService'; +import 'vs/workbench/services/backup/node/backupFileService'; registerSingleton(IMenuService, MenuService, true); registerSingleton(IListService, ListService, true);