From 723042560f7ba7853b5cff772009f5b798f88c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Sch=C3=A4rlund?= Date: Thu, 27 Sep 2018 19:16:53 +0200 Subject: [PATCH 01/76] Support odd indentation sizes (fixes #17639) Adds support for 3, 5 and 7 space indentation. Given equal support, still prefers even numbered indentation. --- .../editor/common/model/indentationGuesser.ts | 4 ++-- .../test/common/model/textModel.test.ts | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/vs/editor/common/model/indentationGuesser.ts b/src/vs/editor/common/model/indentationGuesser.ts index 01e850b65ff..c9cf713aabd 100644 --- a/src/vs/editor/common/model/indentationGuesser.ts +++ b/src/vs/editor/common/model/indentationGuesser.ts @@ -112,8 +112,8 @@ export function guessIndentation(source: ITextBuffer, defaultTabSize: number, de let previousLineText = ''; // content of latest line that contained non-whitespace chars let previousLineIndentation = 0; // index at which latest line contained the first non-whitespace char - const ALLOWED_TAB_SIZE_GUESSES = [2, 4, 6, 8]; // limit guesses for `tabSize` to 2, 4, 6 or 8. - const MAX_ALLOWED_TAB_SIZE_GUESS = 8; // max(2,4,6,8) = 8 + const ALLOWED_TAB_SIZE_GUESSES = [2, 4, 6, 8, 3, 5, 7]; // prefer even guesses for `tabSize`, limit to [2, 8]. + const MAX_ALLOWED_TAB_SIZE_GUESS = 8; // max(ALLOWED_TAB_SIZE_GUESSES) = 8 let spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0]; // `tabSize` scores let tmp = new SpacesDiffResult(); diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index ae557f66ab4..689d106837a 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -315,7 +315,7 @@ suite('Editor Model - TextModel', () => { ' ', ' ', ], 'whitespace lines don\'t count'); - assertGuess(true, 4, [ + assertGuess(true, 3, [ 'x', ' x', ' x', @@ -328,8 +328,8 @@ suite('Editor Model - TextModel', () => { ' x', ' x', ' x', - ], 'odd number is not allowed: 6x3, 3x4'); - assertGuess(true, 4, [ + ], '6x3, 3x4'); + assertGuess(true, 5, [ 'x', ' x', ' x', @@ -342,8 +342,12 @@ suite('Editor Model - TextModel', () => { ' x', ' x', ' x', - ], 'odd number is not allowed: 6x5, 3x4'); - assertGuess(true, 4, [ + ], '6x5, 3x4'); + assertGuess(true, 7, [ + 'x', + ' x', + ' x', + ' x', 'x', ' x', ' x', @@ -352,11 +356,7 @@ suite('Editor Model - TextModel', () => { ' x', ' x', ' x', - 'x', - ' x', - ' x', - ' x', - ], 'odd number is not allowed: 6x7, 3x4'); + ], '6x7, 1x5, 2x4'); assertGuess(true, 2, [ 'x', ' x', @@ -508,7 +508,7 @@ suite('Editor Model - TextModel', () => { ' x', ' x', ], '6x4, 2x5, 4x8'); - assertGuess(true, undefined, [ + assertGuess(true, 3, [ 'x', ' x', ' x', From 4e50ae607d4fa59e387a97283c1a2dfb21756149 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Sep 2018 11:23:23 -0700 Subject: [PATCH 02/76] Prev/Next Panel item --- .../workbench/browser/parts/compositeBar.ts | 8 +++ .../browser/parts/panel/panelActions.ts | 65 +++++++++++++++++++ .../browser/parts/panel/panelPart.ts | 7 ++ .../services/panel/common/panelService.ts | 7 +- .../progress/test/progressService.test.ts | 4 ++ 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index f2984c48423..098737bae7e 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -72,6 +72,10 @@ export class CompositeBar extends Widget implements ICompositeBar { return this.model.items; } + getPinnedComposites(): ICompositeBarItem[] { + return this.model.pinnedItems; + } + create(parent: HTMLElement): HTMLElement { const actionBarDiv = parent.appendChild($('.composite-bar')); this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, { @@ -460,6 +464,10 @@ class CompositeBarModel { return this.items.filter(item => item.visible); } + get pinnedItems(): ICompositeBarItem[] { + return this.items.filter(item => item.visible && item.pinned); + } + private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarItem { const options = this.options; return { diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 879f869d160..28cca983c57 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -169,6 +169,69 @@ export class PanelActivityAction extends ActivityAction { } } +export class SwitchPanelItemAction extends Action { + + constructor( + id: string, + name: string, + @IPanelService private panelService: IPanelService + ) { + super(id, name); + } + + run(offset: number): TPromise { + const pinnedPanels = this.panelService.getPinnedPanels(); + const activePanel = this.panelService.getActivePanel(); + if (!activePanel) { + return TPromise.as(null); + } + let targetPanelId: string; + for (let i = 0; i < pinnedPanels.length; i++) { + if (pinnedPanels[i].id === activePanel.getId()) { + targetPanelId = pinnedPanels[(i + pinnedPanels.length + offset) % pinnedPanels.length].id; + break; + } + } + return this.panelService.openPanel(targetPanelId, true); + } +} + +export class PreviousPanelViewAction extends SwitchPanelItemAction { + + static readonly ID = 'workbench.action.previousPanelView'; + static LABEL = nls.localize('previousPanelView', 'Previous Panel View'); + + constructor( + id: string, + name: string, + @IPanelService panelService: IPanelService + ) { + super(id, name, panelService); + } + + run(): TPromise { + return super.run(-1); + } +} + +export class NextPanelViewAction extends SwitchPanelItemAction { + + static readonly ID = 'workbench.action.nextPanelView'; + static LABEL = nls.localize('nextPanelView', 'Next Panel View'); + + constructor( + id: string, + name: string, + @IPanelService panelService: IPanelService + ) { + super(id, name, panelService); + } + + public run(): TPromise { + return super.run(1); + } +} + const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View")); @@ -176,6 +239,8 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedP actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PreviousPanelViewAction, PreviousPanelViewAction.ID, PreviousPanelViewAction.LABEL), 'View: Open Previous Panel View', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NextPanelViewAction, NextPanelViewAction.ID, NextPanelViewAction.LABEL), 'View: Open Next Panel View', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index d79b236141e..6b2332052da 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -198,6 +198,13 @@ export class PanelPart extends CompositePart implements IPanelService { .sort((v1, v2) => v1.order - v2.order); } + getPinnedPanels(): PanelDescriptor[] { + const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(c => c.id); + return this.getPanels() + .filter(p => pinnedCompositeIds.indexOf(p.id) !== -1) + .sort((p1, p2) => pinnedCompositeIds.indexOf(p1.id) - pinnedCompositeIds.indexOf(p2.id)); + } + setPanelEnablement(id: string, enabled: boolean): void { const descriptor = Registry.as(PanelExtensions.Panels).getPanels().filter(p => p.id === id).pop(); if (descriptor && descriptor.enabled !== enabled) { diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index 97179ea7bb8..6d73423c591 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -34,10 +34,15 @@ export interface IPanelService { getActivePanel(): IPanel; /** - * Returns all enabled panels + * * Returns all built-in panels following the default order (Problems - Output - Debug Console - Terminal) */ getPanels(): IPanelIdentifier[]; + /** + * Returns pinned panels following the visual order + */ + getPinnedPanels(): IPanelIdentifier[]; + /** * Enables or disables a panel. Disabled panels are completly hidden from UI. * By default all panels are enabled. diff --git a/src/vs/workbench/services/progress/test/progressService.test.ts b/src/vs/workbench/services/progress/test/progressService.test.ts index e81c13a61db..00c3b62b128 100644 --- a/src/vs/workbench/services/progress/test/progressService.test.ts +++ b/src/vs/workbench/services/progress/test/progressService.test.ts @@ -79,6 +79,10 @@ class TestPanelService implements IPanelService { return []; } + public getPinnedPanels(): any[] { + return []; + } + public getActivePanel(): IViewlet { return activeViewlet; } From 8869632ba20473f1e795c1217aab4caf7875ce21 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Sep 2018 14:34:36 -0700 Subject: [PATCH 03/76] Prev/Next Sidebar View --- .../parts/activitybar/activitybarActions.ts | 108 +++++++++++++++--- .../parts/activitybar/activitybarPart.ts | 8 +- .../browser/parts/panel/panelActions.ts | 6 +- .../workbench/electron-browser/workbench.ts | 2 +- .../activity/browser/activityService.ts | 5 + .../services/activity/common/activity.ts | 5 + .../services/viewlet/browser/viewlet.ts | 2 +- 7 files changed, 113 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 1ab2e743b9e..592230a3491 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -5,26 +5,31 @@ 'use strict'; -import 'vs/css!./media/activityaction'; import * as DOM from 'vs/base/browser/dom'; -import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { Action } from 'vs/base/common/actions'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; -import { dispose } from 'vs/base/common/lifecycle'; -import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActivityAction, ActivityActionItem, ICompositeBarColors, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; +import { Action } from 'vs/base/common/actions'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { dispose } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import 'vs/css!./media/activityaction'; +import * as nls from 'vs/nls'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; +import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { ActivityAction, ActivityActionItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; +import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; import { ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; +import { IActivityService } from 'vs/workbench/services/activity/common/activity'; +import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; export class ViewletActivityAction extends ActivityAction { @@ -191,6 +196,77 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne } } +class SwitchSidebarViewAction extends Action { + + constructor( + id: string, + name: string, + @IViewletService private viewletService: IViewletService, + @IActivityService private activityService: IActivityService + ) { + super(id, name); + } + + run(offset: number): TPromise { + const pinnedViewletIds = this.activityService.getPinnedViewletIds(); + + const activeViewlet = this.viewletService.getActiveViewlet(); + if (!activeViewlet) { + return TPromise.as(null); + } + let targetViewletId: string; + for (let i = 0; i < pinnedViewletIds.length; i++) { + if (pinnedViewletIds[i] === activeViewlet.getId()) { + targetViewletId = pinnedViewletIds[(i + pinnedViewletIds.length + offset) % pinnedViewletIds.length]; + break; + } + } + return this.viewletService.openViewlet(targetViewletId, true); + } +} + +export class PreviousSidebarViewAction extends SwitchSidebarViewAction { + + static readonly ID = 'workbench.action.previousSidebarView'; + static LABEL = nls.localize('previousSidebarView', 'Previous Sidebar View'); + + constructor( + id: string, + name: string, + @IViewletService viewletService: IViewletService, + @IActivityService activityService: IActivityService + ) { + super(id, name, viewletService, activityService); + } + + run(): TPromise { + return super.run(-1); + } +} + +export class NextSidebarViewAction extends SwitchSidebarViewAction { + + static readonly ID = 'workbench.action.nextSidebarView'; + static LABEL = nls.localize('nextSidebarView', 'Next Sidebar View'); + + constructor( + id: string, + name: string, + @IViewletService viewletService: IViewletService, + @IActivityService activityService: IActivityService + ) { + super(id, name, viewletService, activityService); + } + + run(): TPromise { + return super.run(1); + } +} + +const registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(PreviousSidebarViewAction, PreviousSidebarViewAction.ID, PreviousSidebarViewAction.LABEL), 'View: Open Previous Sidebar View', nls.localize('view', "View")); +registry.registerWorkbenchAction(new SyncActionDescriptor(NextSidebarViewAction, NextSidebarViewAction.ID, NextSidebarViewAction.LABEL), 'View: Open Next Sidebar View', nls.localize('view', "View")); + registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const activeForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 4ef749c3fda..74b9dc71297 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -306,8 +306,12 @@ export class ActivitybarPart extends Part { } } - getPinned(): string[] { - return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id)); + getPinnedViewletIds(): string[] { + const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id); + return this.viewletService.getViewlets() + .filter(v => this.compositeBar.isPinned(v.id)) + .sort((v1, v2) => pinnedCompositeIds.indexOf(v1.id) - pinnedCompositeIds.indexOf(v2.id)) + .map(v => v.id); } layout(dimension: Dimension): Dimension[] { diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 28cca983c57..34582928dec 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -169,7 +169,7 @@ export class PanelActivityAction extends ActivityAction { } } -export class SwitchPanelItemAction extends Action { +export class SwitchPanelViewAction extends Action { constructor( id: string, @@ -196,7 +196,7 @@ export class SwitchPanelItemAction extends Action { } } -export class PreviousPanelViewAction extends SwitchPanelItemAction { +export class PreviousPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.previousPanelView'; static LABEL = nls.localize('previousPanelView', 'Previous Panel View'); @@ -214,7 +214,7 @@ export class PreviousPanelViewAction extends SwitchPanelItemAction { } } -export class NextPanelViewAction extends SwitchPanelItemAction { +export class NextPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.nextPanelView'; static LABEL = nls.localize('nextPanelView', 'Next Panel View'); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 2952ac488fe..9b322ad8934 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -762,7 +762,7 @@ export class Workbench extends Disposable implements IPartService { return { customKeybindingsCount: this.keybindingService.customKeybindingsCount(), - pinnedViewlets: this.activitybarPart.getPinned(), + pinnedViewlets: this.activitybarPart.getPinnedViewletIds(), restoredViewlet: viewletIdToRestore, restoredEditorsCount: this.editorService.visibleEditors.length }; diff --git a/src/vs/workbench/services/activity/browser/activityService.ts b/src/vs/workbench/services/activity/browser/activityService.ts index 27bbe40af63..f230d4a2303 100644 --- a/src/vs/workbench/services/activity/browser/activityService.ts +++ b/src/vs/workbench/services/activity/browser/activityService.ts @@ -28,4 +28,9 @@ export class ActivityService implements IActivityService { return this.activitybarPart.showActivity(compositeOrActionId, badge, clazz, priority); } + + getPinnedViewletIds(): string[] { + return this.activitybarPart.getPinnedViewletIds(); + } + } diff --git a/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts index 27513b65417..06d2d83edd7 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -67,4 +67,9 @@ export interface IActivityService { * Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action. */ showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable; + + /** + * Returns id of pinned viewlets following the visual order + */ + getPinnedViewletIds(): string[]; } diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index a6903bb9fb9..1f0b49bb12f 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -42,7 +42,7 @@ export interface IViewletService { getViewlet(id: string): ViewletDescriptor; /** - * Returns all viewlets + * Returns all enabled viewlets following the default order (Explorer - Search - SCM - Debug - Extensions) */ getAllViewlets(): ViewletDescriptor[]; From 660209ca74f63033ea013d42dfc34954e8cee1c8 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Sep 2018 14:36:39 -0700 Subject: [PATCH 04/76] Import order --- .../workbench/browser/parts/activitybar/activitybarActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 592230a3491..ec9b4b364e7 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -5,6 +5,8 @@ 'use strict'; +import 'vs/css!./media/activityaction'; +import * as nls from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; @@ -14,8 +16,6 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { dispose } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import 'vs/css!./media/activityaction'; -import * as nls from 'vs/nls'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { Registry } from 'vs/platform/registry/common/platform'; From 7d30396d0cff7184b8e585a9d49893b41a6f5d8b Mon Sep 17 00:00:00 2001 From: benjamenhogben Date: Fri, 5 Oct 2018 09:48:33 +0100 Subject: [PATCH 05/76] Add throwable to try/catch block --- extensions/php/snippets/php.snippets.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/php/snippets/php.snippets.json b/extensions/php/snippets/php.snippets.json index c8dc8405300..1010dad8993 100644 --- a/extensions/php/snippets/php.snippets.json +++ b/extensions/php/snippets/php.snippets.json @@ -254,6 +254,8 @@ "body": [ "try {", "\t${1://code...}", + "} catch (\\Throwable \\$$t) {", + "\t${2://throw $$t;}", "} catch (\\Exception \\$$e) {", "\t${2://throw $$e;}", "}" From f0b51ea9ad914cadd0879d9ca784a05df528a7e8 Mon Sep 17 00:00:00 2001 From: benjamenhogben Date: Fri, 5 Oct 2018 10:50:02 +0100 Subject: [PATCH 06/76] Catch Throwable user editable --- extensions/php/snippets/php.snippets.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extensions/php/snippets/php.snippets.json b/extensions/php/snippets/php.snippets.json index 1010dad8993..f964dc42a01 100644 --- a/extensions/php/snippets/php.snippets.json +++ b/extensions/php/snippets/php.snippets.json @@ -254,10 +254,8 @@ "body": [ "try {", "\t${1://code...}", - "} catch (\\Throwable \\$$t) {", - "\t${2://throw $$t;}", - "} catch (\\Exception \\$$e) {", - "\t${2://throw $$e;}", + "} catch (${2:\\Throwable} ${3:$$t}) {", + "\t${4://throw $$th;}", "}" ], "description": "Try catch block" From 75dc89debcc71398b23761e3af4d5846ad584a1e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 8 Oct 2018 11:13:17 +0200 Subject: [PATCH 07/76] more measurement prop... --- src/vs/editor/contrib/suggest/suggestController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 0f873ea9bc3..74a5df0502c 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -284,7 +284,7 @@ export class SuggestController implements IEditorContribution { /* __GDPR__ "acceptSuggestion" : { "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "multiline" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "multiline" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } } */ service.publicLog('acceptSuggestion', { From a39a101d424075d20ba02ee6ed6ce7f2b9c2f7e4 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 8 Oct 2018 11:14:13 +0200 Subject: [PATCH 08/76] Don't assign 'editor' label --- .github/classifier.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/classifier.yml b/.github/classifier.yml index a7bcb40c96f..eba4910f445 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -20,7 +20,10 @@ }, diff-editor: [], dropdown: [], - editor: [], + editor: { + assignees: [], + assignLabel: false + }, editor-1000-limit: [], editor-autoclosing: [], editor-autoindent: [], From 96eb2ffc55273753c4e6c38e3c1f9a5b5c01e649 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 8 Oct 2018 11:23:16 +0200 Subject: [PATCH 09/76] debug: minimal updates to repl title when repl is not visible --- .../parts/debug/electron-browser/repl.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index 31b3b76547b..4f9dbc8019f 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -127,11 +127,23 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } this.replInput.updateOptions({ readOnly: !session }); - this.updateInputDecoration(); + if (this.isVisible()) { + this.updateInputDecoration(); + } })); this._register(this.panelService.onDidPanelOpen(panel => this.refreshReplElements(true))); this._register(this.debugService.onDidNewSession(() => this.updateTitleArea())); - this._register(this.themeService.onThemeChange(() => this.updateInputDecoration())); + this._register(this.debugService.onDidEndSession(() => { + if (this.debugService.getModel().getSessions().length === 0 && this.isVisible()) { + // Only hide the session drop down when there are 0 sessions + this.updateTitleArea(); + } + })); + this._register(this.themeService.onThemeChange(() => { + if (this.isVisible()) { + this.updateInputDecoration(); + } + })); } private refreshReplElements(noDelay: boolean): void { @@ -356,7 +368,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati return this.instantiationService.createInstance(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL); } - @memoize private get focusSessionActionItem(): FocusSessionActionItem { return this.instantiationService.createInstance(FocusSessionActionItem, this.focusSessionAction); } From e2027598992e56d7f6f6f26f804d53449ea1a2ee Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 8 Oct 2018 11:26:07 +0200 Subject: [PATCH 10/76] repl: minor fix --- src/vs/workbench/parts/debug/electron-browser/repl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index 4f9dbc8019f..0a0d7127d64 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -134,7 +134,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this._register(this.panelService.onDidPanelOpen(panel => this.refreshReplElements(true))); this._register(this.debugService.onDidNewSession(() => this.updateTitleArea())); this._register(this.debugService.onDidEndSession(() => { - if (this.debugService.getModel().getSessions().length === 0 && this.isVisible()) { + if (this.debugService.getModel().getSessions().length === 0) { // Only hide the session drop down when there are 0 sessions this.updateTitleArea(); } From 1580cd184645494128e1013d750800392ee58b7d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 8 Oct 2018 12:38:26 +0200 Subject: [PATCH 11/76] first version of simple clipboard API, #217 --- src/vs/vscode.proposed.d.ts | 13 +++++++++ .../extensionHost.contribution.ts | 1 + .../electron-browser/mainThreadClipboard.ts | 27 +++++++++++++++++++ src/vs/workbench/api/node/extHost.api.impl.ts | 6 +++++ src/vs/workbench/api/node/extHost.protocol.ts | 6 +++++ src/vs/workbench/api/node/extHostClipboard.ts | 26 ++++++++++++++++++ 6 files changed, 79 insertions(+) create mode 100644 src/vs/workbench/api/electron-browser/mainThreadClipboard.ts create mode 100644 src/vs/workbench/api/node/extHostClipboard.ts diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 29317dff255..c16a02dd272 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -11,6 +11,19 @@ declare module 'vscode' { export function sampleFunction(): Thenable; } + //#region Joh - clipboard https://github.com/Microsoft/vscode/issues/217 + + export interface Clipboard { + readText(): Promise; + writeText(value: string): Promise; + } + + export namespace env { + export const clipboard: Clipboard; + } + + //#endregion + //#region Joh - read/write in chunks export interface FileSystemProvider { diff --git a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts index 681c0ac477d..1b16047d2a9 100644 --- a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts @@ -15,6 +15,7 @@ import { LanguageConfigurationFileHandler } from 'vs/workbench/parts/codeEditor/ // --- mainThread participants import 'vs/workbench/api/node/apiCommands'; +import './mainThreadClipboard'; import './mainThreadCommands'; import './mainThreadConfiguration'; import './mainThreadDebugService'; diff --git a/src/vs/workbench/api/electron-browser/mainThreadClipboard.ts b/src/vs/workbench/api/electron-browser/mainThreadClipboard.ts new file mode 100644 index 00000000000..14c3f9bb644 --- /dev/null +++ b/src/vs/workbench/api/electron-browser/mainThreadClipboard.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { clipboard } from 'electron'; +import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { MainContext, MainThreadClipboardShape } from '../node/extHost.protocol'; + +@extHostNamedCustomer(MainContext.MainThreadClipboard) +export class MainThreadCommands implements MainThreadClipboardShape { + + dispose(): void { + // nothing + } + + $readText(): Promise { + return Promise.resolve(clipboard.readText()); + } + + $writeText(value: string): Promise { + clipboard.writeText(value); + return undefined; + } +} diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 37f9eb1ba19..a4ba38dd2ae 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -61,6 +61,7 @@ import { ExtHostComments } from './extHostComments'; import { ExtHostSearch } from './extHostSearch'; import { ExtHostUrls } from './extHostUrls'; import { localize } from 'vs/nls'; +import { ExtHostClipboard } from 'vs/workbench/api/node/extHostClipboard'; export interface IExtensionApiFactory { (extension: IExtensionDescription): typeof vscode; @@ -134,6 +135,7 @@ export function createApiFactory( rpcProtocol.assertRegistered(expected); // Other instances + const extHostClipboard = new ExtHostClipboard(rpcProtocol); const extHostMessageService = new ExtHostMessageService(rpcProtocol); const extHostDialogs = new ExtHostDialogs(rpcProtocol); const extHostStatusBar = new ExtHostStatusBar(rpcProtocol); @@ -237,6 +239,10 @@ export function createApiFactory( get onDidChangeLogLevel() { checkProposedApiEnabled(extension); return extHostLogService.onDidChangeLogLevel; + }, + get clipboard(): vscode.Clipboard { + checkProposedApiEnabled(extension); + return extHostClipboard; } }); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 113ab79fe56..8debd6373de 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -86,6 +86,11 @@ export interface IMainContext extends IRPCProtocol { // --- main thread +export interface MainThreadClipboardShape extends IDisposable { + $readText(): Promise; + $writeText(value: string): Promise; +} + export interface MainThreadCommandsShape extends IDisposable { $registerCommand(id: string): void; $unregisterCommand(id: string): void; @@ -1014,6 +1019,7 @@ export interface ExtHostCommentsShape { // --- proxy identifiers export const MainContext = { + MainThreadClipboard: >createMainId('MainThreadClipboard'), MainThreadCommands: >createMainId('MainThreadCommands'), MainThreadComments: createMainId('MainThreadComments'), MainThreadConfiguration: createMainId('MainThreadConfiguration'), diff --git a/src/vs/workbench/api/node/extHostClipboard.ts b/src/vs/workbench/api/node/extHostClipboard.ts new file mode 100644 index 00000000000..342845ba00d --- /dev/null +++ b/src/vs/workbench/api/node/extHostClipboard.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { IMainContext, MainContext, MainThreadClipboardShape } from 'vs/workbench/api/node/extHost.protocol'; +import * as vscode from 'vscode'; + +export class ExtHostClipboard implements vscode.Clipboard { + + private readonly _proxy: MainThreadClipboardShape; + + constructor(mainContext: IMainContext) { + this._proxy = mainContext.getProxy(MainContext.MainThreadClipboard); + } + + readText(): Promise { + return this._proxy.$readText(); + } + + writeText(value: string): Promise { + return this._proxy.$writeText(value); + } +} From f91e70bcdb7021fd3bb354d1ea5331260ce7abbb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 8 Oct 2018 15:10:04 +0200 Subject: [PATCH 12/76] expose label tuple in API, #56337 --- src/vs/vscode.d.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index e53b48e2b7e..13b07a2fc06 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3023,10 +3023,13 @@ declare module 'vscode' { export class ParameterInformation { /** - * The label of this signature. *Note*: Must be a substring of its - * containing signature information's [label](#SignatureInformation.label). + * The label of this signature. + * + * Either a string or inclusive start and exclusive end offsets within its containing + * [signature label](#SignatureInformation.label). *Note*: A label of type string must be + * a substring of its containing signature information's [label](#SignatureInformation.label). */ - label: string; + label: string | [number, number]; /** * The human-readable doc-comment of this signature. Will be shown From e69c3db65a17c9cfc6606fbe7e7449861c440766 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 8 Oct 2018 15:38:11 +0200 Subject: [PATCH 13/76] fix #59966 --- .../parts/snippets/electron-browser/configureSnippets.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/snippets/electron-browser/configureSnippets.ts b/src/vs/workbench/parts/snippets/electron-browser/configureSnippets.ts index 3995d569a17..74a5456754e 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/configureSnippets.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/configureSnippets.ts @@ -19,6 +19,7 @@ import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/ import { SnippetSource } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IFileService } from 'vs/platform/files/common/files'; +import { INotificationService } from 'vs/platform/notification/common/notification'; const id = 'workbench.action.openSnippets'; @@ -117,7 +118,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir return { existing, future }; } -async function createGlobalSnippetFile(defaultPath: URI, windowService: IWindowService, fileService: IFileService, opener: IOpenerService) { +async function createGlobalSnippetFile(defaultPath: URI, windowService: IWindowService, notificationService: INotificationService, fileService: IFileService, opener: IOpenerService) { await fileService.createFolder(defaultPath); await timeout(100); // ensure quick pick closes... @@ -131,6 +132,7 @@ async function createGlobalSnippetFile(defaultPath: URI, windowService: IWindowS } const resource = URI.file(path); if (dirname(resource.fsPath) !== defaultPath.fsPath) { + notificationService.error(nls.localize('badPath', "Snippets must be inside this folder: '{0}'. ", defaultPath.fsPath)); return undefined; } @@ -190,6 +192,7 @@ CommandsRegistry.registerCommand(id, async accessor => { const windowService = accessor.get(IWindowService); const modeService = accessor.get(IModeService); const envService = accessor.get(IEnvironmentService); + const notificationService = accessor.get(INotificationService); const workspaceService = accessor.get(IWorkspaceContextService); const fileService = accessor.get(IFileService); @@ -221,7 +224,7 @@ CommandsRegistry.registerCommand(id, async accessor => { }); if (globalSnippetPicks.indexOf(pick as GlobalSnippetPick) >= 0) { - return createGlobalSnippetFile((pick as GlobalSnippetPick).uri, windowService, fileService, opener); + return createGlobalSnippetFile((pick as GlobalSnippetPick).uri, windowService, notificationService, fileService, opener); } else if (ISnippetPick.is(pick)) { if (pick.hint) { await createLanguageSnippetFile(pick, fileService); From 61ee5fad062f9ee123a96c178f192a5fa3a9d371 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 8 Oct 2018 15:52:35 +0200 Subject: [PATCH 14/76] fix typo --- .../services/configuration/node/configurationService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 302ba8a2a22..ea48e1b4e4a 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -322,7 +322,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private createWorkspace(arg: IWorkspaceIdentifier | URI | IWindowConfiguration): Promise { if (isWorkspaceIdentifier(arg)) { - return this.createMulitFolderWorkspace(arg); + return this.createMultiFolderWorkspace(arg); } if (isSingleFolderWorkspaceIdentifier(arg)) { @@ -332,7 +332,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return this.createEmptyWorkspace(arg); } - private createMulitFolderWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise { + private createMultiFolderWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise { const workspaceConfigPath = URI.file(workspaceIdentifier.configPath); return this.workspaceConfiguration.load(workspaceConfigPath) .then(() => { From fc971b16741c1c035fd3eb2bfc99526cf6dd016b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 8 Oct 2018 16:08:23 +0200 Subject: [PATCH 15/76] electron@2.0.11 (#60143) --- .yarnrc | 2 +- OSSREADME.json | 2 +- test/smoke/package.json | 2 +- test/smoke/yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.yarnrc b/.yarnrc index 40cb5766ccb..55749a8a0a7 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "2.0.9" +target "2.0.11" runtime "electron" diff --git a/OSSREADME.json b/OSSREADME.json index 98c9d0476b5..c59395867eb 100644 --- a/OSSREADME.json +++ b/OSSREADME.json @@ -51,7 +51,7 @@ }, { "name": "electron", - "version": "2.0.9", + "version": "2.0.11", "license": "MIT", "repositoryURL": "https://github.com/electron/electron", "isProd": true diff --git a/test/smoke/package.json b/test/smoke/package.json index 5c895fb7209..ef0dd229f41 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -22,7 +22,7 @@ "@types/webdriverio": "4.6.1", "concurrently": "^3.5.1", "cpx": "^1.5.0", - "electron": "^2.0.9", + "electron": "^2.0.11", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^5.2.0", diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 3ebe0c75ec5..0f246945f20 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -584,10 +584,10 @@ electron-download@^3.0.1: semver "^5.3.0" sumchecker "^1.2.0" -electron@^2.0.9: - version "2.0.9" - resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.9.tgz#dfc863d653fa3a2dd4fea0c63303df9c0e33c602" - integrity sha512-xRefYuz6C65ahX8vDwIJxr1Y5ffFa106dugZEbl23yLKfrAG01lh5csBJ9hJwCBPLHp2zj/9PGoJ8dt5zlzOvQ== +electron@^2.0.11: + version "2.0.11" + resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.11.tgz#8e352a83ec607471e82d323a2adc7e7b53698e79" + integrity sha512-bFTMDQN3epfiymqTPdgffyTxuy/7A52sIkW7Hos+hY5XLPArOXLXAKx1JtB3dM7CcPfZa+5qp/J3cPCidh5WXg== dependencies: "@types/node" "^8.0.24" electron-download "^3.0.1" From ff085d3bc7e4098f4965e4649f226c60ff46f229 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 8 Oct 2018 16:11:59 +0200 Subject: [PATCH 16/76] Fixes #59328 --- src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts index 2b6a07650d2..05e59918069 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts @@ -138,7 +138,7 @@ export class ViewCursor { width = dom.computeScreenAwareSize(1); } let left = visibleRange.left; - if (width >= 2) { + if (width >= 2 && left >= 1) { // try to center cursor left -= 1; } From a2455b79a0dfe1f928f0f015b7e53ddff770c5a8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 8 Oct 2018 16:54:28 +0200 Subject: [PATCH 17/76] revert "exploration" --- build/tfs/common/publish.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tfs/common/publish.ts b/build/tfs/common/publish.ts index 100d2b88581..7a74dc6106e 100644 --- a/build/tfs/common/publish.ts +++ b/build/tfs/common/publish.ts @@ -152,7 +152,7 @@ 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' || quality === 'exploration') + const isReleased = quality === 'insider' && /^master$|^refs\/heads\/master$/.test(sourceBranch) && /Project Collection Service Accounts|Microsoft.VisualStudio.Services.TFS/.test(queuedBy); From 6d8b6d39ccf849ecd2805937d386a8c159559e1f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 08:10:15 -0700 Subject: [PATCH 18/76] Remove css vendor pefixes for transition and transform (#60050) The css3 `transform` and `transition` properties are now widely supported. I do not believe we need to ship vendor prefixed rules for these anymore --- src/vs/base/browser/ui/actionbar/actionbar.css | 14 +------------- src/vs/base/browser/ui/menu/menu.css | 8 -------- src/vs/base/browser/ui/progressbar/progressbar.css | 4 ---- .../base/browser/ui/scrollbar/media/scrollbars.css | 8 -------- src/vs/base/browser/ui/splitview/panelview.css | 8 -------- src/vs/editor/contrib/find/findWidget.css | 6 ------ src/vs/editor/contrib/find/simpleFindWidget.css | 5 ----- .../contrib/parameterHints/parameterHints.css | 3 --- .../parts/debug/browser/media/debugViewlet.css | 2 -- 9 files changed, 1 insertion(+), 57 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 4ff042d038f..25795ddb631 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -28,10 +28,6 @@ .monaco-action-bar .action-item { cursor: pointer; display: inline-block; - -ms-transition: -ms-transform 50ms ease; - -webkit-transition: -webkit-transform 50ms ease; - -moz-transition: -moz-transform 50ms ease; - -o-transition: -o-transform 50ms ease; transition: transform 50ms ease; position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */ } @@ -41,11 +37,7 @@ } .monaco-action-bar.animated .action-item.active { - -ms-transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */ - -webkit-transform: scale(1.272019649, 1.272019649); - -moz-transform: scale(1.272019649, 1.272019649); - -o-transform: scale(1.272019649, 1.272019649); - transform: scale(1.272019649, 1.272019649); + transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */ } .monaco-action-bar .action-item .icon { @@ -87,10 +79,6 @@ } .monaco-action-bar.animated.vertical .action-item.active { - -ms-transform: translate(5px, 0); - -webkit-transform: translate(5px, 0); - -moz-transform: translate(5px, 0); - -o-transform: translate(5px, 0); transform: translate(5px, 0); } diff --git a/src/vs/base/browser/ui/menu/menu.css b/src/vs/base/browser/ui/menu/menu.css index 938304b5ef2..63c1860664d 100644 --- a/src/vs/base/browser/ui/menu/menu.css +++ b/src/vs/base/browser/ui/menu/menu.css @@ -14,20 +14,12 @@ .monaco-menu .monaco-action-bar.vertical .action-item { padding: 0; - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; transform: none; display: -ms-flexbox; display: flex; } .monaco-menu .monaco-action-bar.vertical .action-item.active { - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; transform: none; } diff --git a/src/vs/base/browser/ui/progressbar/progressbar.css b/src/vs/base/browser/ui/progressbar/progressbar.css index 0546a200cdf..f926530cec4 100644 --- a/src/vs/base/browser/ui/progressbar/progressbar.css +++ b/src/vs/base/browser/ui/progressbar/progressbar.css @@ -24,10 +24,6 @@ .monaco-progress-container.discrete .progress-bit { left: 0; transition: width 100ms linear; - -webkit-transition: width 100ms linear; - -o-transition: width 100ms linear; - -moz-transition: width 100ms linear; - -ms-transition: width 100ms linear; } .monaco-progress-container.discrete.done .progress-bit { diff --git a/src/vs/base/browser/ui/scrollbar/media/scrollbars.css b/src/vs/base/browser/ui/scrollbar/media/scrollbars.css index aa824d83a2f..b05c77eed8a 100644 --- a/src/vs/base/browser/ui/scrollbar/media/scrollbars.css +++ b/src/vs/base/browser/ui/scrollbar/media/scrollbars.css @@ -44,10 +44,6 @@ /* Background rule added for IE9 - to allow clicks on dom node */ background:rgba(0,0,0,0); - -webkit-transition: opacity 100ms linear; - -o-transition: opacity 100ms linear; - -moz-transition: opacity 100ms linear; - -ms-transition: opacity 100ms linear; transition: opacity 100ms linear; } .monaco-scrollable-element > .invisible { @@ -55,10 +51,6 @@ pointer-events: none; } .monaco-scrollable-element > .invisible.fade { - -webkit-transition: opacity 800ms linear; - -o-transition: opacity 800ms linear; - -moz-transition: opacity 800ms linear; - -ms-transition: opacity 800ms linear; transition: opacity 800ms linear; } diff --git a/src/vs/base/browser/ui/splitview/panelview.css b/src/vs/base/browser/ui/splitview/panelview.css index fba60f61621..4801a2bd3a9 100644 --- a/src/vs/base/browser/ui/splitview/panelview.css +++ b/src/vs/base/browser/ui/splitview/panelview.css @@ -90,21 +90,13 @@ .monaco-panel-view.animated .split-view-view { transition-duration: 0.15s; - -webkit-transition-duration: 0.15s; - -moz-transition-duration: 0.15s; transition-timing-function: ease-out; - -webkit-transition-timing-function: ease-out; - -moz-transition-timing-function: ease-out; } .monaco-panel-view.animated.vertical .split-view-view { transition-property: height; - -webkit-transition-property: height; - -moz-transition-property: height; } .monaco-panel-view.animated.horizontal .split-view-view { transition-property: width; - -webkit-transition-property: width; - -moz-transition-property: width; } diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index eb838937d58..461ece739b9 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -36,13 +36,7 @@ height: 34px; /* find input height */ overflow: hidden; line-height: 19px; - - -webkit-transition: top 200ms linear; - -o-transition: top 200ms linear; - -moz-transition: top 200ms linear; - -ms-transition: top 200ms linear; transition: top 200ms linear; - padding: 0 4px; } /* Find widget when replace is toggled on */ diff --git a/src/vs/editor/contrib/find/simpleFindWidget.css b/src/vs/editor/contrib/find/simpleFindWidget.css index 9037b26a7fc..cbcf1f1fc8b 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.css +++ b/src/vs/editor/contrib/find/simpleFindWidget.css @@ -22,11 +22,6 @@ padding: 4px; align-items: center; pointer-events: all; - - -webkit-transition: top 200ms linear; - -o-transition: top 200ms linear; - -moz-transition: top 200ms linear; - -ms-transition: top 200ms linear; transition: top 200ms linear; } diff --git a/src/vs/editor/contrib/parameterHints/parameterHints.css b/src/vs/editor/contrib/parameterHints/parameterHints.css index c65b3e07e8d..625740080a7 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHints.css +++ b/src/vs/editor/contrib/parameterHints/parameterHints.css @@ -22,9 +22,6 @@ } .monaco-editor .parameter-hints-widget.visible { - -webkit-transition: left .05s ease-in-out; - -moz-transition: left .05s ease-in-out; - -o-transition: left .05s ease-in-out; transition: left .05s ease-in-out; } diff --git a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css index 48ab4d9099a..1f760b93e71 100644 --- a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css @@ -72,7 +72,6 @@ background-position: center center; flex-shrink: 0; transition: transform 50ms ease; - -webkit-transition: -webkit-transform 50ms ease; } .vs-dark .monaco-workbench > .part > .title > .title-actions .start-debug-action-item .icon, @@ -93,7 +92,6 @@ } .monaco-workbench > .part > .title > .title-actions .start-debug-action-item .icon.active { - -webkit-transform: scale(1.272019649, 1.272019649); transform: scale(1.272019649, 1.272019649); } From a342380e896984977fa6a79121c559818dda4c71 Mon Sep 17 00:00:00 2001 From: Marcus Farkas Date: Sun, 7 Oct 2018 20:58:47 +0200 Subject: [PATCH 19/76] Add setting to allow to disable Replace Preview Introduces a new settings option "search.useReplacePreview" which allows you to disable "Replace Preview" during a Search/Replace. Closes #60027 --- src/vs/platform/search/common/search.ts | 1 + src/vs/workbench/parts/search/browser/searchView.ts | 3 ++- .../parts/search/electron-browser/search.contribution.ts | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 31be8e8fcde..4469a60ea0b 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -282,6 +282,7 @@ export interface ISearchConfigurationProperties { smartCase: boolean; globalFindClipboard: boolean; location: 'sidebar' | 'panel'; + useReplacePreview: boolean; } export interface ISearchConfiguration extends IFilesConfiguration { diff --git a/src/vs/workbench/parts/search/browser/searchView.ts b/src/vs/workbench/parts/search/browser/searchView.ts index 57d08121dbf..de7679300bc 100644 --- a/src/vs/workbench/parts/search/browser/searchView.ts +++ b/src/vs/workbench/parts/search/browser/searchView.ts @@ -1402,7 +1402,8 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { return TPromise.as(true); } - return (this.viewModel.isReplaceActive() && !!this.viewModel.replaceString) ? + const useReplacePreview = this.configurationService.getValue().search.useReplacePreview; + return (useReplacePreview && this.viewModel.isReplaceActive() && !!this.viewModel.replaceString) ? this.replaceService.openReplacePreview(lineMatch, preserveFocus, sideBySide, pinned) : this.open(lineMatch, preserveFocus, sideBySide, pinned); } diff --git a/src/vs/workbench/parts/search/electron-browser/search.contribution.ts b/src/vs/workbench/parts/search/electron-browser/search.contribution.ts index 3cd8d9f8021..d7ce5846eb6 100644 --- a/src/vs/workbench/parts/search/electron-browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/electron-browser/search.contribution.ts @@ -643,6 +643,11 @@ configurationRegistry.registerConfiguration({ ], default: 'auto', description: nls.localize('search.collapseAllResults', "Controls whether the search results will be collapsed or expanded."), + }, + 'search.useReplacePreview': { + type: 'boolean', + default: true, + description: nls.localize('search.useReplacePreview', "Controls whether to open Replace Preview when replacing a match."), } } }); From 00cd0c355bbc5479070bee5604b8fe3d64ae05ad Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Mon, 8 Oct 2018 08:48:08 -0700 Subject: [PATCH 20/76] Increase max-width for find-widget --- src/vs/editor/contrib/find/findWidget.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index 461ece739b9..faf3f7efe98 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -247,7 +247,7 @@ /* COLLAPSED (SMALLER THAN NARROW) */ .monaco-editor .find-widget.collapsed-find-widget { - max-width: 111px !important; + max-width: 170px !important; } .monaco-editor .find-widget.collapsed-find-widget .button.previous, From d4f40dd755171447cc1c522f7ce57518bcafba25 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 8 Oct 2018 09:14:43 -0700 Subject: [PATCH 21/76] vscode-xterm@3.9.0-beta2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e988b55a858..ae860ddb5c1 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "vscode-nsfw": "1.0.17", "vscode-ripgrep": "^1.2.2", "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.9.0-beta1", + "vscode-xterm": "3.9.0-beta2", "winreg": "^1.2.4", "yauzl": "^2.9.1", "yazl": "^2.4.3" diff --git a/yarn.lock b/yarn.lock index d256989808f..757d51dd7af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9351,10 +9351,10 @@ vscode-textmate@^4.0.1: dependencies: oniguruma "^7.0.0" -vscode-xterm@3.9.0-beta1: - version "3.9.0-beta1" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.9.0-beta1.tgz#dfe0ff41ee062a9fbcda9eb050dcd9e73fe34278" - integrity sha512-PMLI+4n6ysY2VB/6UF9j1OZ8RR4wATc+mdVFb1fEVWI4k6i6mdTNpMrd9U5cLJaswfr+hlql2PQL9EprhuKRNA== +vscode-xterm@3.9.0-beta2: + version "3.9.0-beta2" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.9.0-beta2.tgz#36e6c6b3dee9324343d240acec0bc0af5283e8bd" + integrity sha512-v8uPv0UGoOxz6t22l/0uxIdcZVNOldk/5ZNp1zjVW+EBecE/zN4JCY3rAJALpgsTm4XlJZfi0f49yLVeyg3WeA== vso-node-api@6.1.2-preview: version "6.1.2-preview" From fd52305912e5ad64134f3b942d3d8f2d0ab81ccc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 8 Oct 2018 09:15:40 -0700 Subject: [PATCH 22/76] Update xterm types --- src/typings/vscode-xterm.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/typings/vscode-xterm.d.ts b/src/typings/vscode-xterm.d.ts index a104e7aee35..2631d806ad2 100644 --- a/src/typings/vscode-xterm.d.ts +++ b/src/typings/vscode-xterm.d.ts @@ -89,6 +89,16 @@ declare module 'vscode-xterm' { */ experimentalCharAtlas?: 'none' | 'static' | 'dynamic'; + /** + * (EXPERIMENTAL) Defines which implementation to use for buffer lines. + * + * - 'JsArray': The default/stable implementation. + * - 'TypedArray': The new experimental implementation based on TypedArrays that is expected to + * significantly boost performance and memory consumption. Use at your own risk. + * + * This option will be removed in the future. + */ + experimentalBufferLineImpl?: 'JsArray' | 'TypedArray'; /** * The font size used to render text. */ From a2b1bf32bb524806c560cc530d05ad94cbc310ea Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 8 Oct 2018 09:33:56 -0700 Subject: [PATCH 23/76] Add terminal.integrated.experimentalBufferImpl setting Fixes #60155 --- src/vs/workbench/parts/terminal/common/terminal.ts | 1 + .../terminal/electron-browser/terminal.contribution.ts | 8 +++++++- .../parts/terminal/electron-browser/terminalInstance.ts | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 77ad882bbbf..3f698d71998 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -99,6 +99,7 @@ export interface ITerminalConfiguration { windows: { [key: string]: string }; }; showExitAlert: boolean; + experimentalBufferImpl: 'JsArray' | 'TypedArray'; } export interface ITerminalConfigHelper { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 747f387527b..4a5d86980b4 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -372,7 +372,13 @@ configurationRegistry.registerConfiguration({ 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.experimentalBufferImpl': { + description: nls.localize('terminal.integrated.experimentalBufferImpl', "Controls the terminal's internal buffer implementation. This setting is picked up on terminal creation and will not apply to existing terminals."), + type: 'string', + enum: ['JsArray', 'TypedArray'], + default: 'JsArray' + }, } }); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 8df176d3cee..68b2f48d4e9 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -302,7 +302,8 @@ export class TerminalInstance implements ITerminalInstance { // TODO: Guess whether to use canvas or dom better rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType, // TODO: Remove this once the setting is removed upstream - experimentalCharAtlas: 'dynamic' + experimentalCharAtlas: 'dynamic', + experimentalBufferLineImpl: config.experimentalBufferImpl }); if (this._shellLaunchConfig.initialText) { this._xterm.writeln(this._shellLaunchConfig.initialText); From d0ecfa0ba66bf522ffae18390485d88d35d931a9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 09:34:48 -0700 Subject: [PATCH 24/76] Adding pinning tests for vscode-resource in webviews --- .../src/singlefolder-tests/webview.test.ts | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts index e4311f57343..3bde493b12b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts @@ -43,7 +43,7 @@ suite('Webview tests', () => { }); test('webviews should not have scripts enabled by default', async () => { - const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { })); + const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, {})); const response = Promise.race([ getMesssage(webview), new Promise<{}>(resolve => setTimeout(() => resolve({ value: '🎉' }), 1000)) @@ -71,14 +71,14 @@ suite('Webview tests', () => { assert.strictEqual((await response).value, 'first'); } { - const firstResponse = getMesssage(webview); + const response = getMesssage(webview); webview.webview.html = createHtmlDocumentWithBody(/*html*/` `); - assert.strictEqual((await firstResponse).value, 'second'); + assert.strictEqual((await response).value, 'second'); } }); @@ -243,6 +243,40 @@ suite('Webview tests', () => { const secondResponse = await sendRecieveMessage(webview, { type: 'get' }); assert.strictEqual(secondResponse.value, 100); }); + + test('webviews should only be able to load resources from workspace by default', async () => { + const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); + + webview.webview.html = createHtmlDocumentWithBody(/*html*/` + `); + + const workspaceRootUri = vscode.Uri.file(vscode.workspace.rootPath!).with({ scheme: 'vscode-resource' }); + + { + const imagePath = workspaceRootUri.toString() + '/image.png'; + const response = sendRecieveMessage(webview, { src: imagePath }); + assert.strictEqual((await response).value, true); + } + { + const imagePath = workspaceRootUri.toString() + '/no-such-image.png'; + const response = sendRecieveMessage(webview, { src: imagePath }); + assert.strictEqual((await response).value, false); + } + { + const imagePath = vscode.Uri.file(join(vscode.workspace.rootPath!, '..', '..', '..', 'resources', 'linux', 'code.png')).with({ scheme: 'vscode-resource' }); + const response = sendRecieveMessage(webview, { src: imagePath.toString() }); + assert.strictEqual((await response).value, false); + } + }); }); function createHtmlDocumentWithBody(body: string): string { From 5b03dcd69d98b6540f789868cf4647b6486ed739 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 10:08:34 -0700 Subject: [PATCH 25/76] Add pinning test for setting localResourceRoots --- .../src/singlefolder-tests/webview.test.ts | 30 ++++++++++++++++++ .../testWorkspace/sub/image.png | Bin 0 -> 36726 bytes 2 files changed, 30 insertions(+) create mode 100644 extensions/vscode-api-tests/testWorkspace/sub/image.png diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts index 3bde493b12b..d211db9565b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts @@ -277,6 +277,36 @@ suite('Webview tests', () => { assert.strictEqual((await response).value, false); } }); + + test('webviews should allow overriding allowed resource paths using localResourceRoots', async () => { + const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { + enableScripts: true, + localResourceRoots: [vscode.Uri.file(join(vscode.workspace.rootPath!, 'sub'))] + })); + + webview.webview.html = createHtmlDocumentWithBody(/*html*/` + `); + + const workspaceRootUri = vscode.Uri.file(vscode.workspace.rootPath!).with({ scheme: 'vscode-resource' }); + + { + const response = sendRecieveMessage(webview, { src: workspaceRootUri.toString() + '/sub/image.png' }); + assert.strictEqual((await response).value, true); + } + { + const response = sendRecieveMessage(webview, { src: workspaceRootUri.toString() + '/image.png' }); + assert.strictEqual((await response).value, false); + } + }); }); function createHtmlDocumentWithBody(body: string): string { diff --git a/extensions/vscode-api-tests/testWorkspace/sub/image.png b/extensions/vscode-api-tests/testWorkspace/sub/image.png new file mode 100644 index 0000000000000000000000000000000000000000..ff8b42295dd3078e8336b79f03385de09d68ed33 GIT binary patch literal 36726 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 literal 0 HcmV?d00001 From 6b2c0d902b003425a495c9236aad56adffd252d5 Mon Sep 17 00:00:00 2001 From: Marcus Farkas Date: Mon, 8 Oct 2018 19:47:27 +0200 Subject: [PATCH 26/76] Reword description of "search.useReplacePreview" setting --- .../parts/search/electron-browser/search.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/search/electron-browser/search.contribution.ts b/src/vs/workbench/parts/search/electron-browser/search.contribution.ts index d7ce5846eb6..cacb5c850b3 100644 --- a/src/vs/workbench/parts/search/electron-browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/electron-browser/search.contribution.ts @@ -647,7 +647,7 @@ configurationRegistry.registerConfiguration({ 'search.useReplacePreview': { type: 'boolean', default: true, - description: nls.localize('search.useReplacePreview', "Controls whether to open Replace Preview when replacing a match."), + description: nls.localize('search.useReplacePreview', "Controls whether to open Replace Preview when selecting or replacing a match."), } } }); From b1a4f3203f599a972806bdd7b933aa8a42c3cc0b Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Mon, 8 Oct 2018 10:48:10 -0700 Subject: [PATCH 27/76] fixes #60067 --- src/vs/base/browser/ui/actionbar/actionbar.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 9a4fb385355..4d25c01ecfd 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -419,6 +419,10 @@ export class ActionBar extends Disposable implements IActionRunner { this._context = options.context; this._actionRunner = this.options.actionRunner; + if (!this.options.triggerKeys) { + this.options.triggerKeys = defaultOptions.triggerKeys; + } + if (!this._actionRunner) { this._actionRunner = new ActionRunner(); this._register(this._actionRunner); From d4f8db74d41ff3f74a1b3743f677097369c75429 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Mon, 8 Oct 2018 10:55:34 -0700 Subject: [PATCH 28/76] adding ability to set checked state for menu item at registration (#60004) * adding ability to set checked state for menu item at registration * address feedback --- src/vs/platform/actions/common/actions.ts | 4 +++- .../browser/parts/editor/breadcrumbsControl.ts | 3 ++- .../browser/parts/titlebar/menubarControl.ts | 18 ------------------ .../electron-browser/toggleMinimap.ts | 4 +++- .../toggleRenderControlCharacter.ts | 4 +++- .../electron-browser/toggleRenderWhitespace.ts | 4 +++- .../fileActions.contribution.ts | 3 ++- 7 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index b9807b16522..ea9ccf27ca7 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -27,6 +27,7 @@ export interface IBaseCommandAction { export interface ICommandAction extends IBaseCommandAction { iconLocation?: { dark: URI; light?: URI; }; precondition?: ContextKeyExpr; + toggled?: ContextKeyExpr; } export interface ISerializableCommandAction extends IBaseCommandAction { @@ -220,7 +221,6 @@ export class ExecuteCommandAction extends Action { } export class SubmenuItemAction extends Action { - // private _options: IMenuActionOptions; readonly item: ISubmenuItem; constructor(item: ISubmenuItem) { @@ -246,6 +246,8 @@ export class MenuItemAction extends ExecuteCommandAction { typeof item.title === 'string' ? super(item.id, item.title, commandService) : super(item.id, item.title.value, commandService); this._cssClass = undefined; this._enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition); + this._checked = item.toggled && contextKeyService.contextMatchesRules(item.toggled); + this._options = options || {}; this.item = item; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 28ed4f7fc3d..515593ff365 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -458,7 +458,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { order: 99, command: { id: 'breadcrumbs.toggle', - title: localize('miToggleBreadcrumbs', "Toggle &&Breadcrumbs") + title: localize('miToggleBreadcrumbs', "Toggle &&Breadcrumbs"), + toggled: ContextKeyExpr.equals('config.breadcrumbs.enabled', true) } }); CommandsRegistry.registerCommand('breadcrumbs.toggle', accessor => { diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 3c0365e9418..260eaa4b47c 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -179,10 +179,6 @@ export class MenubarControl extends Disposable { return enableMenuBarMnemonics; } - private get currentAutoSaveSetting(): string { - return this.configurationService.getValue('files.autoSave'); - } - private get currentSidebarPosition(): string { return this.configurationService.getValue('workbench.sideBar.location'); } @@ -485,17 +481,6 @@ export class MenubarControl extends Disposable { this.mnemonics.set(KeyCodeUtils.fromString(mnemonic), menuIndex); } - private setCheckedStatus(action: IAction | IMenubarMenuItemAction) { - switch (action.id) { - case 'workbench.action.toggleAutoSave': - action.checked = this.currentAutoSaveSetting !== 'off'; - break; - - default: - break; - } - } - private calculateActionLabel(action: IAction | IMenubarMenuItemAction): string { let label = action.label; switch (action.id) { @@ -717,7 +702,6 @@ export class MenubarControl extends Disposable { target.push(new SubmenuAction(action.label, submenuActions)); } else { action.label = this.calculateActionLabel(action); - this.setCheckedStatus(action); target.push(action); } } @@ -987,9 +971,7 @@ export class MenubarControl extends Disposable { keybinding: this.getMenubarKeybinding(menuItem.id) }; - this.setCheckedStatus(menubarMenuItem); menubarMenuItem.label = this.calculateActionLabel(menubarMenuItem); - menuToPopulate.items.push(menubarMenuItem); } }); diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts index dd032a17ec2..0b7cf367959 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts @@ -9,6 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export class ToggleMinimapAction extends Action { public static readonly ID = 'editor.action.toggleMinimap'; @@ -35,7 +36,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', command: { id: ToggleMinimapAction.ID, - title: nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap") + title: nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap"), + toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true) }, order: 2 }); diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts index f7f7e580297..e0e854880ff 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts @@ -9,6 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export class ToggleRenderControlCharacterAction extends Action { @@ -36,7 +37,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', command: { id: ToggleRenderControlCharacterAction.ID, - title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters") + title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"), + toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true) }, order: 4 }); diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts index 8b3f0bf808e..b6d0bc806eb 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts @@ -9,6 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export class ToggleRenderWhitespaceAction extends Action { @@ -44,7 +45,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', command: { id: ToggleRenderWhitespaceAction.ID, - title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace") + title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"), + toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none') }, order: 3 }); diff --git a/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.ts index 6f49cecc5bd..0e1d9d3b494 100644 --- a/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.ts @@ -555,7 +555,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '5_autosave', command: { id: ToggleAutoSaveAction.ID, - title: nls.localize({ key: 'miAutoSave', comment: ['&& denotes a mnemonic'] }, "A&&uto Save") + title: nls.localize({ key: 'miAutoSave', comment: ['&& denotes a mnemonic'] }, "A&&uto Save"), + toggled: ContextKeyExpr.notEquals('config.files.autoSave', 'off') }, order: 1 }); From ab8bc96039222acfb2b8d35727ef1b0bb577136a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 8 Oct 2018 11:03:00 -0700 Subject: [PATCH 29/76] Stabilize active terminal APIs Fixes #58357 --- src/vs/vscode.d.ts | 13 +++++++++++++ src/vs/vscode.proposed.d.ts | 13 ------------- src/vs/workbench/api/node/extHost.api.impl.ts | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 13b07a2fc06..1acd83a8262 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5920,6 +5920,19 @@ declare module 'vscode' { */ export const terminals: ReadonlyArray; + /** + * The currently active terminal or `undefined`. The active terminal is the one that + * currently has focus or most recently had focus. + */ + export const activeTerminal: Terminal | undefined; + + /** + * An [event](#Event) which fires when the [active terminal](#window.activeTerminal) + * has changed. *Note* that the event also fires when the active terminal changes + * to `undefined`. + */ + export const onDidChangeActiveTerminal: Event; + /** * An [event](#Event) which fires when a terminal has been created, either through the * [createTerminal](#window.createTerminal) API or commands. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index c16a02dd272..18714234e9d 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -995,19 +995,6 @@ declare module 'vscode' { } export namespace window { - /** - * The currently active terminal or `undefined`. The active terminal is the one that - * currently has focus or most recently had focus. - */ - export const activeTerminal: Terminal | undefined; - - /** - * An [event](#Event) which fires when the [active terminal](#window.activeTerminal) - * has changed. *Note* that the event also fires when the active terminal changes - * to `undefined`. - */ - export const onDidChangeActiveTerminal: Event; - /** * Create a [TerminalRenderer](#TerminalRenderer). * diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index a4ba38dd2ae..f625545fdf4 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -354,7 +354,7 @@ export function createApiFactory( return extHostEditors.getVisibleTextEditors(); }, get activeTerminal() { - return proposedApiFunction(extension, extHostTerminalService.activeTerminal); + return extHostTerminalService.activeTerminal; }, get terminals() { return extHostTerminalService.terminals; @@ -397,9 +397,9 @@ export function createApiFactory( onDidOpenTerminal(listener, thisArg?, disposables?) { return extHostTerminalService.onDidOpenTerminal(listener, thisArg, disposables); }, - onDidChangeActiveTerminal: proposedApiFunction(extension, (listener, thisArg?, disposables?) => { + onDidChangeActiveTerminal(listener, thisArg?, disposables?) { return extHostTerminalService.onDidChangeActiveTerminal(listener, thisArg, disposables); - }), + }, get state() { return extHostWindow.state; }, From 09afa054eed0b027639f98a7434c20c78cc170a2 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Mon, 8 Oct 2018 11:24:42 -0700 Subject: [PATCH 30/76] fix undo, redo, selectAll on macOS (#60040) --- .../platform/menubar/electron-main/menubar.ts | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 1a518e18a0f..840ec4d0659 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -25,6 +25,11 @@ import { IStateService } from 'vs/platform/state/common/state'; const telemetryFrom = 'menu'; +interface IMenuItemClickHandler { + inDevTools: (contents: Electron.WebContents) => void; + inNoWindow: () => void; +} + export class Menubar { private static readonly MAX_MENU_RECENT_ENTRIES = 10; @@ -634,8 +639,8 @@ export class Menubar { commandId = arg2[0]; } - // Add role for special case menu items if (isMacintosh) { + // Add role for special case menu items if (commandId === 'editor.action.clipboardCutAction') { options['role'] = 'cut'; } else if (commandId === 'editor.action.clipboardCopyAction') { @@ -643,11 +648,47 @@ export class Menubar { } else if (commandId === 'editor.action.clipboardPasteAction') { options['role'] = 'paste'; } + + // Add context aware click handlers for special case menu items + if (commandId === 'undo') { + options.click = this.makeContextAwareClickHandler(click, { + inDevTools: devTools => devTools.undo(), + inNoWindow: () => Menu.sendActionToFirstResponder('undo:') + }); + } else if (commandId === 'redo') { + options.click = this.makeContextAwareClickHandler(click, { + inDevTools: devTools => devTools.redo(), + inNoWindow: () => Menu.sendActionToFirstResponder('redo:') + }); + } else if (commandId === 'editor.action.selectAll') { + options.click = this.makeContextAwareClickHandler(click, { + inDevTools: devTools => devTools.selectAll(), + inNoWindow: () => Menu.sendActionToFirstResponder('selectAll:') + }); + } } return new MenuItem(this.withKeybinding(commandId, options)); } + private makeContextAwareClickHandler(click: () => void, contextSpecificHandlers: IMenuItemClickHandler): () => void { + return () => { + // No Active Window + const activeWindow = this.windowsMainService.getFocusedWindow(); + if (!activeWindow) { + return contextSpecificHandlers.inNoWindow(); + } + + // DevTools focused + if (activeWindow.win.webContents.isDevToolsFocused()) { + return contextSpecificHandlers.inDevTools(activeWindow.win.webContents.devToolsWebContents); + } + + // Finally execute command in Window + click(); + }; + } + private runActionInRenderer(id: string): void { // We make sure to not run actions when the window has no focus, this helps // for https://github.com/Microsoft/vscode/issues/25907 and specifically for From 5f5488ce75a4d29024521217cbc494be5e9f3745 Mon Sep 17 00:00:00 2001 From: Marcus Farkas Date: Mon, 8 Oct 2018 22:13:11 +0200 Subject: [PATCH 31/76] Consider "search.useReplacePreview" setting in ReplaceAction --- src/vs/workbench/parts/search/browser/searchActions.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index d0d3026d3d8..6921c98e215 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -18,7 +18,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { ICommandHandler } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ISearchHistoryService, VIEW_ID } from 'vs/platform/search/common/search'; +import { ISearchHistoryService, VIEW_ID, ISearchConfiguration } from 'vs/platform/search/common/search'; import { SearchView } from 'vs/workbench/parts/search/browser/searchView'; import * as Constants from 'vs/workbench/parts/search/common/constants'; import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; @@ -28,6 +28,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { normalize } from 'vs/base/common/paths'; import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export function isSearchViewFocused(viewletService: IViewletService, panelService: IPanelService): boolean { let searchView = getSearchView(viewletService, panelService); @@ -561,7 +562,8 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { constructor(private viewer: ITree, private element: Match, private viewlet: SearchView, @IReplaceService private replaceService: IReplaceService, @IKeybindingService keyBindingService: IKeybindingService, - @IEditorService private editorService: IEditorService) { + @IEditorService private editorService: IEditorService, + @IConfigurationService private configurationService: IConfigurationService) { super(Constants.ReplaceActionId, appendKeyBindingLabel(ReplaceAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceActionId), keyBindingService), 'action-replace'); } @@ -575,7 +577,9 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } let elementToShowReplacePreview = this.getElementToShowReplacePreview(elementToFocus); this.viewer.domFocus(); - if (!elementToShowReplacePreview || this.hasToOpenFile()) { + + const useReplacePreview = this.configurationService.getValue().search.useReplacePreview; + if (!useReplacePreview || !elementToShowReplacePreview || this.hasToOpenFile()) { this.viewlet.open(this.element, true); } else { this.replaceService.openReplacePreview(elementToShowReplacePreview, true); From f516d17267d9349e71dc744f8e1799fc5e40ff56 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 15:17:56 -0700 Subject: [PATCH 32/76] Add support for TS RenameTextSpan Fixes #60204 --- .../src/features/rename.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/extensions/typescript-language-features/src/features/rename.ts b/extensions/typescript-language-features/src/features/rename.ts index 3547b15d508..683869054ab 100644 --- a/extensions/typescript-language-features/src/features/rename.ts +++ b/extensions/typescript-language-features/src/features/rename.ts @@ -11,6 +11,13 @@ import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import API from '../utils/api'; import * as typeConverters from '../utils/typeConverters'; +// TODO: Remove when we pick up TS 3.2 +declare module '../protocol' { + interface RenameTextSpan extends TextSpan { + readonly prefixText?: string; + readonly suffixText?: string; + } +} const localize = nls.loadMessageBundle(); @@ -102,8 +109,9 @@ class TypeScriptRenameProvider implements vscode.RenameProvider { for (const spanGroup of locations) { const resource = this.client.toResource(spanGroup.file); if (resource) { - for (const textSpan of spanGroup.locs) { - edit.replace(resource, typeConverters.Range.fromTextSpan(textSpan), newName); + for (const textSpan of spanGroup.locs as Proto.RenameTextSpan[]) { + edit.replace(resource, typeConverters.Range.fromTextSpan(textSpan), + (textSpan.prefixText || '') + newName + (textSpan.suffixText || '')); } } } From 0cfe8a1d7e7ce60a906ff5efdebb0c85915f8fec Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 15:24:11 -0700 Subject: [PATCH 33/76] Fix potential TSC error --- extensions/typescript-language-features/src/features/rename.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/features/rename.ts b/extensions/typescript-language-features/src/features/rename.ts index 683869054ab..8d0ceeeff77 100644 --- a/extensions/typescript-language-features/src/features/rename.ts +++ b/extensions/typescript-language-features/src/features/rename.ts @@ -13,7 +13,7 @@ import * as typeConverters from '../utils/typeConverters'; // TODO: Remove when we pick up TS 3.2 declare module '../protocol' { - interface RenameTextSpan extends TextSpan { + interface RenameTextSpan extends Proto.TextSpan { readonly prefixText?: string; readonly suffixText?: string; } From 7d95e3e5f9ff8b3be98e3c43e06078a7489558b1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 15:51:29 -0700 Subject: [PATCH 34/76] Support markdown link navigation when duplicate slugs exist Fixes #59711 For a md document: ```md # a # a - [a](#a) - [next a](#a-1) ``` You can now click on the second link in the editor to navigate to the second `a` header. It is identified by being suffixed with `-1`. --- .../src/tableOfContentsProvider.ts | 14 ++++++++++++- .../src/test/tableOfContentsProvider.test.ts | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/extensions/markdown-language-features/src/tableOfContentsProvider.ts b/extensions/markdown-language-features/src/tableOfContentsProvider.ts index 944fc750734..bbb30b7cea6 100644 --- a/extensions/markdown-language-features/src/tableOfContentsProvider.ts +++ b/extensions/markdown-language-features/src/tableOfContentsProvider.ts @@ -51,11 +51,23 @@ export class TableOfContentsProvider { const toc: TocEntry[] = []; const tokens = await this.engine.parse(document.uri, document.getText()); + const slugCount = new Map(); + for (const heading of tokens.filter(token => token.type === 'heading_open')) { const lineNumber = heading.map[0]; const line = document.lineAt(lineNumber); + + let slug = githubSlugifier.fromHeading(line.text); + if (slugCount.has(slug.value)) { + const count = slugCount.get(slug.value)!; + slugCount.set(slug.value, count + 1); + slug = githubSlugifier.fromHeading(slug.value + '-' + (count + 1)); + } else { + slugCount.set(slug.value, 0); + } + toc.push({ - slug: githubSlugifier.fromHeading(line.text), + slug, text: TableOfContentsProvider.getHeaderText(line.text), level: TableOfContentsProvider.getHeaderLevel(heading.markup), line: lineNumber, diff --git a/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts index ee103b294ca..91e12f278a5 100644 --- a/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts +++ b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts @@ -106,4 +106,25 @@ suite('markdown.TableOfContentsProvider', () => { assert.strictEqual((await provider.lookup('Заголовок-header-3'))!.line, 4); assert.strictEqual((await provider.lookup('Заголовок'))!.line, 5); }); + + test('Lookup should support suffixes for repeated headers', async () => { + const doc = new InMemoryDocument(testFileName, `# a\n# a\n## a`); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); + + { + const entry = await provider.lookup('a'); + assert.ok(entry); + assert.strictEqual(entry!.line, 0); + } + { + const entry = await provider.lookup('a-1'); + assert.ok(entry); + assert.strictEqual(entry!.line, 1); + } + { + const entry = await provider.lookup('a-2'); + assert.ok(entry); + assert.strictEqual(entry!.line, 2); + } + }); }); From 9e017425b3d38cfc2d31a7375a28ff6d833ea4ae Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 8 Oct 2018 16:04:47 -0700 Subject: [PATCH 35/76] Replace markdown-named-headers with custom version Fixes #47537 Use our own version of markdown named headers. This fixes some bugs around handling duplicate headers --- .../markdown-language-features/package.json | 1 - .../src/markdownEngine.ts | 35 ++++++++++++++++--- .../markdown-language-features/yarn.lock | 12 ------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index ee9484ad6c9..dc1a07ae6b0 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -308,7 +308,6 @@ "dependencies": { "highlight.js": "9.12.0", "markdown-it": "^8.4.1", - "markdown-it-named-headers": "0.0.4", "vscode-extension-telemetry": "0.0.22", "vscode-nls": "^4.0.0" }, diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index 909bc760c2f..085b1a5e2eb 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -17,8 +17,8 @@ export class MarkdownEngine { private md?: MarkdownIt; private firstLine?: number; - private currentDocument?: vscode.Uri; + private _slugCount = new Map(); public constructor( private readonly extensionPreviewResourceProvider: MarkdownContributions, @@ -36,7 +36,6 @@ export class MarkdownEngine { private async getEngine(resource: vscode.Uri): Promise { if (!this.md) { const hljs = await import('highlight.js'); - const mdnh = await import('markdown-it-named-headers'); this.md = (await import('markdown-it'))({ html: true, highlight: (str: string, lang?: string) => { @@ -54,8 +53,6 @@ export class MarkdownEngine { } return `
${this.md!.utils.escapeHtml(str)}
`; } - }).use(mdnh, { - slugify: (header: string) => this.slugifier.fromHeading(header).value }); for (const plugin of this.extensionPreviewResourceProvider.markdownItPlugins) { @@ -71,6 +68,7 @@ export class MarkdownEngine { this.addLinkNormalizer(this.md); this.addLinkValidator(this.md); + this.addNamedHeaders(this.md); } const config = vscode.workspace.getConfiguration('markdown', resource); @@ -101,6 +99,8 @@ export class MarkdownEngine { } this.currentDocument = document; this.firstLine = offset; + this._slugCount = new Map(); + const engine = await this.getEngine(document); return engine.render(text); } @@ -108,6 +108,8 @@ export class MarkdownEngine { public async parse(document: vscode.Uri, source: string): Promise { const { text, offset } = this.stripFrontmatter(source); this.currentDocument = document; + this._slugCount = new Map(); + const engine = await this.getEngine(document); return engine.parse(text, {}).map(token => { @@ -219,4 +221,29 @@ export class MarkdownEngine { return validateLink(link) || link.indexOf('file:') === 0; }; } + + private addNamedHeaders(md: any): void { + const original = md.renderer.rules.heading_open; + md.renderer.rules.heading_open = (tokens: any, idx: number, options: any, env: any, self: any) => { + const title = tokens[idx + 1].children.reduce((acc: string, t: any) => acc + t.content, ''); + let slug = this.slugifier.fromHeading(title); + + if (this._slugCount.has(slug.value)) { + const count = this._slugCount.get(slug.value)!; + this._slugCount.set(slug.value, count + 1); + slug = this.slugifier.fromHeading(slug.value + '-' + (count + 1)); + } else { + this._slugCount.set(slug.value, 0); + } + + tokens[idx].attrs = tokens[idx].attrs || []; + tokens[idx].attrs.push(['id', slug.value]); + + if (original) { + return original(tokens, idx, options, env, self); + } else { + return self.renderToken(tokens, idx, options, env, self); + } + }; + } } \ No newline at end of file diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 2ee630f88b9..e95b79f5238 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -3895,13 +3895,6 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -markdown-it-named-headers@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/markdown-it-named-headers/-/markdown-it-named-headers-0.0.4.tgz#82efc28324240a6b1e77b9aae501771d5f351c1f" - integrity sha1-gu/CgyQkCmsed7mq5QF3HV81HB8= - dependencies: - string "^3.0.1" - markdown-it@^8.4.1: version "8.4.1" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.1.tgz#206fe59b0e4e1b78a7c73250af9b34a4ad0aaf44" @@ -5711,11 +5704,6 @@ string-width@^2.0.0, string-width@^2.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string@^3.0.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/string/-/string-3.3.1.tgz#8d2757ec1c0e6c526796fbb6b14036a4098398b7" - integrity sha1-jSdX7BwObFJnlvu2sUA2pAmDmLc= - string_decoder@^1.0.0, string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" From c1100eff93b35dc220ce63e2ed0d5ace54259795 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 08:34:50 +0200 Subject: [PATCH 36/76] disable cached data for extensions #60168 --- .../services/extensions/electron-browser/extensionHost.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 98612acf46d..bab147b26dc 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -177,7 +177,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { VSCODE_IPC_HOOK_EXTHOST: pipeName, VSCODE_HANDLES_UNCAUGHT_ERRORS: true, VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || product.quality !== 'stable' || this._environmentService.verbose), - VSCODE_LOG_LEVEL: this._environmentService.verbose ? 'trace' : this._environmentService.log + VSCODE_LOG_LEVEL: this._environmentService.verbose ? 'trace' : this._environmentService.log, + VSCODE_NODE_CACHED_DATA_DIR: '' }), // We only detach the extension host on windows. Linux and Mac orphan by default // and detach under Linux and Mac create another process group. From 6daba7710a7bbb5fc9f2b246d42949688de71f52 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 9 Oct 2018 09:23:24 +0200 Subject: [PATCH 37/76] Migrate to native Promise in web worker related code (#53526) --- src/vs/base/common/worker/simpleWorker.ts | 83 +++++++++---------- .../common/services/editorSimpleWorker.ts | 47 +++++------ .../common/services/editorWorkerService.ts | 11 ++- .../services/editorWorkerServiceImpl.ts | 49 ++++++----- src/vs/editor/common/services/webWorker.ts | 17 ++-- .../parts/output/common/outputLinkComputer.ts | 4 +- .../parts/output/common/outputLinkProvider.ts | 3 +- 7 files changed, 104 insertions(+), 110 deletions(-) diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index 7f9293c5927..c55e76ee6f1 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -5,7 +5,6 @@ import { transformErrorForSerialization } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ErrorCallback, TPromise, ValueCallback } from 'vs/base/common/winjs.base'; import { isWeb } from 'vs/base/common/platform'; const INITIALIZE = '$initialize'; @@ -56,13 +55,13 @@ interface IReplyMessage extends IMessage { } interface IMessageReply { - c: ValueCallback; - e: ErrorCallback; + resolve: (value?: any) => void; + reject: (error?: any) => void; } interface IMessageHandler { sendMessage(msg: string): void; - handleMessage(method: string, args: any[]): TPromise; + handleMessage(method: string, args: any[]): Promise; } class SimpleWorkerProtocol { @@ -83,15 +82,15 @@ class SimpleWorkerProtocol { this._workerId = workerId; } - public sendMessage(method: string, args: any[]): TPromise { + public sendMessage(method: string, args: any[]): Promise { let req = String(++this._lastSentReq); let reply: IMessageReply = { - c: null, - e: null + resolve: null, + reject: null }; - let result = new TPromise((c, e) => { - reply.c = c; - reply.e = e; + let result = new Promise((resolve, reject) => { + reply.resolve = resolve; + reply.reject = reject; }); this._pendingReplies[req] = reply; @@ -140,11 +139,11 @@ class SimpleWorkerProtocol { err.message = replyMessage.err.message; err.stack = replyMessage.err.stack; } - reply.e(err); + reply.reject(err); return; } - reply.c(replyMessage.res); + reply.resolve(replyMessage.res); return; } @@ -185,14 +184,14 @@ class SimpleWorkerProtocol { export class SimpleWorkerClient extends Disposable { private _worker: IWorker; - private _onModuleLoaded: TPromise; + private _onModuleLoaded: Promise; private _protocol: SimpleWorkerProtocol; - private _lazyProxy: TPromise; + private _lazyProxy: Promise; constructor(workerFactory: IWorkerFactory, moduleId: string) { super(); - let lazyProxyFulfill: (v: T) => void = null; + let lazyProxyResolve: (v: T) => void = null; let lazyProxyReject: (err: any) => void = null; this._worker = this._register(workerFactory.create( @@ -211,9 +210,9 @@ export class SimpleWorkerClient extends Disposable { sendMessage: (msg: string): void => { this._worker.postMessage(msg); }, - handleMessage: (method: string, args: any[]): TPromise => { + handleMessage: (method: string, args: any[]): Promise => { // Intentionally not supporting worker -> main requests - return TPromise.as(null); + return Promise.resolve(null); } }); this._protocol.setWorkerId(this._worker.getId()); @@ -228,9 +227,9 @@ export class SimpleWorkerClient extends Disposable { loaderConfiguration = (self).requirejs.s.contexts._.config; } - this._lazyProxy = new TPromise((c, e) => { - lazyProxyFulfill = c; - lazyProxyReject = e; + this._lazyProxy = new Promise((resolve, reject) => { + lazyProxyResolve = resolve; + lazyProxyReject = reject; }); // Send initialize message @@ -244,18 +243,18 @@ export class SimpleWorkerClient extends Disposable { for (let i = 0; i < availableMethods.length; i++) { (proxy as any)[availableMethods[i]] = createProxyMethod(availableMethods[i], proxyMethodRequest); } - lazyProxyFulfill(proxy); + lazyProxyResolve(proxy); }, (e) => { lazyProxyReject(e); this._onError('Worker failed to load ' + moduleId, e); }); // Create proxy to loaded code - let proxyMethodRequest = (method: string, args: any[]): TPromise => { + let proxyMethodRequest = (method: string, args: any[]): Promise => { return this._request(method, args); }; - let createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => TPromise): Function => { + let createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise): Function => { return function () { let args = Array.prototype.slice.call(arguments, 0); return proxyMethodRequest(method, args); @@ -263,15 +262,15 @@ export class SimpleWorkerClient extends Disposable { }; } - public getProxyObject(): TPromise { + public getProxyObject(): Promise { return this._lazyProxy; } - private _request(method: string, args: any[]): TPromise { - return new TPromise((c, e) => { + private _request(method: string, args: any[]): Promise { + return new Promise((resolve, reject) => { this._onModuleLoaded.then(() => { - this._protocol.sendMessage(method, args).then(c, e); - }, e); + this._protocol.sendMessage(method, args).then(resolve, reject); + }, reject); }); } @@ -300,7 +299,7 @@ export class SimpleWorkerServer { sendMessage: (msg: string): void => { postSerializedMessage(msg); }, - handleMessage: (method: string, args: any[]): TPromise => this._handleMessage(method, args) + handleMessage: (method: string, args: any[]): Promise => this._handleMessage(method, args) }); } @@ -308,23 +307,23 @@ export class SimpleWorkerServer { this._protocol.handleMessage(msg); } - private _handleMessage(method: string, args: any[]): TPromise { + private _handleMessage(method: string, args: any[]): Promise { if (method === INITIALIZE) { return this.initialize(args[0], args[1], args[2]); } if (!this._requestHandler || typeof this._requestHandler[method] !== 'function') { - return TPromise.wrapError(new Error('Missing requestHandler or method: ' + method)); + return Promise.reject(new Error('Missing requestHandler or method: ' + method)); } try { - return TPromise.as(this._requestHandler[method].apply(this._requestHandler, args)); + return Promise.resolve(this._requestHandler[method].apply(this._requestHandler, args)); } catch (e) { - return TPromise.wrapError(e); + return Promise.reject(e); } } - private initialize(workerId: number, moduleId: string, loaderConfig: any): TPromise { + private initialize(workerId: number, moduleId: string, loaderConfig: any): Promise { this._protocol.setWorkerId(workerId); if (this._requestHandler) { @@ -335,7 +334,7 @@ export class SimpleWorkerServer { methods.push(prop); } } - return TPromise.as(methods); + return Promise.resolve(methods); } if (loaderConfig) { @@ -354,11 +353,11 @@ export class SimpleWorkerServer { (self).require.config(loaderConfig); } - let cc: ValueCallback; - let ee: ErrorCallback; - let r = new TPromise((c, e) => { - cc = c; - ee = e; + let resolve: (value?: string[]) => void; + let reject: (error?: any) => void; + let r = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; }); // Use the global require to be sure to get the global config @@ -373,8 +372,8 @@ export class SimpleWorkerServer { } } - cc(methods); - }, ee); + resolve(methods); + }, reject); return r; } diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index 4f7ec3433c3..c38a201b8b8 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IRequestHandler } from 'vs/base/common/worker/simpleWorker'; import { Range, IRange } from 'vs/editor/common/core/range'; @@ -336,7 +335,7 @@ export abstract class BaseEditorSimpleWorker { // ---- BEGIN diff -------------------------------------------------------------------------- - public computeDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): TPromise { + public computeDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): Promise { let original = this._getModel(originalUrl); let modified = this._getModel(modifiedUrl); if (!original || !modified) { @@ -351,10 +350,10 @@ export abstract class BaseEditorSimpleWorker { shouldIgnoreTrimWhitespace: ignoreTrimWhitespace, shouldMakePrettyDiff: true }); - return TPromise.as(diffComputer.computeDiff()); + return Promise.resolve(diffComputer.computeDiff()); } - public computeDirtyDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): TPromise { + public computeDirtyDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): Promise { let original = this._getModel(originalUrl); let modified = this._getModel(modifiedUrl); if (!original || !modified) { @@ -369,7 +368,7 @@ export abstract class BaseEditorSimpleWorker { shouldIgnoreTrimWhitespace: ignoreTrimWhitespace, shouldMakePrettyDiff: true }); - return TPromise.as(diffComputer.computeDiff()); + return Promise.resolve(diffComputer.computeDiff()); } // ---- END diff -------------------------------------------------------------------------- @@ -379,10 +378,10 @@ export abstract class BaseEditorSimpleWorker { private static readonly _diffLimit = 10000; - public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): TPromise { + public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise { const model = this._getModel(modelUrl); if (!model) { - return TPromise.as(edits); + return Promise.resolve(edits); } const result: TextEdit[] = []; @@ -437,25 +436,25 @@ export abstract class BaseEditorSimpleWorker { result.push({ eol: lastEol, text: undefined, range: undefined }); } - return TPromise.as(result); + return Promise.resolve(result); } // ---- END minimal edits --------------------------------------------------------------- - public computeLinks(modelUrl: string): TPromise { + public computeLinks(modelUrl: string): Promise { let model = this._getModel(modelUrl); if (!model) { return null; } - return TPromise.as(computeLinks(model)); + return Promise.resolve(computeLinks(model)); } // ---- BEGIN suggest -------------------------------------------------------------------------- private static readonly _suggestionsLimit = 10000; - public textualSuggest(modelUrl: string, position: IPosition, wordDef: string, wordDefFlags: string): TPromise { + public textualSuggest(modelUrl: string, position: IPosition, wordDef: string, wordDefFlags: string): Promise { const model = this._getModel(modelUrl); if (model) { const suggestions: CompletionItem[] = []; @@ -488,7 +487,7 @@ export abstract class BaseEditorSimpleWorker { }); } - return TPromise.as({ suggestions }); + return Promise.resolve({ suggestions }); } return undefined; } @@ -529,7 +528,7 @@ export abstract class BaseEditorSimpleWorker { //#endregion - public navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): TPromise { + public navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): Promise { let model = this._getModel(modelUrl); if (!model) { return null; @@ -555,12 +554,12 @@ export abstract class BaseEditorSimpleWorker { } let result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up); - return TPromise.as(result); + return Promise.resolve(result); } // ---- BEGIN foreign module support -------------------------------------------------------------------------- - public loadForeignModule(moduleId: string, createData: any): TPromise { + public loadForeignModule(moduleId: string, createData: any): Promise { let ctx: IWorkerContext = { getMirrorModels: (): IMirrorModel[] => { return this._getModels(); @@ -576,10 +575,10 @@ export abstract class BaseEditorSimpleWorker { methods.push(prop); } } - return TPromise.as(methods); + return Promise.resolve(methods); } // ESM-comment-begin - return new TPromise((c, e) => { + return new Promise((resolve, reject) => { require([moduleId], (foreignModule: { create: IForeignModuleFactory }) => { this._foreignModule = foreignModule.create(ctx, createData); @@ -590,27 +589,27 @@ export abstract class BaseEditorSimpleWorker { } } - c(methods); + resolve(methods); - }, e); + }, reject); }); // ESM-comment-end // ESM-uncomment-begin - // return TPromise.wrapError(new Error(`Unexpected usage`)); + // return Promise.reject(new Error(`Unexpected usage`)); // ESM-uncomment-end } // foreign method request - public fmr(method: string, args: any[]): TPromise { + public fmr(method: string, args: any[]): Promise { if (!this._foreignModule || typeof this._foreignModule[method] !== 'function') { - return TPromise.wrapError(new Error('Missing requestHandler or method: ' + method)); + return Promise.reject(new Error('Missing requestHandler or method: ' + method)); } try { - return TPromise.as(this._foreignModule[method].apply(this._foreignModule, args)); + return Promise.resolve(this._foreignModule[method].apply(this._foreignModule, args)); } catch (e) { - return TPromise.wrapError(e); + return Promise.reject(e); } } diff --git a/src/vs/editor/common/services/editorWorkerService.ts b/src/vs/editor/common/services/editorWorkerService.ts index 5d96d912bda..ff2fa9eb212 100644 --- a/src/vs/editor/common/services/editorWorkerService.ts +++ b/src/vs/editor/common/services/editorWorkerService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IChange, ILineChange } from 'vs/editor/common/editorCommon'; import { IInplaceReplaceSupportResult, TextEdit } from 'vs/editor/common/modes'; @@ -17,16 +16,16 @@ export interface IEditorWorkerService { _serviceBrand: any; canComputeDiff(original: URI, modified: URI): boolean; - computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise; + computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise; canComputeDirtyDiff(original: URI, modified: URI): boolean; - computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise; + computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise; - computeMoreMinimalEdits(resource: URI, edits: TextEdit[]): TPromise; + computeMoreMinimalEdits(resource: URI, edits: TextEdit[]): Promise; canComputeWordRanges(resource: URI): boolean; - computeWordRanges(resource: URI, range: IRange): TPromise<{ [word: string]: IRange[] }>; + computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] }>; canNavigateValueSet(resource: URI): boolean; - navigateValueSet(resource: URI, range: IRange, up: boolean): TPromise; + navigateValueSet(resource: URI, range: IRange, up: boolean): Promise; } diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index 8b14e5e2412..db899de6fdb 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -6,7 +6,6 @@ import { IntervalTimer } from 'vs/base/common/async'; import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; import { SimpleWorkerClient, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker'; import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -60,7 +59,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker this._register(modes.LinkProviderRegistry.register('*', { provideLinks: (model, token) => { if (!canSyncModel(this._modelService, model.uri)) { - return TPromise.as([]); // File too large + return Promise.resolve([]); // File too large } return this._workerManager.withWorker().then(client => client.computeLinks(model.uri)); } @@ -76,7 +75,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker return (canSyncModel(this._modelService, original) && canSyncModel(this._modelService, modified)); } - public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise { + public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise { return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, ignoreTrimWhitespace)); } @@ -84,16 +83,16 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker return (canSyncModel(this._modelService, original) && canSyncModel(this._modelService, modified)); } - public computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise { + public computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise { return this._workerManager.withWorker().then(client => client.computeDirtyDiff(original, modified, ignoreTrimWhitespace)); } - public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): TPromise { + public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): Promise { if (!Array.isArray(edits) || edits.length === 0) { - return TPromise.as(edits); + return Promise.resolve(edits); } else { if (!canSyncModel(this._modelService, resource)) { - return TPromise.as(edits); // File too large + return Promise.resolve(edits); // File too large } return this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits)); } @@ -103,7 +102,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker return (canSyncModel(this._modelService, resource)); } - public navigateValueSet(resource: URI, range: IRange, up: boolean): TPromise { + public navigateValueSet(resource: URI, range: IRange, up: boolean): Promise { return this._workerManager.withWorker().then(client => client.navigateValueSet(resource, range, up)); } @@ -111,7 +110,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker return canSyncModel(this._modelService, resource); } - computeWordRanges(resource: URI, range: IRange): TPromise<{ [word: string]: IRange[] }> { + computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] }> { return this._workerManager.withWorker().then(client => client.computeWordRanges(resource, range)); } } @@ -132,7 +131,7 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { this._modelService = modelService; } - provideCompletionItems(model: ITextModel, position: Position): TPromise { + provideCompletionItems(model: ITextModel, position: Position): Promise { const { wordBasedSuggestions } = this._configurationService.getValue(model.uri, position, 'editor'); if (!wordBasedSuggestions) { return undefined; @@ -200,12 +199,12 @@ class WorkerManager extends Disposable { } } - public withWorker(): TPromise { + public withWorker(): Promise { this._lastWorkerUsedTime = (new Date()).getTime(); if (!this._editorWorkerClient) { this._editorWorkerClient = new EditorWorkerClient(this._modelService, 'editorWorkerService'); } - return TPromise.as(this._editorWorkerClient); + return Promise.resolve(this._editorWorkerClient); } } @@ -308,17 +307,17 @@ class EditorModelManager extends Disposable { } interface IWorkerClient { - getProxyObject(): TPromise; + getProxyObject(): Promise; dispose(): void; } class SynchronousWorkerClient implements IWorkerClient { private _instance: T; - private _proxyObj: TPromise; + private _proxyObj: Promise; constructor(instance: T) { this._instance = instance; - this._proxyObj = TPromise.as(this._instance); + this._proxyObj = Promise.resolve(this._instance); } public dispose(): void { @@ -327,7 +326,7 @@ class SynchronousWorkerClient implements IWorkerClient this._proxyObj = null; } - public getProxyObject(): TPromise { + public getProxyObject(): Promise { return this._proxyObj; } } @@ -362,7 +361,7 @@ export class EditorWorkerClient extends Disposable { return this._worker; } - protected _getProxy(): TPromise { + protected _getProxy(): Promise { return this._getOrCreateWorker().getProxyObject().then(null, (err) => { logOnceWebWorkerWarning(err); this._worker = new SynchronousWorkerClient(new EditorSimpleWorkerImpl(null)); @@ -377,38 +376,38 @@ export class EditorWorkerClient extends Disposable { return this._modelManager; } - protected _withSyncedResources(resources: URI[]): TPromise { + protected _withSyncedResources(resources: URI[]): Promise { return this._getProxy().then((proxy) => { this._getOrCreateModelManager(proxy).esureSyncedResources(resources); return proxy; }); } - public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise { + public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise { return this._withSyncedResources([original, modified]).then(proxy => { return proxy.computeDiff(original.toString(), modified.toString(), ignoreTrimWhitespace); }); } - public computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise { + public computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise { return this._withSyncedResources([original, modified]).then(proxy => { return proxy.computeDirtyDiff(original.toString(), modified.toString(), ignoreTrimWhitespace); }); } - public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): TPromise { + public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): Promise { return this._withSyncedResources([resource]).then(proxy => { return proxy.computeMoreMinimalEdits(resource.toString(), edits); }); } - public computeLinks(resource: URI): TPromise { + public computeLinks(resource: URI): Promise { return this._withSyncedResources([resource]).then(proxy => { return proxy.computeLinks(resource.toString()); }); } - public textualSuggest(resource: URI, position: IPosition): TPromise { + public textualSuggest(resource: URI, position: IPosition): Promise { return this._withSyncedResources([resource]).then(proxy => { let model = this._modelService.getModel(resource); if (!model) { @@ -421,7 +420,7 @@ export class EditorWorkerClient extends Disposable { }); } - computeWordRanges(resource: URI, range: IRange): TPromise<{ [word: string]: IRange[] }> { + computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] }> { return this._withSyncedResources([resource]).then(proxy => { let model = this._modelService.getModel(resource); if (!model) { @@ -434,7 +433,7 @@ export class EditorWorkerClient extends Disposable { }); } - public navigateValueSet(resource: URI, range: IRange, up: boolean): TPromise { + public navigateValueSet(resource: URI, range: IRange, up: boolean): Promise { return this._withSyncedResources([resource]).then(proxy => { let model = this._modelService.getModel(resource); if (!model) { diff --git a/src/vs/editor/common/services/webWorker.ts b/src/vs/editor/common/services/webWorker.ts index 9646331f279..f0c97ae56a4 100644 --- a/src/vs/editor/common/services/webWorker.ts +++ b/src/vs/editor/common/services/webWorker.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IModelService } from 'vs/editor/common/services/modelService'; import { EditorWorkerClient } from 'vs/editor/common/services/editorWorkerServiceImpl'; @@ -27,12 +26,12 @@ export interface MonacoWebWorker { /** * Get a proxy to the arbitrary loaded code. */ - getProxy(): TPromise; + getProxy(): Promise; /** * Synchronize (send) the models at `resources` to the web worker, * making them available in the monaco.worker.getMirrorModels(). */ - withSyncedResources(resources: URI[]): TPromise; + withSyncedResources(resources: URI[]): Promise; } export interface IWebWorkerOptions { @@ -55,7 +54,7 @@ class MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWork private _foreignModuleId: string; private _foreignModuleCreateData: any; - private _foreignProxy: TPromise; + private _foreignProxy: Promise; constructor(modelService: IModelService, opts: IWebWorkerOptions) { super(modelService, opts.label); @@ -64,18 +63,18 @@ class MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWork this._foreignProxy = null; } - private _getForeignProxy(): TPromise { + private _getForeignProxy(): Promise { if (!this._foreignProxy) { this._foreignProxy = this._getProxy().then((proxy) => { return proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData).then((foreignMethods) => { this._foreignModuleId = null; this._foreignModuleCreateData = null; - let proxyMethodRequest = (method: string, args: any[]): TPromise => { + let proxyMethodRequest = (method: string, args: any[]): Promise => { return proxy.fmr(method, args); }; - let createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => TPromise): Function => { + let createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise): Function => { return function () { let args = Array.prototype.slice.call(arguments, 0); return proxyMethodRequest(method, args); @@ -94,11 +93,11 @@ class MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWork return this._foreignProxy; } - public getProxy(): TPromise { + public getProxy(): Promise { return this._getForeignProxy(); } - public withSyncedResources(resources: URI[]): TPromise { + public withSyncedResources(resources: URI[]): Promise { return this._withSyncedResources(resources).then(_ => this.getProxy()); } } diff --git a/src/vs/workbench/parts/output/common/outputLinkComputer.ts b/src/vs/workbench/parts/output/common/outputLinkComputer.ts index fa043755526..081ab8a0da7 100644 --- a/src/vs/workbench/parts/output/common/outputLinkComputer.ts +++ b/src/vs/workbench/parts/output/common/outputLinkComputer.ts @@ -55,7 +55,7 @@ export class OutputLinkComputer { return null; } - public computeLinks(uri: string): ILink[] { + public computeLinks(uri: string): Promise { const model = this.getModel(uri); if (!model) { return void 0; @@ -81,7 +81,7 @@ export class OutputLinkComputer { } }); - return links; + return Promise.resolve(links); } public static createPatterns(workspaceFolder: URI): RegExp[] { diff --git a/src/vs/workbench/parts/output/common/outputLinkProvider.ts b/src/vs/workbench/parts/output/common/outputLinkProvider.ts index f9fb24af057..de9ae22b121 100644 --- a/src/vs/workbench/parts/output/common/outputLinkProvider.ts +++ b/src/vs/workbench/parts/output/common/outputLinkProvider.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TPromise } from 'vs/base/common/winjs.base'; import { URI } from 'vs/base/common/uri'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -75,7 +74,7 @@ export class OutputLinkProvider { return this.worker; } - private provideLinks(modelUri: URI): TPromise { + private provideLinks(modelUri: URI): Promise { return this.getOrCreateWorker().withSyncedResources([modelUri]).then(linkComputer => { return linkComputer.computeLinks(modelUri.toString()); }); From fdf2dec52d1bafd37978e8cdf24371af7f49f8e7 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 9 Oct 2018 09:46:54 +0200 Subject: [PATCH 38/76] Remove usage of TPromise from public editor API (#53526) --- build/monaco/api.js | 1 - build/monaco/api.ts | 1 - src/vs/editor/browser/widget/codeEditorWidget.ts | 4 ++-- src/vs/editor/common/editorAction.ts | 11 +++++------ src/vs/editor/common/editorCommon.ts | 3 +-- src/vs/editor/standalone/browser/colorizer.ts | 9 ++++----- .../standalone/browser/quickOpen/quickCommand.ts | 3 +-- .../editor/standalone/browser/standaloneCodeEditor.ts | 8 +++----- src/vs/editor/standalone/browser/standaloneEditor.ts | 4 ++-- .../parts/quickopen/browser/commandsHandler.ts | 2 +- 10 files changed, 19 insertions(+), 27 deletions(-) diff --git a/build/monaco/api.js b/build/monaco/api.js index d4502c97997..f411ab4a566 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -315,7 +315,6 @@ function generateDeclarationFile(out, inputFiles, recipe) { var resultTxt = result.join(endl); resultTxt = resultTxt.replace(/\bURI\b/g, 'Uri'); resultTxt = resultTxt.replace(/\bEvent => { + (): Promise => { return this._instantiationService.invokeFunction((accessor) => { - return action.runEditorCommand(accessor, this, null); + return Promise.resolve(action.runEditorCommand(accessor, this, null)); }); }, this._contextKeyService diff --git a/src/vs/editor/common/editorAction.ts b/src/vs/editor/common/editorAction.ts index b0f8fcbe71a..ce29a961c5d 100644 --- a/src/vs/editor/common/editorAction.ts +++ b/src/vs/editor/common/editorAction.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TPromise } from 'vs/base/common/winjs.base'; import { IEditorAction } from 'vs/editor/common/editorCommon'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -14,7 +13,7 @@ export class InternalEditorAction implements IEditorAction { public readonly alias: string; private readonly _precondition: ContextKeyExpr; - private readonly _run: () => void | TPromise; + private readonly _run: () => Promise; private readonly _contextKeyService: IContextKeyService; constructor( @@ -22,7 +21,7 @@ export class InternalEditorAction implements IEditorAction { label: string, alias: string, precondition: ContextKeyExpr, - run: () => void, + run: () => Promise, contextKeyService: IContextKeyService ) { this.id = id; @@ -37,12 +36,12 @@ export class InternalEditorAction implements IEditorAction { return this._contextKeyService.contextMatchesRules(this._precondition); } - public run(): TPromise { + public run(): Promise { if (!this.isSupported()) { - return TPromise.as(void 0); + return Promise.resolve(void 0); } const r = this._run(); - return r ? r : TPromise.as(void 0); + return r ? r : Promise.resolve(void 0); } } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 5f940755d70..78829d1fe2b 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -5,7 +5,6 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { Range, IRange } from 'vs/editor/common/core/range'; @@ -185,7 +184,7 @@ export interface IEditorAction { readonly label: string; readonly alias: string; isSupported(): boolean; - run(): TPromise; + run(): Promise; } export type IEditorModel = ITextModel | IDiffEditorModel; diff --git a/src/vs/editor/standalone/browser/colorizer.ts b/src/vs/editor/standalone/browser/colorizer.ts index a0c88e7e18f..4e79aaaed50 100644 --- a/src/vs/editor/standalone/browser/colorizer.ts +++ b/src/vs/editor/standalone/browser/colorizer.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable } from 'vs/base/common/lifecycle'; -import { TPromise } from 'vs/base/common/winjs.base'; import { ITextModel } from 'vs/editor/common/model'; import { ColorId, MetadataConsts, FontStyle, TokenizationRegistry, ITokenizationSupport } from 'vs/editor/common/modes'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -26,7 +25,7 @@ export interface IColorizerElementOptions extends IColorizerOptions { export class Colorizer { - public static colorizeElement(themeService: IStandaloneThemeService, modeService: IModeService, domNode: HTMLElement, options: IColorizerElementOptions): TPromise { + public static colorizeElement(themeService: IStandaloneThemeService, modeService: IModeService, domNode: HTMLElement, options: IColorizerElementOptions): Promise { options = options || {}; let theme = options.theme || 'vs'; let mimeType = options.mimeType || domNode.getAttribute('lang') || domNode.getAttribute('data-lang'); @@ -45,7 +44,7 @@ export class Colorizer { return this.colorize(modeService, text, mimeType, options).then(render, (err) => console.error(err)); } - public static colorize(modeService: IModeService, text: string, mimeType: string, options: IColorizerOptions): TPromise { + public static colorize(modeService: IModeService, text: string, mimeType: string, options: IColorizerOptions): Promise { if (strings.startsWithUTF8BOM(text)) { text = text.substr(1); } @@ -62,10 +61,10 @@ export class Colorizer { let tokenizationSupport = TokenizationRegistry.get(language); if (tokenizationSupport) { - return TPromise.as(_colorize(lines, options.tabSize, tokenizationSupport)); + return Promise.resolve(_colorize(lines, options.tabSize, tokenizationSupport)); } - return new TPromise((resolve, reject) => { + return new Promise((resolve, reject) => { let listener: IDisposable = null; let timeout: TimeoutTimer = null; diff --git a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts index b7928bcbab6..b3b30c1b95b 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts @@ -6,7 +6,6 @@ import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; import { matchesFuzzy } from 'vs/base/common/filters'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IContext, IHighlight, QuickOpenEntryGroup, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IAutoFocus, Mode } from 'vs/base/parts/quickopen/common/quickOpen'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -55,7 +54,7 @@ export class EditorActionCommandEntry extends QuickOpenEntryGroup { this.editor.focus(); try { - let promise = this.action.run() || TPromise.as(null); + let promise = this.action.run() || Promise.resolve(); promise.then(null, onUnexpectedError); } catch (error) { onUnexpectedError(error); diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 8e69016587e..0b8eb55f9ab 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands'; @@ -72,7 +71,7 @@ export interface IActionDescriptor { * Method that will be executed when the action is triggered. * @param editor The editor instance is passed in as a convinience */ - run(editor: ICodeEditor): void | TPromise; + run(editor: ICodeEditor): void | Promise; } /** @@ -221,9 +220,8 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon ); const contextMenuGroupId = _descriptor.contextMenuGroupId || null; const contextMenuOrder = _descriptor.contextMenuOrder || 0; - const run = (): TPromise => { - const r = _descriptor.run(this); - return r ? r : TPromise.as(void 0); + const run = (): Promise => { + return Promise.resolve(_descriptor.run(this)); }; diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 2aa953c0596..a85dd145bea 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -240,14 +240,14 @@ export function createWebWorker(opts: IWebWorkerOptions): MonacoWebWorker /** * Colorize the contents of `domNode` using attribute `data-lang`. */ -export function colorizeElement(domNode: HTMLElement, options: IColorizerElementOptions): TPromise { +export function colorizeElement(domNode: HTMLElement, options: IColorizerElementOptions): Promise { return Colorizer.colorizeElement(StaticServices.standaloneThemeService.get(), StaticServices.modeService.get(), domNode, options); } /** * Colorize `text` using language `languageId`. */ -export function colorize(text: string, languageId: string, options: IColorizerOptions): TPromise { +export function colorize(text: string, languageId: string, options: IColorizerOptions): Promise { return Colorizer.colorize(StaticServices.modeService.get(), text, languageId, options); } diff --git a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts index 1c5bff83890..a1c28485cde 100644 --- a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts @@ -304,7 +304,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { } */ this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'quick open' }); - (action.run() || TPromise.as(null)).then(() => { + (action.run() || Promise.resolve()).then(() => { if (action instanceof Action) { action.dispose(); } From fd655a5462265e4216cd9b3d1b6482d1fb33cb3c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 10:20:21 +0200 Subject: [PATCH 39/76] fix breadcrumbs keybinding select issue --- src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 515593ff365..cfe0453ff28 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -323,7 +323,7 @@ export class BreadcrumbsControl { editorViewState = undefined; } this._contextViewService.hideContextView(this); - this._revealInEditor(event, data.target, this._getEditorGroup(data.payload && data.payload.originalEvent), (data.payload && data.payload.originalEvent.middleButton)); + this._revealInEditor(event, data.target, this._getEditorGroup(data.payload && data.payload.originalEvent), (data.payload && data.payload.originalEvent && data.payload.originalEvent.middleButton)); /* __GDPR__ "breadcrumbs/open" : { "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } From 0741911a0f8faf0c0842a17f05f8c6f18f6c5178 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 10:28:25 +0200 Subject: [PATCH 40/76] add test for #60232 --- .../editor/test/common/modes/languageSelector.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/vs/editor/test/common/modes/languageSelector.test.ts b/src/vs/editor/test/common/modes/languageSelector.test.ts index f56c0368c59..8d43170b22c 100644 --- a/src/vs/editor/test/common/modes/languageSelector.test.ts +++ b/src/vs/editor/test/common/modes/languageSelector.test.ts @@ -94,4 +94,14 @@ suite('LanguageSelector', function () { assert.equal(score({ language: 'javascript', scheme: 'file', hasAccessToAllModels: true }, doc.uri, doc.langId, false), 10); assert.equal(score(['fooLang', '*', { language: '*', hasAccessToAllModels: true }], doc.uri, doc.langId, false), 5); }); + + test('Document selector match - unexpected result value #60232', function () { + let selector = { + language: 'json', + scheme: 'file', + pattern: '**/*.interface.json' + }; + let value = score(selector, URI.parse('file:///C:/Users/zlhe/Desktop/test.interface.json'), 'json', true); + assert.equal(value, 10); + }); }); From 711217acc508e70269e4940c1c12403e7578d96d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 10:33:26 +0200 Subject: [PATCH 41/76] debt - less TPromise usage --- src/vs/editor/standalone/browser/quickOpen/quickOutline.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts index c3babe9b43a..f81c9c3801b 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts @@ -7,7 +7,6 @@ import 'vs/css!./quickOutline'; import * as nls from 'vs/nls'; import { matchesFuzzy } from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IContext, IHighlight, QuickOpenEntryGroup, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IAutoFocus, Mode } from 'vs/base/parts/quickopen/common/quickOpen'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -129,7 +128,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): TPromise { + public run(accessor: ServicesAccessor, editor: ICodeEditor): Thenable { let model = editor.getModel(); @@ -138,13 +137,13 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { } // Resolve outline - return TPromise.wrap(getDocumentSymbols(model, true, CancellationToken.None).then((result: DocumentSymbol[]) => { + return getDocumentSymbols(model, true, CancellationToken.None).then((result: DocumentSymbol[]) => { if (result.length === 0) { return; } this._run(editor, result); - })); + }); } private _run(editor: ICodeEditor, result: DocumentSymbol[]): void { From 291f9af1748f5be412f0491b0fcbe9c1b80ac17a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 10:35:13 +0200 Subject: [PATCH 42/76] debt - less TPromise usage --- src/vs/workbench/api/node/extHostWorkspace.ts | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 215deb22d3a..08a022a9fad 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -13,7 +13,6 @@ import { isLinux } from 'vs/base/common/platform'; import { basenameOrAuthority, dirname, isEqual } from 'vs/base/common/resources'; import { compare } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; import { localize } from 'vs/nls'; import { ILogService } from 'vs/platform/log/common/log'; import { Severity } from 'vs/platform/notification/common/notification'; @@ -373,7 +372,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { } if (token && token.isCancellationRequested) { - return TPromise.wrap([]); + return Promise.resolve([]); } return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token) @@ -433,18 +432,16 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { }; if (token.isCancellationRequested) { - return TPromise.wrap(undefined); + return Promise.resolve(undefined); } - return this._proxy.$startTextSearch(query, queryOptions, requestId, token).then( - result => { - delete this._activeSearchCallbacks[requestId]; - return result; - }, - err => { - delete this._activeSearchCallbacks[requestId]; - return TPromise.wrapError(err); - }); + return this._proxy.$startTextSearch(query, queryOptions, requestId, token).then(result => { + delete this._activeSearchCallbacks[requestId]; + return result; + }, err => { + delete this._activeSearchCallbacks[requestId]; + return Promise.reject(err); + }); } $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void { From 6ea40d7b9e64cf0bdd69d2a0d0425b864d9d28b0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 10:40:34 +0200 Subject: [PATCH 43/76] debt - less TPromise usage --- .../electron-browser/remoteFileService.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index ffd8d26bcc0..f08e96ed830 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -55,7 +55,7 @@ function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse // dir -> resolve return provider.readdir(resource).then(entries => { // resolve children if requested - return TPromise.join(entries.map(tuple => { + return Promise.all(entries.map(tuple => { const [name, type] = tuple; const childResource = resources.joinPath(resource, name); return toIFileStat(provider, [childResource, new TypeOnlyStat(type)], recurse); @@ -68,7 +68,7 @@ function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse } // file or (un-resolved) dir - return TPromise.as(fileStat); + return Promise.resolve(fileStat); } export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], to: URI[]): Thenable { @@ -243,7 +243,7 @@ export class RemoteFileService extends FileService { // --- stat - private _withProvider(resource: URI): TPromise { + private _withProvider(resource: URI): Promise { if (!resources.isAbsolutePath(resource)) { throw new FileOperationError( @@ -252,7 +252,7 @@ export class RemoteFileService extends FileService { ); } - return TPromise.join([ + return Promise.all([ this._extensionService.activateByEvent('onFileSystem:' + resource.scheme) ]).then(() => { const provider = this._provider.get(resource.scheme); @@ -270,7 +270,7 @@ export class RemoteFileService extends FileService { if (resource.scheme === Schemas.file) { return super.existsFile(resource); } else { - return this.resolveFile(resource).then(data => true, err => false); + return this.resolveFile(resource).then(_data => true, _err => false); } } @@ -315,7 +315,7 @@ export class RemoteFileService extends FileService { return TPromise.join(promises).then(data => flatten(data)); } - private _doResolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + private _doResolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): Promise { return this._withProvider(toResolve[0].resource).then(provider => { let result: IResolveFileResult[] = []; let promises = toResolve.map((item, idx) => { @@ -327,7 +327,7 @@ export class RemoteFileService extends FileService { result[idx] = { stat: undefined, success: false }; }); }); - return TPromise.join(promises).then(() => result); + return Promise.all(promises).then(() => result); }); } @@ -349,7 +349,7 @@ export class RemoteFileService extends FileService { } } - private _readFile(resource: URI, options: IResolveContentOptions = Object.create(null)): TPromise { + private _readFile(resource: URI, options: IResolveContentOptions = Object.create(null)): Promise { return this._withProvider(resource).then(provider => { return this.resolveFile(resource).then(fileStat => { @@ -383,7 +383,7 @@ export class RemoteFileService extends FileService { return toDecodeStream(readable, decodeStreamOpts).then(data => { if (options.acceptTextOnly && data.detected.seemsBinary) { - return TPromise.wrapError(new FileOperationError( + return Promise.reject(new FileOperationError( localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), FileOperationResult.FILE_IS_BINARY, options @@ -543,11 +543,11 @@ export class RemoteFileService extends FileService { } } - private _doMoveWithInScheme(source: URI, target: URI, overwrite?: boolean): TPromise { + private _doMoveWithInScheme(source: URI, target: URI, overwrite?: boolean): Promise { const prepare = overwrite - ? this.del(target, { recursive: true }).then(undefined, err => { /*ignore*/ }) - : TPromise.as(null); + ? Promise.resolve(this.del(target, { recursive: true }).then(undefined, err => { /*ignore*/ })) + : Promise.resolve(null); return prepare.then(() => this._withProvider(source)).then(RemoteFileService._throwIfFileSystemIsReadonly).then(provider => { return provider.rename(source, target, { overwrite }).then(() => { @@ -600,8 +600,8 @@ export class RemoteFileService extends FileService { } const prepare = overwrite - ? this.del(target, { recursive: true }).then(undefined, err => { /*ignore*/ }) - : TPromise.as(null); + ? Promise.resolve(this.del(target, { recursive: true }).then(undefined, err => { /*ignore*/ })) + : Promise.resolve(null); return prepare.then(() => { // todo@ben, can only copy text files @@ -625,7 +625,7 @@ export class RemoteFileService extends FileService { // file scheme return super.updateContent(target, content.value, { encoding: content.encoding }); } else { - return TPromise.wrapError(err); + return Promise.reject(err); } }); }); From 5300bc54b49a24668526d3053e17c66ef26ec236 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 10:43:43 +0200 Subject: [PATCH 44/76] debt - less TPromise usage --- src/vs/workbench/api/electron-browser/mainThreadCommands.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadCommands.ts b/src/vs/workbench/api/electron-browser/mainThreadCommands.ts index 41109430a65..4753577d61c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadCommands.ts @@ -5,7 +5,6 @@ import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { revive } from 'vs/base/common/marshalling'; @@ -79,7 +78,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { } $getCommands(): Thenable { - return TPromise.as(Object.keys(CommandsRegistry.getCommands())); + return Promise.resolve(Object.keys(CommandsRegistry.getCommands())); } } From 5bd6ebe2dbc4dee510699020a25f70a69784ce8c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 9 Oct 2018 10:57:39 +0200 Subject: [PATCH 45/76] move Promise back to TPromise in nfcall related to #60163 --- src/vs/base/common/async.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index cc3d388ce35..bcf32e22066 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -657,7 +657,7 @@ export class RunOnceWorker extends RunOnceScheduler { export function nfcall(fn: Function, ...args: any[]): Promise; export function nfcall(fn: Function, ...args: any[]): Promise; export function nfcall(fn: Function, ...args: any[]): any { - return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result))); + return new TPromise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result))); } export function ninvoke(thisArg: any, fn: Function, ...args: any[]): TPromise; From 099c23febca61c3ac99066e472fc1e08ed88b24a Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 9 Oct 2018 12:07:13 +0200 Subject: [PATCH 46/76] repl: allow to inspect repl output of inactive sessions --- .../mainThreadDebugService.ts | 2 +- .../parts/debug/browser/debugActionItems.ts | 12 +- .../parts/debug/browser/debugActions.ts | 25 --- src/vs/workbench/parts/debug/common/debug.ts | 7 +- .../parts/debug/common/debugModel.ts | 14 +- .../electron-browser/debug.contribution.ts | 3 +- .../debug/electron-browser/debugService.ts | 12 +- .../debug/electron-browser/debugSession.ts | 11 +- .../parts/debug/electron-browser/repl.ts | 183 ++++++++++++------ .../debug/electron-browser/replViewer.ts | 8 +- .../parts/debug/test/common/mockDebug.ts | 4 - .../test/electron-browser/debugModel.test.ts | 6 +- 12 files changed, 155 insertions(+), 132 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index e470a4f367a..f41a7b9caf0 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -190,7 +190,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb } public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): Thenable { - const session = this.debugService.getSession(sessionId); + const session = this.debugService.getModel().getSessions(true).filter(s => s.getId() === sessionId).pop(); if (session) { return session.customRequest(request, args).then(response => { if (response && response.success) { diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index cc8559fe8d9..52fc337a4ae 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -12,7 +12,7 @@ import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox'; import { SelectActionItem, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, IDebugSession } from 'vs/workbench/parts/debug/common/debug'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; @@ -190,7 +190,7 @@ export class StartDebugActionItem implements IActionItem { export class FocusSessionActionItem extends SelectActionItem { constructor( action: IAction, - @IDebugService private debugService: IDebugService, + @IDebugService protected debugService: IDebugService, @IThemeService themeService: IThemeService, @IContextViewService contextViewService: IContextViewService, ) { @@ -201,7 +201,7 @@ export class FocusSessionActionItem extends SelectActionItem { this.toDispose.push(this.debugService.getViewModel().onDidFocusSession(() => { const session = this.debugService.getViewModel().focusedSession; if (session) { - const index = this.debugService.getModel().getSessions().indexOf(session); + const index = this.getSessions().indexOf(session); this.select(index); } })); @@ -214,8 +214,12 @@ export class FocusSessionActionItem extends SelectActionItem { private update() { const session = this.debugService.getViewModel().focusedSession; - const sessions = this.debugService.getModel().getSessions(); + const sessions = this.getSessions(); const names = sessions.map(s => s.getLabel()); this.setOptions(names, session ? sessions.indexOf(session) : undefined); } + + protected getSessions(): ReadonlyArray { + return this.debugService.getModel().getSessions(); + } } diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index b7818064d6f..31df8070f8a 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -9,7 +9,6 @@ import * as lifecycle from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import * as aria from 'vs/base/browser/ui/aria/aria'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IFileService } from 'vs/platform/files/common/files'; import { IDebugService, State, IDebugSession, IThread, IEnablement, IBreakpoint, IStackFrame, REPL_ID } @@ -677,30 +676,6 @@ export class RemoveAllWatchExpressionsAction extends AbstractDebugAction { } } -export class ClearReplAction extends AbstractDebugAction { - static readonly ID = 'workbench.debug.panel.action.clearReplAction'; - static LABEL = nls.localize('clearRepl', "Clear Console"); - - constructor(id: string, label: string, - @IDebugService debugService: IDebugService, - @IKeybindingService keybindingService: IKeybindingService, - @IPanelService private panelService: IPanelService - ) { - super(id, label, 'debug-action clear-repl', debugService, keybindingService); - } - - public run(): TPromise { - const session = this.debugService.getViewModel().focusedSession; - if (session) { - session.removeReplExpressions(); - aria.status(nls.localize('debugConsoleCleared', "Debug console was cleared")); - } - - // focus back to repl - return this.panelService.openPanel(REPL_ID, true); - } -} - export class ToggleReplAction extends TogglePanelAction { static readonly ID = 'workbench.debug.action.toggleRepl'; static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugConsoleAction' }, 'Debug Console'); diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index d8af85b2cec..addce369d6c 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -376,7 +376,7 @@ export interface IViewModel extends ITreeElement { } export interface IDebugModel extends ITreeElement { - getSessions(): ReadonlyArray; + getSessions(includeInactive?: boolean): ReadonlyArray; getBreakpoints(filter?: { uri?: uri, lineNumber?: number, column?: number, enabledOnly?: boolean }): ReadonlyArray; areBreakpointsActivated(): boolean; getFunctionBreakpoints(): ReadonlyArray; @@ -772,11 +772,6 @@ export interface IDebugService { */ sourceIsNotAvailable(uri: uri): void; - /** - * returns Session with the given ID (or undefined if ID is not found) - */ - getSession(sessionId: string): IDebugSession; - /** * Gets the current debug model. */ diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index a5f38180727..a27da68f7aa 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -17,7 +17,7 @@ import { distinct } from 'vs/base/common/arrays'; import { Range, IRange } from 'vs/editor/common/core/range'; import { ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource, - IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint + IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State } from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { commonSuffixLength } from 'vs/base/common/strings'; @@ -751,16 +751,16 @@ export class DebugModel implements IDebugModel { return 'root'; } - public getSessions(): IDebugSession[] { - return this.sessions; + public getSessions(includeInactive = false): IDebugSession[] { + // By default do not return inactive sesions. + // However we are still holding onto inactive sessions due to repl and debug service session revival (eh scenario) + return this.sessions.filter(s => includeInactive || s.state !== State.Inactive); } public addSession(session: IDebugSession): void { + // Make sure to remove all inactive sessions once a new session is started + this.sessions = this.sessions.filter(s => s.state !== State.Inactive); this.sessions.push(session); - } - - public removeSession(id: string): void { - this.sessions = this.sessions.filter(p => p.getId() !== id); this._onDidChangeCallStack.fire(); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts index db53d6ad76b..4f3652fdb42 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -30,7 +30,7 @@ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { DebugEditorModelManager } from 'vs/workbench/parts/debug/browser/debugEditorModelManager'; import { - StepOverAction, ClearReplAction, FocusReplAction, StepIntoAction, StepOutAction, StartAction, RestartAction, ContinueAction, StopAction, DisconnectAction, PauseAction, AddFunctionBreakpointAction, + StepOverAction, FocusReplAction, StepIntoAction, StepOutAction, StartAction, RestartAction, ContinueAction, StopAction, DisconnectAction, PauseAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBreakpointsAction, EnableAllBreakpointsAction, RemoveAllBreakpointsAction, RunAction, ReapplyBreakpointsAction, SelectAndStartAction, TerminateThreadAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { DebugToolbar } from 'vs/workbench/parts/debug/browser/debugToolbar'; @@ -147,7 +147,6 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.I registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(FocusReplAction, FocusReplAction.ID, FocusReplAction.LABEL), 'Debug: Focus on Debug Console View', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 4e0ef43dc33..3f3a6f89294 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -81,7 +81,6 @@ export class DebugService implements IDebugService { private model: DebugModel; private viewModel: ViewModel; private configurationManager: ConfigurationManager; - private allSessions = new Map(); private toDispose: IDisposable[]; private debugType: IContextKey; private debugState: IContextKey; @@ -138,7 +137,7 @@ export class DebugService implements IDebugService { this.lifecycleService.onShutdown(this.dispose, this); this.toDispose.push(this.broadcastService.onBroadcast(broadcast => { - const session = this.getSession(broadcast.payload.debugId); + const session = this.model.getSessions(true).filter(s => s.getId() === broadcast.payload.debugId).pop(); if (session) { switch (broadcast.channel) { @@ -179,10 +178,6 @@ export class DebugService implements IDebugService { })); } - getSession(sessionId: string): IDebugSession { - return this.allSessions.get(sessionId); - } - getModel(): IDebugModel { return this.model; } @@ -271,10 +266,6 @@ export class DebugService implements IDebugService { this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(launch ? launch.workspace : undefined).then(() => this.extensionService.whenInstalledExtensionsRegistered().then(() => { - if (this.model.getSessions().length === 0) { - this.allSessions.clear(); - } - let config: IConfig, compound: ICompound; if (!configOrName) { configOrName = this.configurationManager.selectedConfiguration.name; @@ -431,7 +422,6 @@ export class DebugService implements IDebugService { private doCreateSession(root: IWorkspaceFolder, configuration: { resolved: IConfig, unresolved: IConfig }): TPromise { const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model); - this.allSessions.set(session.getId(), session); // register listeners as the very first thing! this.registerSessionListeners(session); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts index f8f87ed14b3..bb9731a3d7c 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts @@ -90,6 +90,10 @@ export class DebugSession implements IDebugSession { } get state(): State { + if (!this.raw) { + return State.Inactive; + } + const focusedThread = this.debugService.getViewModel().focusedThread; if (focusedThread && focusedThread.session === this) { return focusedThread.stopped ? State.Stopped : State.Running; @@ -98,7 +102,7 @@ export class DebugSession implements IDebugSession { return State.Stopped; } - return !!this.raw ? State.Running : State.Inactive; + return State.Running; } get capabilities(): DebugProtocol.Capabilities { @@ -747,14 +751,13 @@ export class DebugSession implements IDebugSession { shutdown(): void { dispose(this.rawListeners); - this.model.clearThreads(this.getId(), true); - this.model.removeSession(this.getId()); - this._onDidChangeState.fire(); this.fetchThreadsScheduler = undefined; if (this.raw) { this.raw.disconnect(); } this.raw = undefined; + this.model.clearThreads(this.getId(), true); + this._onDidChangeState.fire(); } //---- sources diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index 0a0d7127d64..c9ebbd28319 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import { URI as uri } from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import * as errors from 'vs/base/common/errors'; -import { IAction, IActionItem } from 'vs/base/common/actions'; +import { IAction, IActionItem, Action } from 'vs/base/common/actions'; import * as dom from 'vs/base/browser/dom'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { isMacintosh } from 'vs/base/common/platform'; @@ -29,7 +29,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ReplExpressionsRenderer, ReplExpressionsController, ReplExpressionsDataSource, ReplExpressionsActionProvider, ReplExpressionsAccessibilityProvider } from 'vs/workbench/parts/debug/electron-browser/replViewer'; -import { ClearReplAction, FocusSessionAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { Panel } from 'vs/workbench/browser/panel'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -41,7 +40,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { OpenMode, ClickBehavior } from 'vs/base/parts/tree/browser/treeDefaults'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; -import { IDebugService, REPL_ID, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, REPL_ID, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL, IDebugSession, State } from 'vs/workbench/parts/debug/common/debug'; import { HistoryNavigator } from 'vs/base/common/history'; import { IHistoryNavigationWidget } from 'vs/base/browser/history'; import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; @@ -68,10 +67,12 @@ export interface IPrivateReplService { _serviceBrand: any; acceptReplInput(): void; getVisibleContent(): string; + selectSession(session: IDebugSession): void; + clearRepl(): void; } export class Repl extends Panel implements IPrivateReplService, IHistoryNavigationWidget { - public _serviceBrand: any; + _serviceBrand: any; private static readonly HALF_WIDTH_TYPICAL = 'n'; @@ -91,6 +92,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati private replInputHeight: number; private model: ITextModel; private historyNavigationEnablement: IContextKey; + private scopedInstantiationService: IInstantiationService; + private replElementsChangeListener: IDisposable; constructor( @IDebugService private debugService: IDebugService, @@ -112,33 +115,11 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } private registerListeners(): void { - let replElementsChangeListener: IDisposable; this._register(this.debugService.getViewModel().onDidFocusSession(session => { - if (replElementsChangeListener) { - replElementsChangeListener.dispose(); - } - if (session) { - replElementsChangeListener = session.onDidChangeReplElements(() => { - this.refreshReplElements(session.getReplElements().length === 0); - }); - - if (this.tree && this.isVisible()) { - this.tree.setInput(session); - } - } - this.replInput.updateOptions({ readOnly: !session }); - if (this.isVisible()) { - this.updateInputDecoration(); - } + this.selectSession(session); })); - this._register(this.panelService.onDidPanelOpen(panel => this.refreshReplElements(true))); + this._register(this.panelService.onDidPanelOpen(() => this.refreshReplElements(true))); this._register(this.debugService.onDidNewSession(() => this.updateTitleArea())); - this._register(this.debugService.onDidEndSession(() => { - if (this.debugService.getModel().getSessions().length === 0) { - // Only hide the session drop down when there are 0 sessions - this.updateTitleArea(); - } - })); this._register(this.themeService.onThemeChange(() => { if (this.isVisible()) { this.updateInputDecoration(); @@ -166,14 +147,14 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } - public async create(parent: HTMLElement): Promise { + async create(parent: HTMLElement): Promise { await super.create(parent); this.container = dom.append(parent, $('.repl')); this.treeContainer = dom.append(this.container, $('.repl-tree')); this.createReplInput(this.container); this.renderer = this.instantiationService.createInstance(ReplExpressionsRenderer); - const controller = this.instantiationService.createInstance(ReplExpressionsController, new ReplExpressionsActionProvider(this.instantiationService, this.replInput), MenuId.DebugConsoleContext, { openMode: OpenMode.SINGLE_CLICK, clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change, to preserve focus behaviour in input field */ }); + const controller = this.instantiationService.createInstance(ReplExpressionsController, new ReplExpressionsActionProvider(this.clearReplAction, this.replInput), MenuId.DebugConsoleContext, { openMode: OpenMode.SINGLE_CLICK, clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change, to preserve focus behaviour in input field */ }); controller.toFocusOnClick = this.replInput; this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, { @@ -184,7 +165,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati }, replTreeOptions); } - public setVisible(visible: boolean): Promise { + setVisible(visible: boolean): Promise { if (!visible) { dispose(this.model); } else { @@ -193,7 +174,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.updateInputDecoration(); const focusedSession = this.debugService.getViewModel().focusedSession; if (focusedSession && this.tree.getInput() !== focusedSession) { - this.tree.setInput(focusedSession); + this.selectSession(focusedSession); } } @@ -208,11 +189,11 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this._register(scopedContextKeyService); CONTEXT_IN_DEBUG_REPL.bindTo(scopedContextKeyService).set(true); - const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( + this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( [IContextKeyService, scopedContextKeyService], [IPrivateReplService, this])); const options = getSimpleEditorOptions(); options.readOnly = true; - this.replInput = scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); + this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); modes.CompletionProviderRegistry.register({ scheme: DEBUG_SCHEME, pattern: '**/replinput', hasAccessToAllModels: true }, { triggerCharacters: ['.'], @@ -265,19 +246,44 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } - public showPreviousValue(): void { + showPreviousValue(): void { this.navigateHistory(true); } - public showNextValue(): void { + showNextValue(): void { this.navigateHistory(false); } - public acceptReplInput(): void { - const viewModel = this.debugService.getViewModel(); - const session = viewModel.focusedSession; + selectSession(session: IDebugSession): void { + if (this.replElementsChangeListener) { + this.replElementsChangeListener.dispose(); + } if (session) { - session.addReplExpression(viewModel.focusedStackFrame, this.replInput.getValue()); + this.replElementsChangeListener = session.onDidChangeReplElements(() => { + this.refreshReplElements(session.getReplElements().length === 0); + }); + + if (this.tree && this.isVisible() && this.tree.getInput() !== session) { + this.tree.setInput(session); + } + } + + this.replInput.updateOptions({ readOnly: this.isReadonly }); + if (this.isVisible()) { + this.updateInputDecoration(); + } + } + + clearRepl(): void { + const session: IDebugSession = this.tree.getInput(); + session.removeReplExpressions(); + this.replInput.focus(); + } + + acceptReplInput(): void { + const session: IDebugSession = this.tree.getInput(); + if (session) { + session.addReplExpression(this.debugService.getViewModel().focusedStackFrame, this.replInput.getValue()); this.history.add(this.replInput.getValue()); this.replInput.setValue(''); // Trigger a layout to shrink a potential multi line input @@ -286,7 +292,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } - public getVisibleContent(): string { + getVisibleContent(): string { let text = ''; const navigator = this.tree.getNavigator(); // skip first navigator element - the root node @@ -300,7 +306,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati return text; } - public layout(dimension: dom.Dimension): void { + layout(dimension: dom.Dimension): void { this.dimension = dimension; if (this.tree) { this.renderer.setWidth(dimension.width - 25, this.characterWidth); @@ -313,6 +319,16 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.replInput.layout({ width: dimension.width - 20, height: this.replInputHeight }); } + get isReadonly(): boolean { + // Do not allow to edit inactive sessions + const session: IDebugSession = this.tree.getInput(); + if (session && session.state !== State.Inactive) { + return false; + } + + return true; + } + @memoize private get characterWidth(): number { const characterWidthSurveyor = dom.append(this.container, $('.surveyor')); @@ -325,22 +341,22 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati return characterWidthSurveyor.clientWidth / characterWidthSurveyor.textContent.length; } - public focus(): void { + focus(): void { this.replInput.focus(); } getActionItem(action: IAction): IActionItem { - if (action.id === FocusSessionAction.ID) { - return this.focusSessionActionItem; + if (action.id === SelectReplAction.ID) { + return this.instantiationService.createInstance(SelectReplActionItem, this.selectReplAction); } return undefined; } - public getActions(): IAction[] { + getActions(): IAction[] { const result: IAction[] = []; - if (this.debugService.getModel().getSessions().length > 1) { - result.push(this.focusSessionAction); + if (this.debugService.getModel().getSessions(true).length > 1) { + result.push(this.selectReplAction); } result.push(this.clearReplAction); @@ -349,7 +365,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati return result; } - public shutdown(): void { + shutdown(): void { const replHistory = this.history.getHistory(); if (replHistory.length) { this.storageService.store(HISTORY_STORAGE_KEY, JSON.stringify(replHistory), StorageScope.WORKSPACE); @@ -359,17 +375,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } @memoize - private get focusSessionAction(): FocusSessionAction { - return this.instantiationService.createInstance(FocusSessionAction, FocusSessionAction.ID, FocusSessionAction.LABEL); + private get selectReplAction(): SelectReplAction { + return this.scopedInstantiationService.createInstance(SelectReplAction, SelectReplAction.ID, SelectReplAction.LABEL); } @memoize private get clearReplAction(): ClearReplAction { - return this.instantiationService.createInstance(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL); - } - - private get focusSessionActionItem(): FocusSessionActionItem { - return this.instantiationService.createInstance(FocusSessionActionItem, this.focusSessionAction); + return this.scopedInstantiationService.createInstance(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL); } private updateInputDecoration(): void { @@ -378,7 +390,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } const decorations: IDecorationOptions[] = []; - if (!this.debugService.getViewModel().focusedSession) { + if (this.isReadonly) { decorations.push({ range: { startLineNumber: 0, @@ -398,7 +410,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.replInput.setDecorations(DECORATION_KEY, decorations); } - public dispose(): void { + dispose(): void { this.replInput.dispose(); super.dispose(); } @@ -420,7 +432,7 @@ class AcceptReplInputAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): void | TPromise { + run(accessor: ServicesAccessor, editor: ICodeEditor): void | TPromise { SuggestController.get(editor).acceptSelectedSuggestion(); accessor.get(IPrivateReplService).acceptReplInput(); } @@ -437,7 +449,7 @@ export class ReplCopyAllAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): void | TPromise { + run(accessor: ServicesAccessor, editor: ICodeEditor): void | TPromise { clipboard.writeText(accessor.get(IPrivateReplService).getVisibleContent()); } } @@ -456,3 +468,54 @@ registerEditorCommand(new SuggestCommand({ primary: KeyCode.RightArrow } })); + +class SelectReplActionItem extends FocusSessionActionItem { + protected getSessions(): ReadonlyArray { + return this.debugService.getModel().getSessions(true); + } +} + +class SelectReplAction extends Action { + + static readonly ID = 'workbench.action.debug.selectRepl'; + static LABEL = nls.localize('selectRepl', "Select Debug Console"); + + constructor(id: string, label: string, + @IDebugService private debugService: IDebugService, + @IPrivateReplService private replService: IPrivateReplService + ) { + super(id, label); + } + + run(sessionName: string): TPromise { + const session = this.debugService.getModel().getSessions(true).filter(p => p.getLabel() === sessionName).pop(); + // If session is already the focused session we need to manualy update the tree since view model will not send a focused change event + if (session && session.state !== State.Inactive && session !== this.debugService.getViewModel().focusedSession) { + this.debugService.focusStackFrame(undefined, undefined, session, true); + } else { + this.replService.selectSession(session); + } + + return Promise.resolve(undefined); + } +} + +class ClearReplAction extends Action { + static readonly ID = 'workbench.debug.panel.action.clearReplAction'; + static LABEL = nls.localize('clearRepl', "Clear Console"); + + constructor(id: string, label: string, + @IDebugService debugService: IDebugService, + @IPrivateReplService private replService: IPrivateReplService + ) { + super(id, label, 'debug-action clear-repl'); + } + + public run(): TPromise { + this.replService.clearRepl(); + aria.status(nls.localize('debugConsoleCleared', "Debug console was cleared")); + + // focus back to repl + return Promise.resolve(undefined); + } +} diff --git a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts index fecd8d36b1f..82bf8989a13 100644 --- a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IAction } from 'vs/base/common/actions'; +import { IAction, Action } from 'vs/base/common/actions'; import * as lifecycle from 'vs/base/common/lifecycle'; import { isFullWidthCharacter, removeAnsiEscapeCodes, endsWith } from 'vs/base/common/strings'; import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -17,7 +17,7 @@ import { ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults'; import { IExpressionContainer, IExpression, IReplElementSource } from 'vs/workbench/parts/debug/common/debug'; import { RawObjectReplElement, Expression, SimpleReplElement, Variable } from 'vs/workbench/parts/debug/common/debugModel'; import { renderVariable, renderExpressionValue, IVariableTemplateData, BaseDebugController } from 'vs/workbench/parts/debug/browser/baseDebugView'; -import { ClearReplAction, ReplCollapseAllAction } from 'vs/workbench/parts/debug/browser/debugActions'; +import { ReplCollapseAllAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { CopyAction, CopyAllAction } from 'vs/workbench/parts/debug/electron-browser/electronDebugActions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -317,7 +317,7 @@ export class ReplExpressionsAccessibilityProvider implements IAccessibilityProvi export class ReplExpressionsActionProvider implements IActionProvider { - constructor(private instantiationService: IInstantiationService, private toFocus: { focus(): void }) { + constructor(private clearReplAction: Action, private toFocus: { focus(): void }) { // noop } @@ -339,7 +339,7 @@ export class ReplExpressionsActionProvider implements IActionProvider { actions.push(new CopyAllAction(CopyAllAction.ID, CopyAllAction.LABEL, tree)); actions.push(new ReplCollapseAllAction(tree, this.toFocus)); actions.push(new Separator()); - actions.push(this.instantiationService.createInstance(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL)); + actions.push(this.clearReplAction); return Promise.resolve(actions); } diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 09f8cd37c55..36811ef24d1 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -17,10 +17,6 @@ export class MockDebugService implements IDebugService { public _serviceBrand: any; - getSession(sessionId: string): IDebugSession { - return undefined; - } - public get state(): State { return null; } diff --git a/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts b/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts index d9fc61272b5..c16ffe8c9de 100644 --- a/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts +++ b/src/vs/workbench/parts/debug/test/electron-browser/debugModel.test.ts @@ -113,7 +113,7 @@ suite('Debug - Model', () => { const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); model.addSession(session); - assert.equal(model.getSessions().length, 1); + assert.equal(model.getSessions(true).length, 1); model.rawUpdate({ sessionId: session.getId(), threadId: threadId, @@ -127,9 +127,7 @@ suite('Debug - Model', () => { model.clearThreads(session.getId(), true); assert.equal(session.getThread(threadId), null); - assert.equal(model.getSessions().length, 1); - model.removeSession(session.getId()); - assert.equal(model.getSessions().length, 0); + assert.equal(model.getSessions(true).length, 1); }); test('threads multiple wtih allThreadsStopped', () => { From 53321de6d3567a1a696216a47fa38e8f550f8e32 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 12:09:21 +0200 Subject: [PATCH 47/76] fix #60247 --- .../electron-browser/snippetsService.ts | 70 ++++++------------- .../electron-browser/snippetsService.test.ts | 51 +++++++++----- 2 files changed, 55 insertions(+), 66 deletions(-) diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts b/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts index a63e501486e..afb20204aa9 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts @@ -13,7 +13,7 @@ import { compare, endsWith, isFalsyOrWhitespace } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { Position } from 'vs/editor/common/core/position'; import { ITextModel } from 'vs/editor/common/model'; -import { CompletionItem, CompletionList, CompletionItemProvider, LanguageId, CompletionContext, CompletionItemKind } from 'vs/editor/common/modes'; +import { CompletionItem, CompletionList, CompletionItemProvider, LanguageId, CompletionItemKind } from 'vs/editor/common/modes'; import { IModeService } from 'vs/editor/common/services/modeService'; import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser'; import { setSnippetSuggestSupport } from 'vs/editor/contrib/suggest/suggest'; @@ -365,53 +365,35 @@ export class SnippetSuggestProvider implements CompletionItemProvider { // } - provideCompletionItems(model: ITextModel, position: Position, context: CompletionContext): Promise { + provideCompletionItems(model: ITextModel, pos: Position): Promise { - const languageId = this._getLanguageIdAtPosition(model, position); + const languageId = this._getLanguageIdAtPosition(model, pos); return this._snippets.getSnippets(languageId).then(snippets => { - let suggestions: SnippetSuggestion[]; - let shift = Math.max(0, position.column - 100); - let pos = { lineNumber: position.lineNumber, column: Math.max(1, position.column - 100) }; - let lineOffsets: number[] = []; - let linePrefixLow = model.getLineContent(position.lineNumber).substr(Math.max(0, position.column - 100), position.column - 1).toLowerCase(); + let suggestions: SnippetSuggestion[] = []; + let atWord = Boolean(model.getWordAtPosition(pos)); + let lineLow = model.getLineContent(pos.lineNumber).substring(0, pos.column - 1).toLowerCase(); - while (pos.column < position.column) { - let word = model.getWordAtPosition(pos); - if (word) { - // at a word - lineOffsets.push(word.startColumn - 1); - pos.column = word.endColumn + 1; + for (const snippet of snippets) { - if (word.endColumn - 1 < linePrefixLow.length && !/\s/.test(linePrefixLow[word.endColumn - 1])) { - lineOffsets.push(word.endColumn - 1); + let prefixLow = snippet.prefix; + let prefixPos = prefixLow.length - 1; + let linePos = lineLow.length - 1; + let linePosStart = linePos; + while (linePos >= 0 && prefixPos >= 0) { + if (lineLow[linePos] === prefixLow[prefixPos]) { + linePos -= 1; } - - } else if (!/\s/.test(linePrefixLow[pos.column - 1])) { - // at a none-whitespace character - lineOffsets.push(pos.column - 1); - pos.column += 1; - } else { - // always advance! - pos.column += 1; + prefixPos -= 1; } - } - if (lineOffsets.length === 0) { - // no interesting spans found -> pick all snippets - suggestions = snippets.map(snippet => new SnippetSuggestion(snippet, Range.fromPositions(position))); + if (linePos !== linePosStart) { + // some overlap + suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(pos.delta(0, linePos - linePosStart), pos))); - } else { - let consumed = new Set(); - suggestions = []; - for (let start of lineOffsets) { - start -= shift; - for (const snippet of snippets) { - if (!consumed.has(snippet) && matches(linePrefixLow, start, snippet.prefixLow, 0)) { - suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(position.delta(0, -(linePrefixLow.length - start)), position))); - consumed.add(snippet); - } - } + } else if (!atWord) { + // no overlap but not at a word + suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(pos))); } } @@ -451,16 +433,6 @@ export class SnippetSuggestProvider implements CompletionItemProvider { } } -function matches(pattern: string, patternStart: number, word: string, wordStart: number): boolean { - while (patternStart < pattern.length && wordStart < word.length) { - if (pattern[patternStart] === word[wordStart]) { - patternStart += 1; - } - wordStart += 1; - } - return patternStart === pattern.length; -} - export function getNonWhitespacePrefix(model: ISimpleModel, position: Position): string { /** * Do not analyze more characters diff --git a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts index 37e132671ea..2de580f6a71 100644 --- a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts +++ b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts @@ -11,7 +11,6 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { TextModel } from 'vs/editor/common/model/textModel'; import { ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; import { Snippet, SnippetSource } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile'; -import { CompletionContext, CompletionTriggerKind } from 'vs/editor/common/modes'; class SimpleSnippetService implements ISnippetsService { _serviceBrand: any; @@ -39,7 +38,6 @@ suite('SnippetsService', function () { let modeService: ModeServiceImpl; let snippetService: ISnippetsService; - let suggestContext: CompletionContext = { triggerKind: CompletionTriggerKind.Invoke }; setup(function () { modeService = new ModeServiceImpl(); @@ -68,7 +66,7 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = TextModel.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang')); - return provider.provideCompletionItems(model, new Position(1, 1), suggestContext).then(result => { + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { assert.equal(result.incomplete, undefined); assert.equal(result.suggestions.length, 2); }); @@ -79,7 +77,7 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = TextModel.createFromString('bar', undefined, modeService.getLanguageIdentifier('fooLang')); - return provider.provideCompletionItems(model, new Position(1, 4), suggestContext).then(result => { + return provider.provideCompletionItems(model, new Position(1, 4)).then(result => { assert.equal(result.incomplete, undefined); assert.equal(result.suggestions.length, 1); assert.equal(result.suggestions[0].label, 'bar'); @@ -111,7 +109,7 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = TextModel.createFromString('bar-bar', undefined, modeService.getLanguageIdentifier('fooLang')); - await provider.provideCompletionItems(model, new Position(1, 3), suggestContext).then(result => { + await provider.provideCompletionItems(model, new Position(1, 3)).then(result => { assert.equal(result.incomplete, undefined); assert.equal(result.suggestions.length, 2); assert.equal(result.suggestions[0].label, 'bar'); @@ -122,7 +120,7 @@ suite('SnippetsService', function () { assert.equal(result.suggestions[1].range.startColumn, 1); }); - await provider.provideCompletionItems(model, new Position(1, 5), suggestContext).then(result => { + await provider.provideCompletionItems(model, new Position(1, 5)).then(result => { assert.equal(result.incomplete, undefined); assert.equal(result.suggestions.length, 1); assert.equal(result.suggestions[0].label, 'bar-bar'); @@ -130,7 +128,7 @@ suite('SnippetsService', function () { assert.equal(result.suggestions[0].range.startColumn, 1); }); - await provider.provideCompletionItems(model, new Position(1, 6), suggestContext).then(result => { + await provider.provideCompletionItems(model, new Position(1, 6)).then(result => { assert.equal(result.incomplete, undefined); assert.equal(result.suggestions.length, 2); assert.equal(result.suggestions[0].label, 'bar'); @@ -156,19 +154,19 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); let model = TextModel.createFromString('\t { + return provider.provideCompletionItems(model, new Position(1, 7)).then(result => { assert.equal(result.suggestions.length, 1); model.dispose(); model = TextModel.createFromString('\t { assert.equal(result.suggestions.length, 1); assert.equal(result.suggestions[0].range.startColumn, 2); model.dispose(); model = TextModel.createFromString('a { assert.equal(result.suggestions.length, 1); assert.equal(result.suggestions[0].range.startColumn, 2); @@ -191,9 +189,9 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); let model = TextModel.createFromString('\n\t\n>/head>', undefined, modeService.getLanguageIdentifier('fooLang')); - return provider.provideCompletionItems(model, new Position(1, 1), suggestContext).then(result => { + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { assert.equal(result.suggestions.length, 1); - return provider.provideCompletionItems(model, new Position(2, 2), suggestContext); + return provider.provideCompletionItems(model, new Position(2, 2)); }).then(result => { assert.equal(result.suggestions.length, 1); }); @@ -221,7 +219,7 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); let model = TextModel.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang')); - return provider.provideCompletionItems(model, new Position(1, 1), suggestContext).then(result => { + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { assert.equal(result.suggestions.length, 2); let [first, second] = result.suggestions; assert.equal(first.label, 'first'); @@ -243,13 +241,13 @@ suite('SnippetsService', function () { let model = TextModel.createFromString('p-', undefined, modeService.getLanguageIdentifier('fooLang')); - let result = await provider.provideCompletionItems(model, new Position(1, 2), suggestContext); + let result = await provider.provideCompletionItems(model, new Position(1, 2)); assert.equal(result.suggestions.length, 1); - result = await provider.provideCompletionItems(model, new Position(1, 3), suggestContext); + result = await provider.provideCompletionItems(model, new Position(1, 3)); assert.equal(result.suggestions.length, 1); - result = await provider.provideCompletionItems(model, new Position(1, 3), { triggerCharacter: '-', triggerKind: CompletionTriggerKind.TriggerCharacter }); + result = await provider.provideCompletionItems(model, new Position(1, 3)); assert.equal(result.suggestions.length, 1); }); @@ -267,7 +265,26 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); let model = TextModel.createFromString('Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea b', undefined, modeService.getLanguageIdentifier('fooLang')); - let result = await provider.provideCompletionItems(model, new Position(1, 158), suggestContext); + let result = await provider.provideCompletionItems(model, new Position(1, 158)); + + assert.equal(result.suggestions.length, 1); + }); + + test('No snippets suggestion beyond character 100 if not at end of line #60247', async function () { + snippetService = new SimpleSnippetService([new Snippet( + ['fooLang'], + 'bug', + 'bug', + '', + 'second', + '', + SnippetSource.User + )]); + + const provider = new SnippetSuggestProvider(modeService, snippetService); + + let model = TextModel.createFromString('Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea b text_after_b', undefined, modeService.getLanguageIdentifier('fooLang')); + let result = await provider.provideCompletionItems(model, new Position(1, 158)); assert.equal(result.suggestions.length, 1); }); From ccdbbe13a2befa70b49fe0a8d62cafe57ff7176b Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 9 Oct 2018 12:39:08 +0200 Subject: [PATCH 48/76] debug: make sure to dispose of all sesions on shutdown --- src/vs/workbench/parts/debug/common/debugModel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index a27da68f7aa..27eb3321270 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -1049,6 +1049,7 @@ export class DebugModel implements IDebugModel { } public dispose(): void { + this.sessions.forEach(s => s.shutdown()); this.toDispose = lifecycle.dispose(this.toDispose); } } From 12a0b0e74904dc8f112454fe0bc01914e8011045 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 9 Oct 2018 12:44:31 +0200 Subject: [PATCH 49/76] repl: fix smoke test, make sure to get proper state when becomes visible --- .../workbench/parts/debug/electron-browser/repl.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index c9ebbd28319..d2fe3e0f6ee 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -30,7 +30,6 @@ import { IInstantiationService, createDecorator } from 'vs/platform/instantiatio import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ReplExpressionsRenderer, ReplExpressionsController, ReplExpressionsDataSource, ReplExpressionsActionProvider, ReplExpressionsAccessibilityProvider } from 'vs/workbench/parts/debug/electron-browser/replViewer'; import { Panel } from 'vs/workbench/browser/panel'; -import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { clipboard } from 'electron'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -100,7 +99,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati @ITelemetryService telemetryService: ITelemetryService, @IInstantiationService private instantiationService: IInstantiationService, @IStorageService private storageService: IStorageService, - @IPanelService private panelService: IPanelService, @IThemeService protected themeService: IThemeService, @IModelService private modelService: IModelService, @IContextKeyService private contextKeyService: IContextKeyService, @@ -116,9 +114,10 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati private registerListeners(): void { this._register(this.debugService.getViewModel().onDidFocusSession(session => { - this.selectSession(session); + if (this.isVisible()) { + this.selectSession(session); + } })); - this._register(this.panelService.onDidPanelOpen(() => this.refreshReplElements(true))); this._register(this.debugService.onDidNewSession(() => this.updateTitleArea())); this._register(this.themeService.onThemeChange(() => { if (this.isVisible()) { @@ -263,15 +262,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.refreshReplElements(session.getReplElements().length === 0); }); - if (this.tree && this.isVisible() && this.tree.getInput() !== session) { + if (this.tree && this.tree.getInput() !== session) { this.tree.setInput(session); } } this.replInput.updateOptions({ readOnly: this.isReadonly }); - if (this.isVisible()) { - this.updateInputDecoration(); - } + this.updateInputDecoration(); } clearRepl(): void { From 6e6a67a53d665bba574b31ef1e9ea468612ae00e Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 9 Oct 2018 12:53:14 +0200 Subject: [PATCH 50/76] repl: better code grouping --- .../parts/debug/electron-browser/repl.ts | 247 +++++++++--------- 1 file changed, 127 insertions(+), 120 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index d2fe3e0f6ee..c7152b34dc8 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -19,7 +19,6 @@ import { Context as SuggestContext } from 'vs/editor/contrib/suggest/suggest'; import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { ITextModel } from 'vs/editor/common/model'; import { Position } from 'vs/editor/common/core/position'; -import * as modes from 'vs/editor/common/modes'; import { registerEditorAction, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions'; import { IModelService } from 'vs/editor/common/services/modelService'; import { MenuId } from 'vs/platform/actions/common/actions'; @@ -50,6 +49,7 @@ import { IDecorationOptions } from 'vs/editor/common/editorCommon'; import { transparent, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { FocusSessionActionItem } from 'vs/workbench/parts/debug/browser/debugActionItems'; +import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'vs/editor/common/modes'; const $ = dom.$; @@ -74,12 +74,11 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati _serviceBrand: any; private static readonly HALF_WIDTH_TYPICAL = 'n'; - - private history: HistoryNavigator; private static readonly REFRESH_DELAY = 500; // delay in ms to refresh the repl for new elements to show private static readonly REPL_INPUT_INITIAL_HEIGHT = 19; private static readonly REPL_INPUT_MAX_HEIGHT = 170; + private history: HistoryNavigator; private tree: ITree; private renderer: ReplExpressionsRenderer; private container: HTMLElement; @@ -126,44 +125,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati })); } - private refreshReplElements(noDelay: boolean): void { - if (this.tree && this.isVisible()) { - if (this.refreshTimeoutHandle) { - return; // refresh already triggered - } - - const delay = noDelay ? 0 : Repl.REFRESH_DELAY; - this.refreshTimeoutHandle = setTimeout(() => { - this.refreshTimeoutHandle = null; - const previousScrollPosition = this.tree.getScrollPosition(); - this.tree.refresh().then(() => { - if (previousScrollPosition === 1) { - // Only scroll if we were scrolled all the way down before tree refreshed #10486 - this.tree.setScrollPosition(1); - } - }, errors.onUnexpectedError); - }, delay); - } - } - - async create(parent: HTMLElement): Promise { - await super.create(parent); - this.container = dom.append(parent, $('.repl')); - this.treeContainer = dom.append(this.container, $('.repl-tree')); - this.createReplInput(this.container); - - this.renderer = this.instantiationService.createInstance(ReplExpressionsRenderer); - const controller = this.instantiationService.createInstance(ReplExpressionsController, new ReplExpressionsActionProvider(this.clearReplAction, this.replInput), MenuId.DebugConsoleContext, { openMode: OpenMode.SINGLE_CLICK, clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change, to preserve focus behaviour in input field */ }); - controller.toFocusOnClick = this.replInput; - - this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, { - dataSource: new ReplExpressionsDataSource(), - renderer: this.renderer, - accessibilityProvider: new ReplExpressionsAccessibilityProvider(), - controller - }, replTreeOptions); - } - setVisible(visible: boolean): Promise { if (!visible) { dispose(this.model); @@ -180,58 +141,22 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati return super.setVisible(visible); } - private createReplInput(container: HTMLElement): void { - this.replInputContainer = dom.append(container, $('.repl-input-wrapper')); + get isReadonly(): boolean { + // Do not allow to edit inactive sessions + const session: IDebugSession = this.tree.getInput(); + if (session && session.state !== State.Inactive) { + return false; + } - const { scopedContextKeyService, historyNavigationEnablement } = createAndBindHistoryNavigationWidgetScopedContextKeyService(this.contextKeyService, { target: this.replInputContainer, historyNavigator: this }); - this.historyNavigationEnablement = historyNavigationEnablement; - this._register(scopedContextKeyService); - CONTEXT_IN_DEBUG_REPL.bindTo(scopedContextKeyService).set(true); + return true; + } - this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( - [IContextKeyService, scopedContextKeyService], [IPrivateReplService, this])); - const options = getSimpleEditorOptions(); - options.readOnly = true; - this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); + showPreviousValue(): void { + this.navigateHistory(true); + } - modes.CompletionProviderRegistry.register({ scheme: DEBUG_SCHEME, pattern: '**/replinput', hasAccessToAllModels: true }, { - triggerCharacters: ['.'], - provideCompletionItems: (model: ITextModel, position: Position, _context: modes.CompletionContext, token: CancellationToken): Thenable => { - // Disable history navigation because up and down are used to navigate through the suggest widget - this.historyNavigationEnablement.set(false); - - const focusedSession = this.debugService.getViewModel().focusedSession; - if (focusedSession && focusedSession.capabilities.supportsCompletionsRequest) { - - const word = this.replInput.getModel().getWordAtPosition(position); - const overwriteBefore = word ? word.word.length : 0; - const text = this.replInput.getModel().getLineContent(position.lineNumber); - const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; - const frameId = focusedStackFrame ? focusedStackFrame.frameId : undefined; - - return focusedSession.completions(frameId, text, position, overwriteBefore).then(suggestions => { - return { suggestions }; - }, err => { - return { suggestions: [] }; - }); - } - return Promise.resolve({ suggestions: [] }); - } - }); - - this._register(this.replInput.onDidScrollChange(e => { - if (!e.scrollHeightChanged) { - return; - } - this.replInputHeight = Math.max(Repl.REPL_INPUT_INITIAL_HEIGHT, Math.min(Repl.REPL_INPUT_MAX_HEIGHT, e.scrollHeight, this.dimension.height)); - this.layout(this.dimension); - })); - this._register(this.replInput.onDidChangeModelContent(() => { - this.historyNavigationEnablement.set(this.replInput.getModel().getValue() === ''); - })); - - this._register(dom.addStandardDisposableListener(this.replInputContainer, dom.EventType.FOCUS, () => dom.addClass(this.replInputContainer, 'synthetic-focus'))); - this._register(dom.addStandardDisposableListener(this.replInputContainer, dom.EventType.BLUR, () => dom.removeClass(this.replInputContainer, 'synthetic-focus'))); + showNextValue(): void { + this.navigateHistory(false); } private navigateHistory(previous: boolean): void { @@ -245,14 +170,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } - showPreviousValue(): void { - this.navigateHistory(true); - } - - showNextValue(): void { - this.navigateHistory(false); - } - selectSession(session: IDebugSession): void { if (this.replElementsChangeListener) { this.replElementsChangeListener.dispose(); @@ -316,28 +233,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.replInput.layout({ width: dimension.width - 20, height: this.replInputHeight }); } - get isReadonly(): boolean { - // Do not allow to edit inactive sessions - const session: IDebugSession = this.tree.getInput(); - if (session && session.state !== State.Inactive) { - return false; - } - - return true; - } - - @memoize - private get characterWidth(): number { - const characterWidthSurveyor = dom.append(this.container, $('.surveyor')); - characterWidthSurveyor.textContent = Repl.HALF_WIDTH_TYPICAL; - for (let i = 0; i < 10; i++) { - characterWidthSurveyor.textContent += characterWidthSurveyor.textContent; - } - characterWidthSurveyor.style.fontSize = isMacintosh ? '12px' : '14px'; - - return characterWidthSurveyor.clientWidth / characterWidthSurveyor.textContent.length; - } - focus(): void { this.replInput.focus(); } @@ -371,6 +266,19 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } + // --- Cached locals + @memoize + private get characterWidth(): number { + const characterWidthSurveyor = dom.append(this.container, $('.surveyor')); + characterWidthSurveyor.textContent = Repl.HALF_WIDTH_TYPICAL; + for (let i = 0; i < 10; i++) { + characterWidthSurveyor.textContent += characterWidthSurveyor.textContent; + } + characterWidthSurveyor.style.fontSize = isMacintosh ? '12px' : '14px'; + + return characterWidthSurveyor.clientWidth / characterWidthSurveyor.textContent.length; + } + @memoize private get selectReplAction(): SelectReplAction { return this.scopedInstantiationService.createInstance(SelectReplAction, SelectReplAction.ID, SelectReplAction.LABEL); @@ -381,6 +289,102 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati return this.scopedInstantiationService.createInstance(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL); } + // --- Creation + + async create(parent: HTMLElement): Promise { + await super.create(parent); + this.container = dom.append(parent, $('.repl')); + this.treeContainer = dom.append(this.container, $('.repl-tree')); + this.createReplInput(this.container); + + this.renderer = this.instantiationService.createInstance(ReplExpressionsRenderer); + const controller = this.instantiationService.createInstance(ReplExpressionsController, new ReplExpressionsActionProvider(this.clearReplAction, this.replInput), MenuId.DebugConsoleContext, { openMode: OpenMode.SINGLE_CLICK, clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change, to preserve focus behaviour in input field */ }); + controller.toFocusOnClick = this.replInput; + + this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, { + dataSource: new ReplExpressionsDataSource(), + renderer: this.renderer, + accessibilityProvider: new ReplExpressionsAccessibilityProvider(), + controller + }, replTreeOptions); + } + + private createReplInput(container: HTMLElement): void { + this.replInputContainer = dom.append(container, $('.repl-input-wrapper')); + + const { scopedContextKeyService, historyNavigationEnablement } = createAndBindHistoryNavigationWidgetScopedContextKeyService(this.contextKeyService, { target: this.replInputContainer, historyNavigator: this }); + this.historyNavigationEnablement = historyNavigationEnablement; + this._register(scopedContextKeyService); + CONTEXT_IN_DEBUG_REPL.bindTo(scopedContextKeyService).set(true); + + this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( + [IContextKeyService, scopedContextKeyService], [IPrivateReplService, this])); + const options = getSimpleEditorOptions(); + options.readOnly = true; + this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); + + CompletionProviderRegistry.register({ scheme: DEBUG_SCHEME, pattern: '**/replinput', hasAccessToAllModels: true }, { + triggerCharacters: ['.'], + provideCompletionItems: (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken): Thenable => { + // Disable history navigation because up and down are used to navigate through the suggest widget + this.historyNavigationEnablement.set(false); + + const focusedSession = this.debugService.getViewModel().focusedSession; + if (focusedSession && focusedSession.capabilities.supportsCompletionsRequest) { + + const word = this.replInput.getModel().getWordAtPosition(position); + const overwriteBefore = word ? word.word.length : 0; + const text = this.replInput.getModel().getLineContent(position.lineNumber); + const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; + const frameId = focusedStackFrame ? focusedStackFrame.frameId : undefined; + + return focusedSession.completions(frameId, text, position, overwriteBefore).then(suggestions => { + return { suggestions }; + }, err => { + return { suggestions: [] }; + }); + } + return Promise.resolve({ suggestions: [] }); + } + }); + + this._register(this.replInput.onDidScrollChange(e => { + if (!e.scrollHeightChanged) { + return; + } + this.replInputHeight = Math.max(Repl.REPL_INPUT_INITIAL_HEIGHT, Math.min(Repl.REPL_INPUT_MAX_HEIGHT, e.scrollHeight, this.dimension.height)); + this.layout(this.dimension); + })); + this._register(this.replInput.onDidChangeModelContent(() => { + this.historyNavigationEnablement.set(this.replInput.getModel().getValue() === ''); + })); + + this._register(dom.addStandardDisposableListener(this.replInputContainer, dom.EventType.FOCUS, () => dom.addClass(this.replInputContainer, 'synthetic-focus'))); + this._register(dom.addStandardDisposableListener(this.replInputContainer, dom.EventType.BLUR, () => dom.removeClass(this.replInputContainer, 'synthetic-focus'))); + } + + // --- Update + + private refreshReplElements(noDelay: boolean): void { + if (this.tree && this.isVisible()) { + if (this.refreshTimeoutHandle) { + return; // refresh already triggered + } + + const delay = noDelay ? 0 : Repl.REFRESH_DELAY; + this.refreshTimeoutHandle = setTimeout(() => { + this.refreshTimeoutHandle = null; + const previousScrollPosition = this.tree.getScrollPosition(); + this.tree.refresh().then(() => { + if (previousScrollPosition === 1) { + // Only scroll if we were scrolled all the way down before tree refreshed #10486 + this.tree.setScrollPosition(1); + } + }, errors.onUnexpectedError); + }, delay); + } + } + private updateInputDecoration(): void { if (!this.replInput) { return; @@ -409,6 +413,9 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati dispose(): void { this.replInput.dispose(); + if (this.replElementsChangeListener) { + this.replElementsChangeListener.dispose(); + } super.dispose(); } } From 1f83a8d105ca9c99f496c5cf26a32e9f905cae01 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 9 Oct 2018 13:06:46 +0200 Subject: [PATCH 51/76] debugSession: simplify return types where not used --- src/vs/workbench/parts/debug/common/debug.ts | 22 ++++----- .../parts/debug/common/debugModel.ts | 2 +- .../debug/electron-browser/debugSession.ts | 46 +++++++++---------- .../parts/debug/test/common/mockDebug.ts | 22 ++++----- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index addce369d6c..3ae4ba92f13 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -183,13 +183,13 @@ export interface IDebugSession extends ITreeElement { initialize(dbgr: IDebugger): TPromise; launchOrAttach(config: IConfig): TPromise; - restart(): TPromise; + restart(): TPromise; terminate(restart?: boolean /* false */): TPromise; disconnect(restart?: boolean /* false */): TPromise; sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): TPromise; sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): TPromise; - sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): TPromise; + sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): TPromise; stackTrace(threadId: number, startFrame: number, levels: number): TPromise; exceptionInfo(threadId: number): TPromise; @@ -198,15 +198,15 @@ export interface IDebugSession extends ITreeElement { evaluate(expression: string, frameId?: number, context?: string): TPromise; customRequest(request: string, args: any): TPromise; - restartFrame(frameId: number, threadId: number): TPromise; - next(threadId: number): TPromise; - stepIn(threadId: number): TPromise; - stepOut(threadId: number): TPromise; - stepBack(threadId: number): TPromise; - continue(threadId: number): TPromise; - reverseContinue(threadId: number): TPromise; - pause(threadId: number): TPromise; - terminateThreads(threadIds: number[]): TPromise; + restartFrame(frameId: number, threadId: number): TPromise; + next(threadId: number): TPromise; + stepIn(threadId: number): TPromise; + stepOut(threadId: number): TPromise; + stepBack(threadId: number): TPromise; + continue(threadId: number): TPromise; + reverseContinue(threadId: number): TPromise; + pause(threadId: number): TPromise; + terminateThreads(threadIds: number[]): TPromise; completions(frameId: number, text: string, position: Position, overwriteBefore: number): TPromise; setVariable(variablesReference: number, name: string, value: string): TPromise; diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 27eb3321270..fff0e7352d5 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -376,7 +376,7 @@ export class StackFrame implements IStackFrame { }); } - public restart(): TPromise { + public restart(): TPromise { return this.thread.session.restartFrame(this.frameId, this.thread.threadId); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts index bb9731a3d7c..096260921cc 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugSession.ts @@ -165,7 +165,7 @@ export class DebugSession implements IDebugSession { supportsVariablePaging: true, // #9537 supportsRunInTerminalRequest: true, // #10574 locale: platform.locale - }).then(response => { + }).then(() => { this.model.addSession(this); this._onDidChangeState.fire(); this.model.setExceptionBreakpoints(this.raw.capabilities.exceptionBreakpointFilters); @@ -223,9 +223,9 @@ export class DebugSession implements IDebugSession { /** * restart debug adapter session */ - restart(): TPromise { + restart(): TPromise { if (this.raw) { - return this.raw.restart(); + return this.raw.restart().then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } @@ -293,10 +293,10 @@ export class DebugSession implements IDebugSession { return Promise.reject(new Error('no debug adapter')); } - sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): TPromise { + sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): TPromise { if (this.raw) { if (this.raw.readyForBreakpoints) { - return this.raw.setExceptionBreakpoints({ filters: exbpts.map(exb => exb.filter) }); + return this.raw.setExceptionBreakpoints({ filters: exbpts.map(exb => exb.filter) }).then(() => undefined); } return Promise.resolve(null); } @@ -355,65 +355,65 @@ export class DebugSession implements IDebugSession { return Promise.reject(new Error('no debug adapter')); } - restartFrame(frameId: number, threadId: number): TPromise { + restartFrame(frameId: number, threadId: number): TPromise { if (this.raw) { - return this.raw.restartFrame({ frameId }, threadId); + return this.raw.restartFrame({ frameId }, threadId).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - next(threadId: number): TPromise { + next(threadId: number): TPromise { if (this.raw) { - return this.raw.next({ threadId }); + return this.raw.next({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - stepIn(threadId: number): TPromise { + stepIn(threadId: number): TPromise { if (this.raw) { - return this.raw.stepIn({ threadId }); + return this.raw.stepIn({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - stepOut(threadId: number): TPromise { + stepOut(threadId: number): TPromise { if (this.raw) { - return this.raw.stepOut({ threadId }); + return this.raw.stepOut({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - stepBack(threadId: number): TPromise { + stepBack(threadId: number): TPromise { if (this.raw) { - return this.raw.stepBack({ threadId }); + return this.raw.stepBack({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - continue(threadId: number): TPromise { + continue(threadId: number): TPromise { if (this.raw) { - return this.raw.continue({ threadId }); + return this.raw.continue({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - reverseContinue(threadId: number): TPromise { + reverseContinue(threadId: number): TPromise { if (this.raw) { - return this.raw.reverseContinue({ threadId }); + return this.raw.reverseContinue({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - pause(threadId: number): TPromise { + pause(threadId: number): TPromise { if (this.raw) { - return this.raw.pause({ threadId }); + return this.raw.pause({ threadId }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } - terminateThreads(threadIds?: number[]): TPromise { + terminateThreads(threadIds?: number[]): TPromise { if (this.raw) { - return this.raw.terminateThreads({ threadIds }); + return this.raw.terminateThreads({ threadIds }).then(() => undefined); } return Promise.reject(new Error('no debug adapter')); } diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 36811ef24d1..6bffd5e09fa 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -206,7 +206,7 @@ export class MockSession implements IDebugSession { launchOrAttach(config: IConfig): TPromise { throw new Error('Method not implemented.'); } - restart(): TPromise { + restart(): TPromise { throw new Error('Method not implemented.'); } sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): TPromise { @@ -215,7 +215,7 @@ export class MockSession implements IDebugSession { sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): TPromise { throw new Error('Method not implemented.'); } - sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): TPromise { + sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): TPromise { throw new Error('Method not implemented.'); } customRequest(request: string, args: any): TPromise { @@ -236,31 +236,31 @@ export class MockSession implements IDebugSession { evaluate(expression: string, frameId: number, context?: string): TPromise { throw new Error('Method not implemented.'); } - restartFrame(frameId: number, threadId: number): TPromise { + restartFrame(frameId: number, threadId: number): TPromise { throw new Error('Method not implemented.'); } - next(threadId: number): TPromise { + next(threadId: number): TPromise { throw new Error('Method not implemented.'); } - stepIn(threadId: number): TPromise { + stepIn(threadId: number): TPromise { throw new Error('Method not implemented.'); } - stepOut(threadId: number): TPromise { + stepOut(threadId: number): TPromise { throw new Error('Method not implemented.'); } - stepBack(threadId: number): TPromise { + stepBack(threadId: number): TPromise { throw new Error('Method not implemented.'); } - continue(threadId: number): TPromise { + continue(threadId: number): TPromise { throw new Error('Method not implemented.'); } - reverseContinue(threadId: number): TPromise { + reverseContinue(threadId: number): TPromise { throw new Error('Method not implemented.'); } - pause(threadId: number): TPromise { + pause(threadId: number): TPromise { throw new Error('Method not implemented.'); } - terminateThreads(threadIds: number[]): TPromise { + terminateThreads(threadIds: number[]): TPromise { throw new Error('Method not implemented.'); } setVariable(variablesReference: number, name: string, value: string): TPromise { From f4ed8a58d9b164c6f81b149d6a9e51f974f3ff57 Mon Sep 17 00:00:00 2001 From: MaxGrosshandler Date: Tue, 9 Oct 2018 06:58:18 -0500 Subject: [PATCH 52/76] include reference to the usefulness of the built-in reporting tool (#60025) Originally this was just going to be changing `Report Issues` to `Report Issue` (in VSCode, it's the singular not the plural) and I found myself appreciating the said tool and wondering why the contributing guidelines didn't mention how helpful it could be, so I wanted to remedy that --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4d8ba5500ae..46afac5dfe4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,12 +48,13 @@ Do not add your issue as a comment to an existing issue unless it's for the iden The more information you can provide, the more likely someone will be successful at reproducing the issue and finding a fix. +The built-in tool for reporting an issue, which you can access by using `Report Issue` in VS Code's Help menu, can help streamline this process by automatically providing the version of VS Code, all your installed extensions, and your system info. Additionally, the tool will search among existing issues to see if a similar issue already exists. + Please include the following with each issue: * Version of VS Code * List of extensions that you have installed. - * **Tip:** You can easily add the list of extensions by creating the issue using `Report Issues` from VS Code's Help menu * Reproducible steps (1... 2... 3...) that cause the issue From 1de8905bf5c0e26170aff0d7b3332de9f9f5ffe3 Mon Sep 17 00:00:00 2001 From: benjamenhogben Date: Tue, 9 Oct 2018 14:07:13 +0100 Subject: [PATCH 53/76] Change throwable var name --- extensions/php/snippets/php.snippets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/php/snippets/php.snippets.json b/extensions/php/snippets/php.snippets.json index f964dc42a01..1f2a07bef20 100644 --- a/extensions/php/snippets/php.snippets.json +++ b/extensions/php/snippets/php.snippets.json @@ -254,7 +254,7 @@ "body": [ "try {", "\t${1://code...}", - "} catch (${2:\\Throwable} ${3:$$t}) {", + "} catch (${2:\\Throwable} ${3:$$th}) {", "\t${4://throw $$th;}", "}" ], From c94bc234499be19db23e2cdede8fcf26f3896cff Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Oct 2018 15:24:17 +0200 Subject: [PATCH 54/76] cached data for extensions, second try --- src/vs/loader.js | 95 ++++++++++--------- .../electron-browser/extensionHost.ts | 3 +- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/vs/loader.js b/src/vs/loader.js index 04a325a8874..4f44a01db19 100644 --- a/src/vs/loader.js +++ b/src/vs/loader.js @@ -19,10 +19,11 @@ *--------------------------------------------------------------------------------------------- *--------------------------------------------------------------------------------------------*/ var _amdLoaderGlobal = this; +var _commonjsGlobal = typeof global === 'object' ? global : {}; var AMDLoader; (function (AMDLoader) { AMDLoader.global = _amdLoaderGlobal; - var Environment = /** @class */ (function () { + var Environment = (function () { function Environment() { this._detected = false; this._isWindows = false; @@ -93,7 +94,7 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - var LoaderEvent = /** @class */ (function () { + var LoaderEvent = (function () { function LoaderEvent(type, detail, timestamp) { this.type = type; this.detail = detail; @@ -102,7 +103,7 @@ var AMDLoader; return LoaderEvent; }()); AMDLoader.LoaderEvent = LoaderEvent; - var LoaderEventRecorder = /** @class */ (function () { + var LoaderEventRecorder = (function () { function LoaderEventRecorder(loaderAvailableTimestamp) { this._events = [new LoaderEvent(1 /* LoaderAvailable */, '', loaderAvailableTimestamp)]; } @@ -115,7 +116,7 @@ var AMDLoader; return LoaderEventRecorder; }()); AMDLoader.LoaderEventRecorder = LoaderEventRecorder; - var NullLoaderEventRecorder = /** @class */ (function () { + var NullLoaderEventRecorder = (function () { function NullLoaderEventRecorder() { } NullLoaderEventRecorder.prototype.record = function (type, detail) { @@ -124,9 +125,9 @@ var AMDLoader; NullLoaderEventRecorder.prototype.getEvents = function () { return []; }; - NullLoaderEventRecorder.INSTANCE = new NullLoaderEventRecorder(); return NullLoaderEventRecorder; }()); + NullLoaderEventRecorder.INSTANCE = new NullLoaderEventRecorder(); AMDLoader.NullLoaderEventRecorder = NullLoaderEventRecorder; })(AMDLoader || (AMDLoader = {})); /*--------------------------------------------------------------------------------------------- @@ -135,7 +136,7 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - var Utilities = /** @class */ (function () { + var Utilities = (function () { function Utilities() { } /** @@ -221,11 +222,11 @@ var AMDLoader; } return (this.HAS_PERFORMANCE_NOW ? AMDLoader.global.performance.now() : Date.now()); }; - Utilities.NEXT_ANONYMOUS_ID = 1; - Utilities.PERFORMANCE_NOW_PROBED = false; - Utilities.HAS_PERFORMANCE_NOW = false; return Utilities; }()); + Utilities.NEXT_ANONYMOUS_ID = 1; + Utilities.PERFORMANCE_NOW_PROBED = false; + Utilities.HAS_PERFORMANCE_NOW = false; AMDLoader.Utilities = Utilities; })(AMDLoader || (AMDLoader = {})); /*--------------------------------------------------------------------------------------------- @@ -234,7 +235,7 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - var ConfigurationOptionsUtil = /** @class */ (function () { + var ConfigurationOptionsUtil = (function () { function ConfigurationOptionsUtil() { } /** @@ -343,7 +344,7 @@ var AMDLoader; return ConfigurationOptionsUtil; }()); AMDLoader.ConfigurationOptionsUtil = ConfigurationOptionsUtil; - var Configuration = /** @class */ (function () { + var Configuration = (function () { function Configuration(env, options) { this._env = env; this.options = ConfigurationOptionsUtil.mergeConfigurationOptions(options); @@ -554,7 +555,7 @@ var AMDLoader; /** * Load `scriptSrc` only once (avoid multiple