From 891b8c0bf0b747170ffe35e22b61f6db3b78277b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 19 Apr 2016 12:31:10 -0700 Subject: [PATCH 001/255] Integrated terminal prototype Part of #143 --- package.json | 2 + .../parts/terminal/common/terminal.ts | 20 +++++ .../node/media/terminal.contribution.css | 43 +++++++++ .../workbench/parts/terminal/node/pty.js.d.ts | 16 ++++ .../parts/terminal/node/term.js.d.ts | 17 ++++ .../terminal/node/terminal.contribution.ts | 51 +++++++++++ .../parts/terminal/node/terminalActions.ts | 37 ++++++++ .../parts/terminal/node/terminalPanel.ts | 89 +++++++++++++++++++ .../parts/terminal/node/terminalService.ts | 21 +++++ src/vs/workbench/workbench.main.js | 2 + 10 files changed, 298 insertions(+) create mode 100644 src/vs/workbench/parts/terminal/common/terminal.ts create mode 100644 src/vs/workbench/parts/terminal/node/media/terminal.contribution.css create mode 100644 src/vs/workbench/parts/terminal/node/pty.js.d.ts create mode 100644 src/vs/workbench/parts/terminal/node/term.js.d.ts create mode 100644 src/vs/workbench/parts/terminal/node/terminal.contribution.ts create mode 100644 src/vs/workbench/parts/terminal/node/terminalActions.ts create mode 100644 src/vs/workbench/parts/terminal/node/terminalPanel.ts create mode 100644 src/vs/workbench/parts/terminal/node/terminalService.ts diff --git a/package.json b/package.json index 4a72af69404..40770133839 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,10 @@ "https-proxy-agent": "^0.3.5", "iconv-lite": "^0.4.13", "native-keymap": "^0.1.2", + "pty.js": "^0.3.0", "sax": "^1.1.1", "semver": "^4.2.0", + "term.js": "0.0.7", "vscode-debugprotocol": "1.8.0-pre.3", "vscode-textmate": "^1.0.11", "winreg": "0.0.12", diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts new file mode 100644 index 00000000000..9fbb0644ecd --- /dev/null +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * 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 {TPromise} from 'vs/base/common/winjs.base'; +import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; + +export const TERMINAL_PANEL_ID = 'workbench.panel.terminal'; + +export const TERMINAL_SERVICE_ID = 'terminalService'; + +export var ITerminalService = createDecorator(TERMINAL_SERVICE_ID); + +export interface ITerminalService { + serviceId: ServiceIdentifier; + + show(): TPromise; +} diff --git a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css new file mode 100644 index 00000000000..ed76aefc063 --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .integrated-terminal { + align-items: flex-end; + display: flex; +} + +.monaco-workbench .integrated-terminal .terminal { + background-color: #1e1e1e!important; +} + +.monaco-workbench .terminal-cursor { + background-color: #1e1e1e; +} + +.monaco-workbench .reverse-video { + color: #CCC; +} + +.vs-dark .monaco-workbench .terminal-cursor { + background-color: #CCC; +} + +.vs-dark .monaco-workbench .reverse-video { + color: #252526; +} + +/* High Contrast Theming */ + +.hc-dark .monaco-workbench .integrated-terminal .terminal { + background-color: black!important; +} + +.hc-dark .monaco-workbench .terminal-cursor { + background-color: white; +} + +.hc-dark .monaco-workbench .reverse-video { + color: black; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/node/pty.js.d.ts b/src/vs/workbench/parts/terminal/node/pty.js.d.ts new file mode 100644 index 00000000000..0c44c428c51 --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/pty.js.d.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'pty.js' { + export function fork(file: string, args: string[], options: any): Terminal; + export function spawn(file: string, args: string[], options: any): Terminal; + export function createTerminal(file: string, args: string[], options: any): Terminal; + + export interface Terminal { + on(event: string, callback: (data: any) => void): void; + resize(columns: number, rows: number): void; + write(data: string): void; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/node/term.js.d.ts b/src/vs/workbench/parts/terminal/node/term.js.d.ts new file mode 100644 index 00000000000..9f2c4c7ea9e --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/term.js.d.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'term.js' { + function init(): TermJsTerminal; + + // There seems to be no way to export this so it can be referenced outside of this file when a + // module is a function. + interface TermJsTerminal { + on(event: string, callback: (data: any) => void): void; + resize(columns: number, rows: number): void; + } + + export = init; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts new file mode 100644 index 00000000000..3360a59d19a --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/terminal.contribution'; +import nls = require('vs/nls'); +//import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; +import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; +import {registerSingleton} from 'vs/platform/instantiation/common/extensions'; +import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; +import {TerminalService} from 'vs/workbench/parts/terminal/node/terminalService'; +import {ToggleTerminalAction} from 'vs/workbench/parts/terminal/node/terminalActions'; +import {ITerminalService, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; +import * as panel from 'vs/workbench/browser/panel'; +import {Registry} from 'vs/platform/platform'; +import {Extensions, IConfigurationRegistry} from 'vs/platform/configuration/common/configurationRegistry'; + +let configurationRegistry = Registry.as(Extensions.Configuration); +configurationRegistry.registerConfiguration({ + 'id': 'terminal', + 'order': 100, + 'title': nls.localize('integratedTerminalConfigurationTitle', "Integrated terminal configuration"), + 'type': 'object', + 'properties': { + 'terminal.integrated.enabled': { + 'description': nls.localize('terminal.integrated.enabled', "(Experimental) Enable the integrated terminal."), + 'type': 'boolean', + 'default': false + } + } +}); + +// Register Service +registerSingleton(ITerminalService, TerminalService); + +// Register Output Panel +(Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( + 'vs/workbench/parts/terminal/node/terminalPanel', + 'TerminalPanel', + TERMINAL_PANEL_ID, + nls.localize('terminal', "Terminal"), + 'terminal' +)); + +// register toggle output action globally +let actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); +/*actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK +}), nls.localize('viewCategory', "View"));*/ +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), nls.localize('viewCategory', "View")); diff --git a/src/vs/workbench/parts/terminal/node/terminalActions.ts b/src/vs/workbench/parts/terminal/node/terminalActions.ts new file mode 100644 index 00000000000..a260a2d5a51 --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/terminalActions.ts @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import {TPromise} from 'vs/base/common/winjs.base'; +import nls = require('vs/nls'); +import {Action} from 'vs/base/common/actions'; +import {IPartService} from 'vs/workbench/services/part/common/partService'; +import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; +import {TERMINAL_PANEL_ID, ITerminalService} from 'vs/workbench/parts/terminal/common/terminal'; + +export class ToggleTerminalAction extends Action { + + public static ID = 'workbench.action.terminal.toggleTerminal'; + public static LABEL = nls.localize('toggleTerminal', "Toggle Terminal"); + + constructor( + id: string, label: string, + @IPartService private partService: IPartService, + @IPanelService private panelService: IPanelService, + @ITerminalService private terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): TPromise { + const panel = this.panelService.getActivePanel(); + if (panel && panel.getId() === TERMINAL_PANEL_ID) { + this.partService.setPanelHidden(true); + + return TPromise.as(null); + } + + return this.terminalService.show(); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts new file mode 100644 index 00000000000..cebb5b15bf5 --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import termJs = require('term.js'); +import fs = require('fs'); +import {fork, Terminal} from 'pty.js'; +import {TPromise} from 'vs/base/common/winjs.base'; +import {Builder, Dimension} from 'vs/base/browser/builder'; +import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; +import {TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; +import {Panel} from 'vs/workbench/browser/panel'; +import {ScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElementImpl'; +import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable'; + +const TERMINAL_CHAR_WIDTH = 8; +const TERMINAL_CHAR_HEIGHT = 18; + +export class TerminalPanel extends Panel { + + private ptyProcess: Terminal; + private parentDomElement: HTMLElement; + private terminal; + private terminalDomElement: HTMLDivElement; + + constructor( + @ITelemetryService telemetryService: ITelemetryService + ) { + super(TERMINAL_PANEL_ID, telemetryService); + } + + public layout(dimension: Dimension): void { + let cols = Math.floor(this.parentDomElement.offsetWidth / TERMINAL_CHAR_WIDTH); + let rows = Math.floor(this.parentDomElement.offsetHeight / TERMINAL_CHAR_HEIGHT); + this.terminal.resize(cols, rows); + this.ptyProcess.resize(cols, rows); + } + + public create(parent: Builder): TPromise { + super.create(parent); + + this.ptyProcess = fork(process.env.SHELL || 'sh', [], { + name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', + cols: 80, + rows: 6, + cwd: process.env.HOME + }); + this.parentDomElement = parent.getHTMLElement(); + this.terminalDomElement = document.createElement('div'); + this.parentDomElement.classList.add('integrated-terminal'); + let terminalScrollable = new DomNodeScrollable(this.terminalDomElement); + let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' }); + this.terminal = termJs(); + + this.ptyProcess.on('data', (data) => { + this.terminal.write(data); + }); + this.terminal.on('data', (data) => { + this.ptyProcess.write(data); + return false; + }); + + this.terminal.open(this.terminalDomElement); + this.parentDomElement.appendChild(terminalContainer.getDomNode()); + + this.terminalDomElement.style.fontFamily = 'Hack, mono'; + this.terminal.colors = [ + '#000000', // black + '#cd3131', // red + '#09885a', // green + '#e5e510', // yellow + '#0451a5', // blue + '#bc05bc', // magenta + '#0598bc', // cyan + '#e5e5e5', // white + '#111111', // bright black + '#dc6f6f', // bright red + '#53ac8c', // bright green + '#eded58', // bright yellow + '#4f85c0', // bright blue + '#d050d0', // bright magenta + '#50b7d0', // bright cyan + '#FFFFFF', // bright white + ]; + + return TPromise.as(null); + } +} diff --git a/src/vs/workbench/parts/terminal/node/terminalService.ts b/src/vs/workbench/parts/terminal/node/terminalService.ts new file mode 100644 index 00000000000..7d5c3837d96 --- /dev/null +++ b/src/vs/workbench/parts/terminal/node/terminalService.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import {TPromise} from 'vs/base/common/winjs.base'; +import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; +import {ITerminalService, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; + +export class TerminalService implements ITerminalService { + public serviceId = ITerminalService; + + constructor( + @IPanelService private panelService: IPanelService + ) { + } + + public show(): TPromise { + return this.panelService.openPanel(TERMINAL_PANEL_ID, true); + } +} \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.js b/src/vs/workbench/workbench.main.js index ffa5618f20c..77b25bd7d31 100644 --- a/src/vs/workbench/workbench.main.js +++ b/src/vs/workbench/workbench.main.js @@ -58,6 +58,8 @@ define([ 'vs/workbench/parts/output/browser/output.contribution', + 'vs/workbench/parts/terminal/node/terminal.contribution', + 'vs/workbench/parts/markdown/browser/markdown.contribution', 'vs/workbench/parts/markdown/browser/markdownActions.contribution', From ae6bc331969c94ae2df0ff2d7aad3ecfdb4d615f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 19 Apr 2016 14:09:59 -0700 Subject: [PATCH 002/255] Set dep to pty.js@0.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6cd11bdafee..6c9fe0fbfda 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "https-proxy-agent": "0.3.6", "iconv-lite": "0.4.13", "native-keymap": "0.1.2", - "pty.js": "^0.3.0", + "pty.js": "0.3.0", "sax": "1.1.2", "semver": "4.3.6", "term.js": "0.0.7", From 49f20e3d5745c4af35072ee539a4336592daead9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 23 Apr 2016 23:06:15 -0700 Subject: [PATCH 003/255] Support customizable integrated terminal shell --- .../parts/terminal/common/terminal.ts | 16 ++++++++++++++++ .../terminal/node/terminal.contribution.ts | 19 ++++++++++++------- .../parts/terminal/node/terminalPanel.ts | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 9fbb0644ecd..98ed11c002c 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -6,13 +6,29 @@ import {TPromise} from 'vs/base/common/winjs.base'; import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; +import path = require('path'); +import platform = require('vs/base/common/platform'); export const TERMINAL_PANEL_ID = 'workbench.panel.terminal'; export const TERMINAL_SERVICE_ID = 'terminalService'; +export const TERMINAL_DEFAULT_SHELL_UNIX_LIKE = process.env.SHELL || 'sh'; +export const TERMINAL_DEFAULT_SHELL_WINDOWS = platform.isWindows ? path.resolve(process.env.SystemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe') : ''; + export var ITerminalService = createDecorator(TERMINAL_SERVICE_ID); +export interface ITerminalConfiguration { + terminal: { + integrated: { + shell: { + unixLike: string, + windows: string + } + } + }; +} + export interface ITerminalService { serviceId: ServiceIdentifier; diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts index 3360a59d19a..5380e31b95a 100644 --- a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts @@ -11,7 +11,7 @@ import {registerSingleton} from 'vs/platform/instantiation/common/extensions'; import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; import {TerminalService} from 'vs/workbench/parts/terminal/node/terminalService'; import {ToggleTerminalAction} from 'vs/workbench/parts/terminal/node/terminalActions'; -import {ITerminalService, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; +import {ITerminalService, TERMINAL_PANEL_ID, TERMINAL_DEFAULT_SHELL_UNIX_LIKE, TERMINAL_DEFAULT_SHELL_WINDOWS} from 'vs/workbench/parts/terminal/common/terminal'; import * as panel from 'vs/workbench/browser/panel'; import {Registry} from 'vs/platform/platform'; import {Extensions, IConfigurationRegistry} from 'vs/platform/configuration/common/configurationRegistry'; @@ -20,13 +20,18 @@ let configurationRegistry = Registry.as(Extensions.Confi configurationRegistry.registerConfiguration({ 'id': 'terminal', 'order': 100, - 'title': nls.localize('integratedTerminalConfigurationTitle', "Integrated terminal configuration"), + 'title': nls.localize('integratedTerminalConfigurationTitle', "(Experimental) Integrated terminal configuration"), 'type': 'object', 'properties': { - 'terminal.integrated.enabled': { - 'description': nls.localize('terminal.integrated.enabled', "(Experimental) Enable the integrated terminal."), - 'type': 'boolean', - 'default': false + 'terminal.integrated.shell.unixLike': { + 'description': nls.localize('terminal.integrated.shell.unixLike', "The path to the shell the terminal uses on Unix-like systems (Linux, OS X)."), + 'type': 'string', + 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE + }, + 'terminal.integrated.shell.windows': { + 'description': nls.localize('terminal.integrated.shell.windows', "The path to the shell the terminal uses on Windows."), + 'type': 'string', + 'default': TERMINAL_DEFAULT_SHELL_WINDOWS } } }); @@ -48,4 +53,4 @@ let actionRegistry = Registry.as(ActionExtensions.Work /*actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK }), nls.localize('viewCategory', "View"));*/ -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), nls.localize('viewCategory', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), nls.localize('viewCategory', "View"), ['terminal', 'panel']); diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index cebb5b15bf5..fcf73f783f7 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -6,10 +6,12 @@ import termJs = require('term.js'); import fs = require('fs'); import {fork, Terminal} from 'pty.js'; +import platform = require('vs/base/common/platform'); import {TPromise} from 'vs/base/common/winjs.base'; import {Builder, Dimension} from 'vs/base/browser/builder'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; -import {TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; +import {ITerminalConfiguration, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; import {Panel} from 'vs/workbench/browser/panel'; import {ScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElementImpl'; import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable'; @@ -25,6 +27,7 @@ export class TerminalPanel extends Panel { private terminalDomElement: HTMLDivElement; constructor( + @IConfigurationService private configurationService: IConfigurationService, @ITelemetryService telemetryService: ITelemetryService ) { super(TERMINAL_PANEL_ID, telemetryService); @@ -40,7 +43,7 @@ export class TerminalPanel extends Panel { public create(parent: Builder): TPromise { super.create(parent); - this.ptyProcess = fork(process.env.SHELL || 'sh', [], { + this.ptyProcess = fork(this.getShell(), [], { name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', cols: 80, rows: 6, @@ -86,4 +89,12 @@ export class TerminalPanel extends Panel { return TPromise.as(null); } + + private getShell(): string { + let config = this.configurationService.getConfiguration(); + if (platform.isWindows) { + return config.terminal.integrated.shell.windows; + } + return config.terminal.integrated.shell.unixLike; + } } From 8e013351701c7835d9ed6302ea4370b46ce2987e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 23 Apr 2016 23:39:28 -0700 Subject: [PATCH 004/255] Fix errors from merge --- .../parts/terminal/node/terminal.contribution.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts index 5380e31b95a..e7af77311ca 100644 --- a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts @@ -24,12 +24,12 @@ configurationRegistry.registerConfiguration({ 'type': 'object', 'properties': { 'terminal.integrated.shell.unixLike': { - 'description': nls.localize('terminal.integrated.shell.unixLike', "The path to the shell the terminal uses on Unix-like systems (Linux, OS X)."), + 'description': nls.localize('terminal.integrated.shell.unixLike', "The path to the shell that the terminal uses on Unix-like systems (Linux, OS X)."), 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE }, 'terminal.integrated.shell.windows': { - 'description': nls.localize('terminal.integrated.shell.windows', "The path to the shell the terminal uses on Windows."), + 'description': nls.localize('terminal.integrated.shell.windows', "The path to the shell that the terminal uses on Windows."), 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_WINDOWS } @@ -48,9 +48,7 @@ registerSingleton(ITerminalService, TerminalService); 'terminal' )); -// register toggle output action globally +// Register toggle output action globally let actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -/*actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK -}), nls.localize('viewCategory', "View"));*/ -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), nls.localize('viewCategory', "View"), ['terminal', 'panel']); +// { primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK } +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), 'View: ToggleTerminalAction.LABEL', nls.localize('viewCategory', "View")); From fb71f0447863082eeb6b66a9a4bbb7e93bda1701 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 23 Apr 2016 23:41:27 -0700 Subject: [PATCH 005/255] Fix alias, :lipstick: --- .../parts/terminal/node/terminal.contribution.ts | 10 +++++----- .../workbench/parts/terminal/node/terminalActions.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts index e7af77311ca..5b0d300747a 100644 --- a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts @@ -23,13 +23,13 @@ configurationRegistry.registerConfiguration({ 'title': nls.localize('integratedTerminalConfigurationTitle', "(Experimental) Integrated terminal configuration"), 'type': 'object', 'properties': { - 'terminal.integrated.shell.unixLike': { - 'description': nls.localize('terminal.integrated.shell.unixLike', "The path to the shell that the terminal uses on Unix-like systems (Linux, OS X)."), + 'integratedTerminal.shell.unixLike': { + 'description': nls.localize('terminal.integrated.shell.unixLike', "The path of the shell that the terminal uses on Linux and OS X."), 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE }, - 'terminal.integrated.shell.windows': { - 'description': nls.localize('terminal.integrated.shell.windows', "The path to the shell that the terminal uses on Windows."), + 'integratedTerminal.shell.windows': { + 'description': nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows."), 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_WINDOWS } @@ -51,4 +51,4 @@ registerSingleton(ITerminalService, TerminalService); // Register toggle output action globally let actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); // { primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK } -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), 'View: ToggleTerminalAction.LABEL', nls.localize('viewCategory', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), 'View: ' + ToggleTerminalAction.LABEL, nls.localize('viewCategory', "View")); diff --git a/src/vs/workbench/parts/terminal/node/terminalActions.ts b/src/vs/workbench/parts/terminal/node/terminalActions.ts index a260a2d5a51..aa332ca2234 100644 --- a/src/vs/workbench/parts/terminal/node/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/node/terminalActions.ts @@ -13,7 +13,7 @@ import {TERMINAL_PANEL_ID, ITerminalService} from 'vs/workbench/parts/terminal/c export class ToggleTerminalAction extends Action { public static ID = 'workbench.action.terminal.toggleTerminal'; - public static LABEL = nls.localize('toggleTerminal', "Toggle Terminal"); + public static LABEL = nls.localize('toggleTerminal', "(Experimental) Toggle Terminal"); constructor( id: string, label: string, From 111e6153c4fa3f26762a0da08b4272d9a3216186 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 01:06:15 -0700 Subject: [PATCH 006/255] Support custom colors for ansi escape sequences --- .../parts/terminal/common/terminal.ts | 28 +++++-- .../terminal/node/terminal.contribution.ts | 84 ++++++++++++++++++- .../parts/terminal/node/terminalPanel.ts | 46 +++++----- 3 files changed, 130 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 98ed11c002c..5420f41aff8 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -19,12 +19,28 @@ export const TERMINAL_DEFAULT_SHELL_WINDOWS = platform.isWindows ? path.resolve( export var ITerminalService = createDecorator(TERMINAL_SERVICE_ID); export interface ITerminalConfiguration { - terminal: { - integrated: { - shell: { - unixLike: string, - windows: string - } + integratedTerminal: { + shell: { + unixLike: string, + windows: string + }, + ansiColors: { + black: string, + red: string, + green: string, + yellow: string, + blue: string, + magenta: string, + cyan: string, + white: string, + brightBlack: string, + brightRed: string, + brightGreen: string, + brightYellow: string, + brightBlue: string, + brightMagenta: string, + brightCyan: string, + brightWhite: string, } }; } diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts index 5b0d300747a..d56192488fb 100644 --- a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts @@ -24,14 +24,94 @@ configurationRegistry.registerConfiguration({ 'type': 'object', 'properties': { 'integratedTerminal.shell.unixLike': { - 'description': nls.localize('terminal.integrated.shell.unixLike', "The path of the shell that the terminal uses on Linux and OS X."), + 'description': nls.localize('integratedTerminal.shell.unixLike', "The path of the shell that the terminal uses on Linux and OS X."), 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE }, 'integratedTerminal.shell.windows': { - 'description': nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows."), + 'description': nls.localize('integratedTerminal.shell.windows', "The path of the shell that the terminal uses on Windows."), 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_WINDOWS + }, + 'integratedTerminal.ansiColors.black': { + 'description': nls.localize('integratedTerminal.ansiColors.black', "Black color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#000000' + }, + 'integratedTerminal.ansiColors.red': { + 'description': nls.localize('integratedTerminal.ansiColors.red', "Red color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#cd3131' + }, + 'integratedTerminal.ansiColors.green': { + 'description': nls.localize('integratedTerminal.ansiColors.green', "Green color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#09885a' + }, + 'integratedTerminal.ansiColors.yellow': { + 'description': nls.localize('integratedTerminal.ansiColors.yellow', "Yellow color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e510' + }, + 'integratedTerminal.ansiColors.blue': { + 'description': nls.localize('integratedTerminal.ansiColors.blue', "Blue color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0451a5' + }, + 'integratedTerminal.ansiColors.magenta': { + 'description': nls.localize('integratedTerminal.ansiColors.magenta', "Magenta color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#bc05bc' + }, + 'integratedTerminal.ansiColors.cyan': { + 'description': nls.localize('integratedTerminal.ansiColors.cyan', "Cyan color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0598bc' + }, + 'integratedTerminal.ansiColors.white': { + 'description': nls.localize('integratedTerminal.ansiColors.white', "White color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e5e5' + }, + 'integratedTerminal.ansiColors.brightBlack': { + 'description': nls.localize('integratedTerminal.ansiColors.brightBlack', "Bright black color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#000000' + }, + 'integratedTerminal.ansiColors.brightRed': { + 'description': nls.localize('integratedTerminal.ansiColors.brightRed', "Bright red color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#cd3131' + }, + 'integratedTerminal.ansiColors.brightGreen': { + 'description': nls.localize('integratedTerminal.ansiColors.brightGreen', "Bright green color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#09885a' + }, + 'integratedTerminal.ansiColors.brightYellow': { + 'description': nls.localize('integratedTerminal.ansiColors.brightYellow', "Bright yellow color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e510' + }, + 'integratedTerminal.ansiColors.brightBlue': { + 'description': nls.localize('integratedTerminal.ansiColors.brightBlue', "Bright blue color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0451a5' + }, + 'integratedTerminal.ansiColors.brightMagenta': { + 'description': nls.localize('integratedTerminal.ansiColors.brightMagenta', "Bright magenta color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#bc05bc' + }, + 'integratedTerminal.ansiColors.brightCyan': { + 'description': nls.localize('integratedTerminal.ansiColors.brightCyan', "Bright cyan color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0598bc' + }, + 'integratedTerminal.ansiColors.brightWhite': { + 'description': nls.localize('integratedTerminal.ansiColors.brightWhite', "Bright white color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e5e5' } } }); diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index fcf73f783f7..2e7f4cae0f0 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -68,24 +68,7 @@ export class TerminalPanel extends Panel { this.parentDomElement.appendChild(terminalContainer.getDomNode()); this.terminalDomElement.style.fontFamily = 'Hack, mono'; - this.terminal.colors = [ - '#000000', // black - '#cd3131', // red - '#09885a', // green - '#e5e510', // yellow - '#0451a5', // blue - '#bc05bc', // magenta - '#0598bc', // cyan - '#e5e5e5', // white - '#111111', // bright black - '#dc6f6f', // bright red - '#53ac8c', // bright green - '#eded58', // bright yellow - '#4f85c0', // bright blue - '#d050d0', // bright magenta - '#50b7d0', // bright cyan - '#FFFFFF', // bright white - ]; + this.terminal.colors = this.getTerminalColors(); return TPromise.as(null); } @@ -93,8 +76,31 @@ export class TerminalPanel extends Panel { private getShell(): string { let config = this.configurationService.getConfiguration(); if (platform.isWindows) { - return config.terminal.integrated.shell.windows; + return config.integratedTerminal.shell.windows; } - return config.terminal.integrated.shell.unixLike; + return config.integratedTerminal.shell.unixLike; + } + + private getTerminalColors(): string[] { + let config = this.configurationService.getConfiguration().integratedTerminal.ansiColors; + let colors = [ + config.black || '#000000', + config.red || '#cd3131', + config.green || '#09885a', + config.yellow || '#e5e510', + config.blue || '#0451a5', + config.magenta || '#bc05bc', + config.cyan || '#0598bc', + config.white || '#e5e5e5', + config.brightBlack || '#111111', + config.brightRed || '#dc6f6f', + config.brightGreen || '#53ac8c', + config.brightYellow || '#eded58', + config.brightBlue || '#4f85c0', + config.brightMagenta || '#d050d0', + config.brightCyan || '#50b7d0', + config.brightWhite || '#FFFFFF' + ]; + return colors; } } From a2fa0094a0800887cfc7010d79645b8f1463f535 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 01:22:15 -0700 Subject: [PATCH 007/255] Make term chars cover entire line --- .../parts/terminal/node/media/terminal.contribution.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css index ed76aefc063..10486b5a9bb 100644 --- a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css +++ b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css @@ -8,6 +8,10 @@ display: flex; } +.monaco-workbench .integrated-terminal .terminal span { + display: inline-block; /* make terminal characters cover height of line */ +} + .monaco-workbench .integrated-terminal .terminal { background-color: #1e1e1e!important; } From 194874bb165997d32c44841ee6c235785c63eca8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 01:29:29 -0700 Subject: [PATCH 008/255] Remove redundant code --- .../parts/terminal/node/terminalPanel.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 2e7f4cae0f0..f9f3400173e 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -84,22 +84,22 @@ export class TerminalPanel extends Panel { private getTerminalColors(): string[] { let config = this.configurationService.getConfiguration().integratedTerminal.ansiColors; let colors = [ - config.black || '#000000', - config.red || '#cd3131', - config.green || '#09885a', - config.yellow || '#e5e510', - config.blue || '#0451a5', - config.magenta || '#bc05bc', - config.cyan || '#0598bc', - config.white || '#e5e5e5', - config.brightBlack || '#111111', - config.brightRed || '#dc6f6f', - config.brightGreen || '#53ac8c', - config.brightYellow || '#eded58', - config.brightBlue || '#4f85c0', - config.brightMagenta || '#d050d0', - config.brightCyan || '#50b7d0', - config.brightWhite || '#FFFFFF' + config.black, + config.red, + config.green, + config.yellow, + config.blue, + config.magenta, + config.cyan, + config.white, + config.brightBlack, + config.brightRed, + config.brightGreen, + config.brightYellow, + config.brightBlue, + config.brightMagenta, + config.brightCyan, + config.brightWhite ]; return colors; } From 7b19cc64c6c35625d49b56c5272d466a451a89d5 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 01:36:02 -0700 Subject: [PATCH 009/255] Support customizable terminal font family --- src/vs/workbench/parts/terminal/common/terminal.ts | 1 + .../workbench/parts/terminal/node/terminal.contribution.ts | 5 +++++ src/vs/workbench/parts/terminal/node/terminalPanel.ts | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 5420f41aff8..66b820c11c2 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -24,6 +24,7 @@ export interface ITerminalConfiguration { unixLike: string, windows: string }, + fontFamily: string, ansiColors: { black: string, red: string, diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts index d56192488fb..2a94b34383d 100644 --- a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/node/terminal.contribution.ts @@ -33,6 +33,11 @@ configurationRegistry.registerConfiguration({ 'type': 'string', 'default': TERMINAL_DEFAULT_SHELL_WINDOWS }, + 'integratedTerminal.fontFamily': { + 'description': nls.localize('integratedTerminal.fontFamily', "The font family used by the terminal (CSS font-family format)."), + 'type': 'string', + 'default': 'Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"' + }, 'integratedTerminal.ansiColors.black': { 'description': nls.localize('integratedTerminal.ansiColors.black', "Black color for terminals that support ANSI escape sequences (format: #rrggbb)"), 'type': 'string', diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index f9f3400173e..785c0ed073e 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -67,7 +67,8 @@ export class TerminalPanel extends Panel { this.terminal.open(this.terminalDomElement); this.parentDomElement.appendChild(terminalContainer.getDomNode()); - this.terminalDomElement.style.fontFamily = 'Hack, mono'; + let config = this.configurationService.getConfiguration(); + this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily; this.terminal.colors = this.getTerminalColors(); return TPromise.as(null); From a443f81f0fca3bfbb1fe59723bdabd8ac707a6e2 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 01:52:34 -0700 Subject: [PATCH 010/255] Use jeremyramin/term.js --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 16e4ad78843..395a21c5235 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "pty.js": "0.3.0", "sax": "1.1.2", "semver": "4.3.6", - "term.js": "0.0.7", + "term.js": "git+https://github.com/jeremyramin/term.js.git", "vscode-debugprotocol": "1.8.0-pre.3", "vscode-textmate": "1.0.11", "winreg": "1.2.0", From 11d3e047999784bba3a54dec8de14d16e4a7aa42 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 01:53:22 -0700 Subject: [PATCH 011/255] Focus terminal input if anywhere in panel is clicked --- .../parts/terminal/node/terminalPanel.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 785c0ed073e..77e494a9732 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -63,6 +63,11 @@ export class TerminalPanel extends Panel { this.ptyProcess.write(data); return false; }); + this.parentDomElement.addEventListener('mouseup', (event) => { + if (event.which !== 3) { + this.focusTerminal(); + } + }); this.terminal.open(this.terminalDomElement); this.parentDomElement.appendChild(terminalContainer.getDomNode()); @@ -74,6 +79,16 @@ export class TerminalPanel extends Panel { return TPromise.as(null); } + private focusTerminal(): void { + let text = window.getSelection().toString(); + if (!text) { + this.terminal.focus(); + if (this.terminal._textarea) { + this.terminal._textarea.focus(); + } + } + } + private getShell(): string { let config = this.configurationService.getConfiguration(); if (platform.isWindows) { From fca7837bc1cb2aa55f329bccf25f640ed57e8df1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 02:11:08 -0700 Subject: [PATCH 012/255] Fix terminal light theme colors The foreground color was not set so the editor's color was used --- .../node/media/terminal.contribution.css | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css index 10486b5a9bb..66734e11371 100644 --- a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css +++ b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css @@ -8,28 +8,25 @@ display: flex; } -.monaco-workbench .integrated-terminal .terminal span { - display: inline-block; /* make terminal characters cover height of line */ +.monaco-workbench .integrated-terminal { + background-color: #1e1e1e!important; + color: #CCC; } .monaco-workbench .integrated-terminal .terminal { background-color: #1e1e1e!important; } -.monaco-workbench .terminal-cursor { - background-color: #1e1e1e; +.monaco-workbench .integrated-terminal .terminal span { + display: inline-block; /* make terminal characters cover height of line */ } -.monaco-workbench .reverse-video { - color: #CCC; -} - -.vs-dark .monaco-workbench .terminal-cursor { +.monaco-workbench .integrated-terminal .terminal-cursor { background-color: #CCC; } -.vs-dark .monaco-workbench .reverse-video { - color: #252526; +.monaco-workbench .integrated-terminal .reverse-video { + color: #1e1e1e; } /* High Contrast Theming */ @@ -38,10 +35,10 @@ background-color: black!important; } -.hc-dark .monaco-workbench .terminal-cursor { +.hc-dark .monaco-workbench .integrated-terminal .terminal-cursor { background-color: white; } -.hc-dark .monaco-workbench .reverse-video { +.hc-dark .monaco-workbench .integrated-terminal .reverse-video { color: black; } \ No newline at end of file From 08fcd6b5a0141071c094ff16d6f2347a18a5c159 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:06:32 -0700 Subject: [PATCH 013/255] Fix terminal selection --- .../parts/terminal/node/media/terminal.contribution.css | 1 + src/vs/workbench/parts/terminal/node/term.js.d.ts | 2 +- src/vs/workbench/parts/terminal/node/terminalPanel.ts | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css index 66734e11371..1a31ddb8288 100644 --- a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css +++ b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css @@ -11,6 +11,7 @@ .monaco-workbench .integrated-terminal { background-color: #1e1e1e!important; color: #CCC; + -webkit-user-select: initial; } .monaco-workbench .integrated-terminal .terminal { diff --git a/src/vs/workbench/parts/terminal/node/term.js.d.ts b/src/vs/workbench/parts/terminal/node/term.js.d.ts index 9f2c4c7ea9e..faa6d112d7a 100644 --- a/src/vs/workbench/parts/terminal/node/term.js.d.ts +++ b/src/vs/workbench/parts/terminal/node/term.js.d.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ declare module 'term.js' { - function init(): TermJsTerminal; + function init(options: any): TermJsTerminal; // There seems to be no way to export this so it can be referenced outside of this file when a // module is a function. diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 77e494a9732..2ca313b5547 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -54,7 +54,9 @@ export class TerminalPanel extends Panel { this.parentDomElement.classList.add('integrated-terminal'); let terminalScrollable = new DomNodeScrollable(this.terminalDomElement); let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' }); - this.terminal = termJs(); + this.terminal = termJs({ + cursorBlink: false + }); this.ptyProcess.on('data', (data) => { this.terminal.write(data); From d1d8c0f1ac70bb587bd786b6e1d2924ea7217f41 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:06:50 -0700 Subject: [PATCH 014/255] Use jeremyramin/pty.js --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 395a21c5235..16460c1fe36 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "https-proxy-agent": "0.3.6", "iconv-lite": "0.4.13", "native-keymap": "0.1.2", - "pty.js": "0.3.0", + "pty.js": "git+https://github.com/jeremyramin/pty.js.git#28f2667", "sax": "1.1.2", "semver": "4.3.6", "term.js": "git+https://github.com/jeremyramin/term.js.git", From 5194caaf45534fab1956abab0d0e51c6802d0555 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:09:20 -0700 Subject: [PATCH 015/255] Fix middle click to paste on Linux when clicking on selection --- src/vs/workbench/parts/terminal/node/terminalPanel.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 2ca313b5547..468240d0c26 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -65,6 +65,13 @@ export class TerminalPanel extends Panel { this.ptyProcess.write(data); return false; }); + this.parentDomElement.addEventListener('mousedown', (event) => { + // Drop selection and focus terminal on Linux to enable middle button paste when click + // occurs on the selection itself. + if (event.which === 2 && platform.isLinux) { + this.focusTerminal(true); + } + }); this.parentDomElement.addEventListener('mouseup', (event) => { if (event.which !== 3) { this.focusTerminal(); @@ -81,9 +88,9 @@ export class TerminalPanel extends Panel { return TPromise.as(null); } - private focusTerminal(): void { + private focusTerminal(force?: boolean): void { let text = window.getSelection().toString(); - if (!text) { + if (!text || force) { this.terminal.focus(); if (this.terminal._textarea) { this.terminal._textarea.focus(); From 45753f95bfbe591c2878755f45357c2cfb91c738 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:10:42 -0700 Subject: [PATCH 016/255] Add clarifying comment --- src/vs/workbench/parts/terminal/node/terminalPanel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 468240d0c26..22371c584a6 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -55,7 +55,7 @@ export class TerminalPanel extends Panel { let terminalScrollable = new DomNodeScrollable(this.terminalDomElement); let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' }); this.terminal = termJs({ - cursorBlink: false + cursorBlink: false // term.js' blinking cursor breaks selection }); this.ptyProcess.on('data', (data) => { From 4e289c3f4d24c96712b05433099ed979b1589937 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:38:14 -0700 Subject: [PATCH 017/255] Add process title to pty.js interface --- src/vs/workbench/parts/terminal/node/pty.js.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/parts/terminal/node/pty.js.d.ts b/src/vs/workbench/parts/terminal/node/pty.js.d.ts index 0c44c428c51..25b7054d4d0 100644 --- a/src/vs/workbench/parts/terminal/node/pty.js.d.ts +++ b/src/vs/workbench/parts/terminal/node/pty.js.d.ts @@ -9,6 +9,10 @@ declare module 'pty.js' { export function createTerminal(file: string, args: string[], options: any): Terminal; export interface Terminal { + /** + * The title of the active process. + */ + process: string; on(event: string, callback: (data: any) => void): void; resize(columns: number, rows: number): void; write(data: string): void; From 1fdc39a29a7c0d93a23cce0f780447a39cbfcb9b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:44:58 -0700 Subject: [PATCH 018/255] Open terminal in the workspace root if available --- src/vs/workbench/parts/terminal/node/terminalPanel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 22371c584a6..41d1843123a 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -11,6 +11,7 @@ import {TPromise} from 'vs/base/common/winjs.base'; import {Builder, Dimension} from 'vs/base/browser/builder'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; +import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {ITerminalConfiguration, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; import {Panel} from 'vs/workbench/browser/panel'; import {ScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElementImpl'; @@ -28,7 +29,8 @@ export class TerminalPanel extends Panel { constructor( @IConfigurationService private configurationService: IConfigurationService, - @ITelemetryService telemetryService: ITelemetryService + @ITelemetryService telemetryService: ITelemetryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(TERMINAL_PANEL_ID, telemetryService); } @@ -47,7 +49,7 @@ export class TerminalPanel extends Panel { name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', cols: 80, rows: 6, - cwd: process.env.HOME + cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.path : process.env.HOME }); this.parentDomElement = parent.getHTMLElement(); this.terminalDomElement = document.createElement('div'); From deaa5f90089c5a94100042a6eab23d346bd3eb9c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 03:58:55 -0700 Subject: [PATCH 019/255] Handle exit by opening a new terminal This is temporary until multiple terminals are available. --- .../workbench/parts/terminal/node/pty.js.d.ts | 3 +++ .../parts/terminal/node/terminalPanel.ts | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/pty.js.d.ts b/src/vs/workbench/parts/terminal/node/pty.js.d.ts index 25b7054d4d0..cc726238aa2 100644 --- a/src/vs/workbench/parts/terminal/node/pty.js.d.ts +++ b/src/vs/workbench/parts/terminal/node/pty.js.d.ts @@ -13,8 +13,11 @@ declare module 'pty.js' { * The title of the active process. */ process: string; + on(event: string, callback: (data: any) => void): void; + resize(columns: number, rows: number): void; + write(data: string): void; } } \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 41d1843123a..f9d134a5fd8 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -45,13 +45,20 @@ export class TerminalPanel extends Panel { public create(parent: Builder): TPromise { super.create(parent); + this.parentDomElement = parent.getHTMLElement(); + this.createTerminal(); + + return TPromise.as(null); + } + + private createTerminal(): void { + this.parentDomElement.innerHTML = ''; this.ptyProcess = fork(this.getShell(), [], { name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', cols: 80, rows: 6, cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.path : process.env.HOME }); - this.parentDomElement = parent.getHTMLElement(); this.terminalDomElement = document.createElement('div'); this.parentDomElement.classList.add('integrated-terminal'); let terminalScrollable = new DomNodeScrollable(this.terminalDomElement); @@ -67,6 +74,13 @@ export class TerminalPanel extends Panel { this.ptyProcess.write(data); return false; }); + this.ptyProcess.on('exit', (data) => { + this.terminal.destroy(); + // TODO: When multiple terminals are supported this should do something smarter. There is + // also a weird bug here at leasy on Ubuntu 15.10 where the new terminal text does not + // repaint correctly. + this.createTerminal(); + }); this.parentDomElement.addEventListener('mousedown', (event) => { // Drop selection and focus terminal on Linux to enable middle button paste when click // occurs on the selection itself. @@ -86,8 +100,6 @@ export class TerminalPanel extends Panel { let config = this.configurationService.getConfiguration(); this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily; this.terminal.colors = this.getTerminalColors(); - - return TPromise.as(null); } private focusTerminal(force?: boolean): void { From a4c9ed7203b275b400812892e5c8a7d60a0ec2ea Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 24 Apr 2016 04:17:33 -0700 Subject: [PATCH 020/255] Fix bug where terminal output could obscure panel title --- .../parts/terminal/node/media/terminal.contribution.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css index 1a31ddb8288..ff499f7f13d 100644 --- a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css +++ b/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css @@ -12,6 +12,7 @@ background-color: #1e1e1e!important; color: #CCC; -webkit-user-select: initial; + overflow: hidden; /* prevents the terminal output being incorrectly placed over the title */ } .monaco-workbench .integrated-terminal .terminal { From bd613364a531bdce004bc58a68aa943cf8d9ab5d Mon Sep 17 00:00:00 2001 From: Dan Billingham Date: Sun, 24 Apr 2016 19:57:42 +0100 Subject: [PATCH 021/255] Added fold and unfold recursively to foldings (cmd K, cmd ]) (cmd K, cmd [) --- .../editor/contrib/folding/browser/folding.ts | 110 +++++++----------- 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 38f2590acc9..8f4e9b4bb45 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -38,6 +38,10 @@ class CollapsibleRegion { return this._isCollapsed; } + public get isExpanded(): boolean { + return !this._isCollapsed; + } + public get indent(): number { return this._indent; } @@ -475,85 +479,33 @@ export class FoldingController implements editorCommon.IEditorContribution { this.editor.revealPositionInCenterIfOutsideViewport(revealPosition); } - public unfold(): void { - let model = this.editor.getModel(); - let hasChanges = false; - let selections = this.editor.getSelections(); - let selectionsHasChanged = false; - selections.forEach((selection, index) => { - let lineNumber = selection.startLineNumber; - let surroundingUnfolded: editorCommon.IEditorRange; - for (let i = 0, len = this.decorations.length; i < len; i++) { - let dec = this.decorations[i]; - let decRange = dec.getDecorationRange(model); - if (!decRange) { - continue; - } - if (decRange.startLineNumber <= lineNumber) { - if (lineNumber <= decRange.endLineNumber) { - if (dec.isCollapsed) { - this.editor.changeDecorations(changeAccessor => { - dec.setCollapsed(false, changeAccessor); - hasChanges = true; - }); - return; - } - surroundingUnfolded = decRange; - } - } else { // decRange.startLineNumber > lineNumber - if (surroundingUnfolded && Range.containsRange(surroundingUnfolded, decRange)) { - if (dec.isCollapsed) { - this.editor.changeDecorations(changeAccessor => { - dec.setCollapsed(false, changeAccessor); - hasChanges = true; - let lineNumber = decRange.startLineNumber, column = model.getLineMaxColumn(decRange.startLineNumber); - selections[index] = selection.setEndPosition(lineNumber, column).setStartPosition(lineNumber, column); - selectionsHasChanged = true; - }); - return; - } - } else { - return; - } - } - } - }); - if (selectionsHasChanged) { - this.editor.setSelections(selections); - } - - if (hasChanges) { - this.updateHiddenAreas(selections[0].startLineNumber); - } - } - - public fold(): void { + public foldUnfold(isFold: boolean, isRecursive: boolean): void { let hasChanges = false; + const isUnfold = !isFold; let model = this.editor.getModel(); let selections = this.editor.getSelections(); selections.forEach(selection => { let lineNumber = selection.startLineNumber; - let toFold: CollapsibleRegion = null; + let endLineNumber; for (let i = 0, len = this.decorations.length; i < len; i++) { let dec = this.decorations[i]; let decRange = dec.getDecorationRange(model); if (!decRange) { continue; } - if (decRange.startLineNumber <= lineNumber) { - if (lineNumber <= decRange.endLineNumber && !dec.isCollapsed) { - toFold = dec; + if (decRange.startLineNumber >= lineNumber && (decRange.endLineNumber <= endLineNumber || typeof endLineNumber === 'undefined')) { + endLineNumber = endLineNumber || decRange.endLineNumber; + if ((dec.isExpanded && isFold) || (dec.isCollapsed && isUnfold)) { + this.editor.changeDecorations(changeAccessor => { + dec.setCollapsed(isFold, changeAccessor); + hasChanges = true; + }); + if (!isRecursive) { + return; + } } - } else { - break; } }; - if (toFold) { - this.editor.changeDecorations(changeAccessor => { - toFold.setCollapsed(true, changeAccessor); - hasChanges = true; - }); - } }); if (hasChanges) { this.updateHiddenAreas(selections[0].startLineNumber); @@ -622,7 +574,15 @@ class UnfoldAction extends FoldingAction { public static ID = 'editor.unfold'; invoke(foldingController: FoldingController): void { - foldingController.unfold(); + foldingController.foldUnfold(false, false); + } +} + +class UnFoldRecursivelyAction extends FoldingAction { + public static ID = 'editor.unFoldRecursively'; + + invoke(foldingController: FoldingController): void { + foldingController.foldUnfold(false, true); } } @@ -630,7 +590,15 @@ class FoldAction extends FoldingAction { public static ID = 'editor.fold'; invoke(foldingController: FoldingController): void { - foldingController.fold(); + foldingController.foldUnfold(true, false); + } +} + +class FoldRecursivelyAction extends FoldingAction { + public static ID = 'editor.foldRecursively'; + + invoke(foldingController: FoldingController): void { + foldingController.foldUnfold(true, true); } } @@ -674,10 +642,18 @@ CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(UnfoldActio context: ContextKey.EditorFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET }, 'Unfold')); +CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(UnFoldRecursivelyAction, UnFoldRecursivelyAction.ID, nls.localize('unFoldRecursivelyAction.label', "Unfold Recursively"), { + context: ContextKey.EditorFocus, + primary: KeyMod.chord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET) +}, 'Unfold Recursively')); CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(FoldAction, FoldAction.ID, nls.localize('foldAction.label', "Fold"), { context: ContextKey.EditorFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET }, 'Fold')); +CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(FoldRecursivelyAction, FoldRecursivelyAction.ID, nls.localize('foldRecursivelyAction.label', "Fold Recursively"), { + context: ContextKey.EditorFocus, + primary: KeyMod.chord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_OPEN_SQUARE_BRACKET) +}, 'Fold Recursively')); CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(FoldAllAction, FoldAllAction.ID, nls.localize('foldAllAction.label', "Fold All"), { context: ContextKey.EditorFocus, primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET From 2a7969edc46fecc395e91154bfc26400b97e3d53 Mon Sep 17 00:00:00 2001 From: Tom Ross Date: Tue, 26 Apr 2016 13:26:23 +0100 Subject: [PATCH 022/255] Fixed misleading description of margin CSS properties: Margin values may be negative --- src/vs/languages/css/common/services/browsers.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/languages/css/common/services/browsers.js b/src/vs/languages/css/common/services/browsers.js index ab1e928aac4..d6290209c85 100644 --- a/src/vs/languages/css/common/services/browsers.js +++ b/src/vs/languages/css/common/services/browsers.js @@ -3978,7 +3978,7 @@ exports.data ={ }, { "name": "margin", - "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top. The value may not be negative.", + "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top.", "restriction": "length, percentage", "values": [ { @@ -4010,7 +4010,7 @@ exports.data ={ }, { "name": "margin-bottom", - "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top. The value may not be negative.", + "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top.", "restriction": "length, percentage", "values": [ { @@ -4042,7 +4042,7 @@ exports.data ={ }, { "name": "margin-left", - "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top. The value may not be negative.", + "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top.", "restriction": "length, percentage", "values": [ { @@ -4052,7 +4052,7 @@ exports.data ={ }, { "name": "margin-right", - "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top. The value may not be negative.", + "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top.", "restriction": "length, percentage", "values": [ { @@ -4062,7 +4062,7 @@ exports.data ={ }, { "name": "margin-top", - "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top. The value may not be negative.", + "desc": "Shorthand property to set values the thickness of the margin area. If left is omitted, it is the same as right. If bottom is omitted it is the same as top, if right is omitted it is the same as top.", "restriction": "length, percentage", "values": [ { From 1c159bd8850a8bb3ee39c7708b68fe770d05e473 Mon Sep 17 00:00:00 2001 From: Dan Billingham Date: Tue, 26 Apr 2016 22:31:03 +0100 Subject: [PATCH 023/255] Extracted out recursive folding/unfolding into its own function as to not alter existing single folding/unfolding functionality. --- .../editor/contrib/folding/browser/folding.ts | 121 +++++++++++++++--- 1 file changed, 105 insertions(+), 16 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 8f4e9b4bb45..e63d56d5325 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -479,14 +479,99 @@ export class FoldingController implements editorCommon.IEditorContribution { this.editor.revealPositionInCenterIfOutsideViewport(revealPosition); } - public foldUnfold(isFold: boolean, isRecursive: boolean): void { + public unfold(): void { + let model = this.editor.getModel(); + let hasChanges = false; + let selections = this.editor.getSelections(); + let selectionsHasChanged = false; + selections.forEach((selection, index) => { + let lineNumber = selection.startLineNumber; + let surroundingUnfolded: editorCommon.IEditorRange; + for (let i = 0, len = this.decorations.length; i < len; i++) { + let dec = this.decorations[i]; + let decRange = dec.getDecorationRange(model); + if (!decRange) { + continue; + } + if (decRange.startLineNumber <= lineNumber) { + if (lineNumber <= decRange.endLineNumber) { + if (dec.isCollapsed) { + this.editor.changeDecorations(changeAccessor => { + dec.setCollapsed(false, changeAccessor); + hasChanges = true; + }); + return; + } + surroundingUnfolded = decRange; + } + } else { // decRange.startLineNumber > lineNumber + if (surroundingUnfolded && Range.containsRange(surroundingUnfolded, decRange)) { + if (dec.isCollapsed) { + this.editor.changeDecorations(changeAccessor => { + dec.setCollapsed(false, changeAccessor); + hasChanges = true; + let lineNumber = decRange.startLineNumber, column = model.getLineMaxColumn(decRange.startLineNumber); + selections[index] = selection.setEndPosition(lineNumber, column).setStartPosition(lineNumber, column); + selectionsHasChanged = true; + }); + return; + } + } else { + return; + } + } + } + }); + if (selectionsHasChanged) { + this.editor.setSelections(selections); + } + + if (hasChanges) { + this.updateHiddenAreas(selections[0].startLineNumber); + } + } + + public fold(): void { let hasChanges = false; - const isUnfold = !isFold; let model = this.editor.getModel(); let selections = this.editor.getSelections(); selections.forEach(selection => { let lineNumber = selection.startLineNumber; - let endLineNumber; + let toFold: CollapsibleRegion = null; + for (let i = 0, len = this.decorations.length; i < len; i++) { + let dec = this.decorations[i]; + let decRange = dec.getDecorationRange(model); + if (!decRange) { + continue; + } + if (decRange.startLineNumber <= lineNumber) { + if (lineNumber <= decRange.endLineNumber && !dec.isCollapsed) { + toFold = dec; + } + } else { + break; + } + }; + if (toFold) { + this.editor.changeDecorations(changeAccessor => { + toFold.setCollapsed(true, changeAccessor); + hasChanges = true; + }); + } + }); + if (hasChanges) { + this.updateHiddenAreas(selections[0].startLineNumber); + } + } + + public foldUnfoldRecursively(isFold: boolean): void { + let hasChanges = false; + let model = this.editor.getModel(); + let selections = this.editor.getSelections(); + selections.forEach(selection => { + let lineNumber = selection.startLineNumber; + let endLineNumber: number; + let decToFoldUnfold: CollapsibleRegion[] = []; for (let i = 0, len = this.decorations.length; i < len; i++) { let dec = this.decorations[i]; let decRange = dec.getDecorationRange(model); @@ -494,18 +579,22 @@ export class FoldingController implements editorCommon.IEditorContribution { continue; } if (decRange.startLineNumber >= lineNumber && (decRange.endLineNumber <= endLineNumber || typeof endLineNumber === 'undefined')) { - endLineNumber = endLineNumber || decRange.endLineNumber; - if ((dec.isExpanded && isFold) || (dec.isCollapsed && isUnfold)) { - this.editor.changeDecorations(changeAccessor => { - dec.setCollapsed(isFold, changeAccessor); - hasChanges = true; - }); - if (!isRecursive) { - return; - } + //Protect against cursor not being in decoration and lower decoration folding/unfolding + if (decRange.startLineNumber !== lineNumber && typeof endLineNumber === 'undefined') { + return; } + endLineNumber = endLineNumber || decRange.endLineNumber; + decToFoldUnfold.push(dec); } }; + if (decToFoldUnfold.length > 0) { + decToFoldUnfold.forEach(dec => { + this.editor.changeDecorations(changeAccessor => { + dec.setCollapsed(isFold, changeAccessor); + hasChanges = true; + }); + }); + } }); if (hasChanges) { this.updateHiddenAreas(selections[0].startLineNumber); @@ -574,7 +663,7 @@ class UnfoldAction extends FoldingAction { public static ID = 'editor.unfold'; invoke(foldingController: FoldingController): void { - foldingController.foldUnfold(false, false); + foldingController.unfold(); } } @@ -582,7 +671,7 @@ class UnFoldRecursivelyAction extends FoldingAction { public static ID = 'editor.unFoldRecursively'; invoke(foldingController: FoldingController): void { - foldingController.foldUnfold(false, true); + foldingController.foldUnfoldRecursively(false); } } @@ -590,7 +679,7 @@ class FoldAction extends FoldingAction { public static ID = 'editor.fold'; invoke(foldingController: FoldingController): void { - foldingController.foldUnfold(true, false); + foldingController.fold(); } } @@ -598,7 +687,7 @@ class FoldRecursivelyAction extends FoldingAction { public static ID = 'editor.foldRecursively'; invoke(foldingController: FoldingController): void { - foldingController.foldUnfold(true, true); + foldingController.foldUnfoldRecursively(true); } } From 6c3c3d38125efacb7ffcd9f8c1d09d2e867a9223 Mon Sep 17 00:00:00 2001 From: Yuki Ueda Date: Thu, 12 May 2016 19:30:35 +0900 Subject: [PATCH 024/255] fix #6290 --- extensions/html/package.json | 2 +- src/vs/languages/html/common/html.contribution.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/html/package.json b/extensions/html/package.json index 1e7ea9c1173..b126b1f8f48 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -6,7 +6,7 @@ "contributes": { "languages": [{ "id": "html", - "extensions": [ ".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm" ], + "extensions": [ ".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm", ".vue" ], "aliases": [ "HTML", "htm", "html", "xhtml" ], "mimetypes": ["text/html", "text/x-jshtm", "text/template", "text/ng-template", "application/xhtml+xml"] }], diff --git a/src/vs/languages/html/common/html.contribution.ts b/src/vs/languages/html/common/html.contribution.ts index 83652a91437..07b3045ba91 100644 --- a/src/vs/languages/html/common/html.contribution.ts +++ b/src/vs/languages/html/common/html.contribution.ts @@ -11,7 +11,7 @@ import ConfigurationRegistry = require('vs/platform/configuration/common/configu ModesRegistry.registerCompatMode({ id: 'html', - extensions: ['.html', '.htm', '.shtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm'], + extensions: ['.html', '.htm', '.shtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm', '.vue'], aliases: ['HTML', 'htm', 'html', 'xhtml'], mimetypes: ['text/html', 'text/x-jshtm', 'text/template', 'text/ng-template'], moduleId: 'vs/languages/html/common/html', From 186094c7240ee1721352e3137c63906fb179dd5e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 12 May 2016 10:47:01 -0700 Subject: [PATCH 025/255] Use correct path on Windows --- src/vs/workbench/parts/terminal/node/terminalPanel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index f9d134a5fd8..93ee7cc86eb 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -57,7 +57,7 @@ export class TerminalPanel extends Panel { name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', cols: 80, rows: 6, - cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.path : process.env.HOME + cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.fsPath : process.env.HOME }); this.terminalDomElement = document.createElement('div'); this.parentDomElement.classList.add('integrated-terminal'); From a0bda2e0cb0797bbcb7382917641ba31666a0eff Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 12 May 2016 22:20:30 +0200 Subject: [PATCH 026/255] External grammar injections --- src/vs/editor/node/textMate/TMSyntax.ts | 22 +++++++++++++++++-- .../editor/node/textMate/vscode-textmate.d.ts | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/node/textMate/TMSyntax.ts b/src/vs/editor/node/textMate/TMSyntax.ts index 388f1ffb289..605aa2c7c6a 100644 --- a/src/vs/editor/node/textMate/TMSyntax.ts +++ b/src/vs/editor/node/textMate/TMSyntax.ts @@ -19,12 +19,13 @@ export interface ITMSyntaxExtensionPoint { language: string; scopeName: string; path: string; + injectTo: string[]; } let grammarsExtPoint = ExtensionsRegistry.registerExtensionPoint('grammars', { description: nls.localize('vscode.extension.contributes.grammars', 'Contributes textmate tokenizers.'), type: 'array', - defaultSnippets: [ { body: [{ id: '', extensions: [] }] }], + defaultSnippets: [ { body: [{ language: '{{id}}', scopeName: 'source.{{id}}', path: './syntaxes/{{id}}.tmLanguage.'}] }], items: { type: 'object', defaultSnippets: [ { body: { language: '{{id}}', scopeName: 'source.{{id}}', path: './syntaxes/{{id}}.tmLanguage.'} }], @@ -40,8 +41,16 @@ let grammarsExtPoint = ExtensionsRegistry.registerExtensionPoint { return this._scopeNameToFilePath[scopeName]; + }, + getInjections: (scopeName:string) => { + return this._injections[scopeName]; } }); this._scopeNameToFilePath = {}; + this._injections = {}; grammarsExtPoint.setHandler((extensions) => { for (let i = 0; i < extensions.length; i++) { @@ -84,6 +98,10 @@ export class MainProcessTextMateSyntax { collector.error(nls.localize('invalid.path.0', "Expected string in `contributes.{0}.path`. Provided value: {1}", grammarsExtPoint.name, String(syntax.path))); return; } + if (syntax.injectTo && (!Array.isArray(syntax.injectTo) || syntax.injectTo.some(scope => typeof scope !== 'string'))) { + collector.error(nls.localize('invalid.injectTo', "Invalid value in `contributes.{0}.injectTo`. Must be an array of language scope names. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.injectTo))); + return; + } let normalizedAbsolutePath = paths.normalize(paths.join(extensionFolderPath, syntax.path)); if (normalizedAbsolutePath.indexOf(extensionFolderPath) !== 0) { diff --git a/src/vs/editor/node/textMate/vscode-textmate.d.ts b/src/vs/editor/node/textMate/vscode-textmate.d.ts index 7fa8bf6e728..9a61ada1bdd 100644 --- a/src/vs/editor/node/textMate/vscode-textmate.d.ts +++ b/src/vs/editor/node/textMate/vscode-textmate.d.ts @@ -10,6 +10,7 @@ declare module "vscode-textmate" { */ export interface IGrammarLocator { getFilePath(scopeName:string): string; + getInjections(scopeName:string): string[]; } /** From 695ae2ba4165a069f5708e668ac14bfd2f89d275 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 10:28:25 -0700 Subject: [PATCH 027/255] Use platformio's pty.js --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8cb04e544c7..7ad2657beaf 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,10 @@ "iconv-lite": "0.4.13", "minimist": "^1.2.0", "native-keymap": "0.1.2", - "pty.js": "git+https://github.com/jeremyramin/pty.js.git#28f2667", + "pty.js": "https://github.com/platformio/pty.js/tarball/22e84bd6ef177c7c211a767564ffe64426cb8a69", "sax": "1.1.2", "semver": "4.3.6", - "term.js": "git+https://github.com/jeremyramin/term.js.git", + "term.js": "https://github.com/jeremyramin/term.js/tarball/master", "vscode-debugprotocol": "1.8.0-pre.3", "vscode-textmate": "1.0.11", "winreg": "1.2.0", From 5cb353c381dd7603476c13b9d9c7b5fef706df73 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 10:28:38 -0700 Subject: [PATCH 028/255] Add dependencies to npm-shrinkwrap.json --- npm-shrinkwrap.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 2e50b73ddde..24d23415030 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -340,6 +340,11 @@ "from": "preserve@>=0.2.0 <0.3.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz" }, + "pty.js": { + "version": "0.3.0", + "from": "https://github.com/platformio/pty.js/tarball/22e84bd6ef177c7c211a767564ffe64426cb8a69", + "resolved": "https://github.com/platformio/pty.js/tarball/22e84bd6ef177c7c211a767564ffe64426cb8a69" + }, "randomatic": { "version": "1.1.5", "from": "randomatic@>=1.1.3 <2.0.0", @@ -390,6 +395,11 @@ "from": "string_decoder@>=0.10.0 <0.11.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" }, + "term.js": { + "version": "0.0.7", + "from": "https://github.com/jeremyramin/term.js/tarball/master", + "resolved": "https://github.com/jeremyramin/term.js/tarball/master" + }, "typechecker": { "version": "2.0.8", "from": "typechecker@>=2.0.1 <2.1.0", From 18d11591a925805278a368f73f74dc306fc76c3d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 10:59:14 -0700 Subject: [PATCH 029/255] Fix integrated terminal scrollbar after merge --- .../workbench/parts/terminal/node/terminalPanel.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index 93ee7cc86eb..ace17784b3a 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -14,8 +14,8 @@ import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {ITerminalConfiguration, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; import {Panel} from 'vs/workbench/browser/panel'; -import {ScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElementImpl'; -import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable'; +import {DomScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions'; const TERMINAL_CHAR_WIDTH = 8; const TERMINAL_CHAR_HEIGHT = 18; @@ -61,8 +61,12 @@ export class TerminalPanel extends Panel { }); this.terminalDomElement = document.createElement('div'); this.parentDomElement.classList.add('integrated-terminal'); - let terminalScrollable = new DomNodeScrollable(this.terminalDomElement); - let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' }); + let terminalScrollable = new DomScrollableElement(this.terminalDomElement, { + canUseTranslate3d: false, + horizontal: ScrollbarVisibility.Hidden, + vertical: ScrollbarVisibility.Auto + }); + //let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' }); this.terminal = termJs({ cursorBlink: false // term.js' blinking cursor breaks selection }); @@ -95,7 +99,7 @@ export class TerminalPanel extends Panel { }); this.terminal.open(this.terminalDomElement); - this.parentDomElement.appendChild(terminalContainer.getDomNode()); + this.parentDomElement.appendChild(terminalScrollable.getDomNode()); let config = this.configurationService.getConfiguration(); this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily; From 18d8a43f859a6805788d8190cff1913cacae8a14 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 11:00:20 -0700 Subject: [PATCH 030/255] Remove initial col and row as it's immediately overridden --- src/vs/workbench/parts/terminal/node/terminalPanel.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/node/terminalPanel.ts index ace17784b3a..54192b00377 100644 --- a/src/vs/workbench/parts/terminal/node/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/node/terminalPanel.ts @@ -55,8 +55,6 @@ export class TerminalPanel extends Panel { this.parentDomElement.innerHTML = ''; this.ptyProcess = fork(this.getShell(), [], { name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', - cols: 80, - rows: 6, cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.fsPath : process.env.HOME }); this.terminalDomElement = document.createElement('div'); From 613777fbe60fc3bba66703db53d57385419650ce Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 11:17:14 -0700 Subject: [PATCH 031/255] Move integrated terminal from node -> electron-browser --- .../media/terminal.contribution.css | 0 .../parts/terminal/{node => electron-browser}/pty.js.d.ts | 0 .../parts/terminal/{node => electron-browser}/term.js.d.ts | 0 .../{node => electron-browser}/terminal.contribution.ts | 6 +++--- .../terminal/{node => electron-browser}/terminalActions.ts | 0 .../terminal/{node => electron-browser}/terminalPanel.ts | 0 .../terminal/{node => electron-browser}/terminalService.ts | 0 src/vs/workbench/workbench.main.js | 2 +- 8 files changed, 4 insertions(+), 4 deletions(-) rename src/vs/workbench/parts/terminal/{node => electron-browser}/media/terminal.contribution.css (100%) rename src/vs/workbench/parts/terminal/{node => electron-browser}/pty.js.d.ts (100%) rename src/vs/workbench/parts/terminal/{node => electron-browser}/term.js.d.ts (100%) rename src/vs/workbench/parts/terminal/{node => electron-browser}/terminal.contribution.ts (97%) rename src/vs/workbench/parts/terminal/{node => electron-browser}/terminalActions.ts (100%) rename src/vs/workbench/parts/terminal/{node => electron-browser}/terminalPanel.ts (100%) rename src/vs/workbench/parts/terminal/{node => electron-browser}/terminalService.ts (100%) diff --git a/src/vs/workbench/parts/terminal/node/media/terminal.contribution.css b/src/vs/workbench/parts/terminal/electron-browser/media/terminal.contribution.css similarity index 100% rename from src/vs/workbench/parts/terminal/node/media/terminal.contribution.css rename to src/vs/workbench/parts/terminal/electron-browser/media/terminal.contribution.css diff --git a/src/vs/workbench/parts/terminal/node/pty.js.d.ts b/src/vs/workbench/parts/terminal/electron-browser/pty.js.d.ts similarity index 100% rename from src/vs/workbench/parts/terminal/node/pty.js.d.ts rename to src/vs/workbench/parts/terminal/electron-browser/pty.js.d.ts diff --git a/src/vs/workbench/parts/terminal/node/term.js.d.ts b/src/vs/workbench/parts/terminal/electron-browser/term.js.d.ts similarity index 100% rename from src/vs/workbench/parts/terminal/node/term.js.d.ts rename to src/vs/workbench/parts/terminal/electron-browser/term.js.d.ts diff --git a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts similarity index 97% rename from src/vs/workbench/parts/terminal/node/terminal.contribution.ts rename to src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 2a94b34383d..b8e2425cf91 100644 --- a/src/vs/workbench/parts/terminal/node/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -9,8 +9,8 @@ import nls = require('vs/nls'); import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; import {registerSingleton} from 'vs/platform/instantiation/common/extensions'; import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; -import {TerminalService} from 'vs/workbench/parts/terminal/node/terminalService'; -import {ToggleTerminalAction} from 'vs/workbench/parts/terminal/node/terminalActions'; +import {TerminalService} from 'vs/workbench/parts/terminal/electron-browser/terminalService'; +import {ToggleTerminalAction} from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import {ITerminalService, TERMINAL_PANEL_ID, TERMINAL_DEFAULT_SHELL_UNIX_LIKE, TERMINAL_DEFAULT_SHELL_WINDOWS} from 'vs/workbench/parts/terminal/common/terminal'; import * as panel from 'vs/workbench/browser/panel'; import {Registry} from 'vs/platform/platform'; @@ -126,7 +126,7 @@ registerSingleton(ITerminalService, TerminalService); // Register Output Panel (Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( - 'vs/workbench/parts/terminal/node/terminalPanel', + 'vs/workbench/parts/terminal/electron-browser/terminalPanel', 'TerminalPanel', TERMINAL_PANEL_ID, nls.localize('terminal', "Terminal"), diff --git a/src/vs/workbench/parts/terminal/node/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts similarity index 100% rename from src/vs/workbench/parts/terminal/node/terminalActions.ts rename to src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts diff --git a/src/vs/workbench/parts/terminal/node/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts similarity index 100% rename from src/vs/workbench/parts/terminal/node/terminalPanel.ts rename to src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts diff --git a/src/vs/workbench/parts/terminal/node/terminalService.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts similarity index 100% rename from src/vs/workbench/parts/terminal/node/terminalService.ts rename to src/vs/workbench/parts/terminal/electron-browser/terminalService.ts diff --git a/src/vs/workbench/workbench.main.js b/src/vs/workbench/workbench.main.js index 9a30a1160a3..45bbb116fc7 100644 --- a/src/vs/workbench/workbench.main.js +++ b/src/vs/workbench/workbench.main.js @@ -58,7 +58,7 @@ define([ 'vs/workbench/parts/output/browser/output.contribution', - 'vs/workbench/parts/terminal/node/terminal.contribution', + 'vs/workbench/parts/terminal/electron-browser/terminal.contribution', 'vs/workbench/parts/markdown/browser/markdown.contribution', 'vs/workbench/parts/markdown/browser/markdownActions.contribution', From f48a0723fc22358d4fd56cbbb15dc951daeb66da Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 11:22:41 -0700 Subject: [PATCH 032/255] Encapsulated interfaces with part/panel services in terminalService --- .../terminal/electron-browser/terminalActions.ts | 13 +------------ .../terminal/electron-browser/terminalService.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index aa332ca2234..bda26557661 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -6,9 +6,7 @@ import {TPromise} from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import {Action} from 'vs/base/common/actions'; -import {IPartService} from 'vs/workbench/services/part/common/partService'; -import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; -import {TERMINAL_PANEL_ID, ITerminalService} from 'vs/workbench/parts/terminal/common/terminal'; +import {ITerminalService} from 'vs/workbench/parts/terminal/common/terminal'; export class ToggleTerminalAction extends Action { @@ -17,21 +15,12 @@ export class ToggleTerminalAction extends Action { constructor( id: string, label: string, - @IPartService private partService: IPartService, - @IPanelService private panelService: IPanelService, @ITerminalService private terminalService: ITerminalService ) { super(id, label); } public run(event?: any): TPromise { - const panel = this.panelService.getActivePanel(); - if (panel && panel.getId() === TERMINAL_PANEL_ID) { - this.partService.setPanelHidden(true); - - return TPromise.as(null); - } - return this.terminalService.show(); } } \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts index 7d5c3837d96..b834d580627 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts @@ -5,17 +5,26 @@ import {TPromise} from 'vs/base/common/winjs.base'; import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; +import {IPartService} from 'vs/workbench/services/part/common/partService'; import {ITerminalService, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal'; export class TerminalService implements ITerminalService { public serviceId = ITerminalService; constructor( - @IPanelService private panelService: IPanelService + @IPanelService private panelService: IPanelService, + @IPartService private partService: IPartService ) { } public show(): TPromise { + const panel = this.panelService.getActivePanel(); + if (panel && panel.getId() === TERMINAL_PANEL_ID) { + this.partService.setPanelHidden(true); + + return TPromise.as(null); + } + return this.panelService.openPanel(TERMINAL_PANEL_ID, true); } } \ No newline at end of file From 55541cc58d28e308142ca59c74083d21ed4e1a46 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 11:32:49 -0700 Subject: [PATCH 033/255] Have createTerminal execute asynchronously --- .../electron-browser/terminalPanel.ts | 101 +++++++++--------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 54192b00377..0b2db776d05 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -46,62 +46,63 @@ export class TerminalPanel extends Panel { super.create(parent); this.parentDomElement = parent.getHTMLElement(); - this.createTerminal(); - return TPromise.as(null); + return this.createTerminal(); } - private createTerminal(): void { - this.parentDomElement.innerHTML = ''; - this.ptyProcess = fork(this.getShell(), [], { - name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', - cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.fsPath : process.env.HOME - }); - this.terminalDomElement = document.createElement('div'); - this.parentDomElement.classList.add('integrated-terminal'); - let terminalScrollable = new DomScrollableElement(this.terminalDomElement, { - canUseTranslate3d: false, - horizontal: ScrollbarVisibility.Hidden, - vertical: ScrollbarVisibility.Auto - }); - //let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' }); - this.terminal = termJs({ - cursorBlink: false // term.js' blinking cursor breaks selection - }); + private createTerminal(): TPromise { + return new TPromise(resolve => { + this.parentDomElement.innerHTML = ''; + this.ptyProcess = fork(this.getShell(), [], { + name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm', + cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.fsPath : process.env.HOME + }); + this.terminalDomElement = document.createElement('div'); + this.parentDomElement.classList.add('integrated-terminal'); + let terminalScrollable = new DomScrollableElement(this.terminalDomElement, { + canUseTranslate3d: false, + horizontal: ScrollbarVisibility.Hidden, + vertical: ScrollbarVisibility.Auto + }); + this.terminal = termJs({ + cursorBlink: false // term.js' blinking cursor breaks selection + }); - this.ptyProcess.on('data', (data) => { - this.terminal.write(data); - }); - this.terminal.on('data', (data) => { - this.ptyProcess.write(data); - return false; - }); - this.ptyProcess.on('exit', (data) => { - this.terminal.destroy(); - // TODO: When multiple terminals are supported this should do something smarter. There is - // also a weird bug here at leasy on Ubuntu 15.10 where the new terminal text does not - // repaint correctly. - this.createTerminal(); - }); - this.parentDomElement.addEventListener('mousedown', (event) => { - // Drop selection and focus terminal on Linux to enable middle button paste when click - // occurs on the selection itself. - if (event.which === 2 && platform.isLinux) { - this.focusTerminal(true); - } - }); - this.parentDomElement.addEventListener('mouseup', (event) => { - if (event.which !== 3) { - this.focusTerminal(); - } - }); + this.ptyProcess.on('data', (data) => { + this.terminal.write(data); + }); + this.terminal.on('data', (data) => { + this.ptyProcess.write(data); + return false; + }); + this.ptyProcess.on('exit', (data) => { + this.terminal.destroy(); + // TODO: When multiple terminals are supported this should do something smarter. There is + // also a weird bug here at leasy on Ubuntu 15.10 where the new terminal text does not + // repaint correctly. + this.createTerminal(); + }); + this.parentDomElement.addEventListener('mousedown', (event) => { + // Drop selection and focus terminal on Linux to enable middle button paste when click + // occurs on the selection itself. + if (event.which === 2 && platform.isLinux) { + this.focusTerminal(true); + } + }); + this.parentDomElement.addEventListener('mouseup', (event) => { + if (event.which !== 3) { + this.focusTerminal(); + } + }); - this.terminal.open(this.terminalDomElement); - this.parentDomElement.appendChild(terminalScrollable.getDomNode()); + this.terminal.open(this.terminalDomElement); + this.parentDomElement.appendChild(terminalScrollable.getDomNode()); - let config = this.configurationService.getConfiguration(); - this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily; - this.terminal.colors = this.getTerminalColors(); + let config = this.configurationService.getConfiguration(); + this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily; + this.terminal.colors = this.getTerminalColors(); + resolve(void 0); + }); } private focusTerminal(force?: boolean): void { From f39ca65cc35cd1d036887cde2ad1d70042c2e5bc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 11:39:15 -0700 Subject: [PATCH 034/255] Dispose terminal scrollbar and event listeners --- .../electron-browser/terminalPanel.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 0b2db776d05..8f9927186b9 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import termJs = require('term.js'); +import lifecycle = require('vs/base/common/lifecycle'); import fs = require('fs'); +import DOM = require('vs/base/browser/dom'); import {fork, Terminal} from 'pty.js'; import platform = require('vs/base/common/platform'); import {TPromise} from 'vs/base/common/winjs.base'; @@ -22,6 +24,7 @@ const TERMINAL_CHAR_HEIGHT = 18; export class TerminalPanel extends Panel { + private toDispose: lifecycle.IDisposable[]; private ptyProcess: Terminal; private parentDomElement: HTMLElement; private terminal; @@ -33,6 +36,7 @@ export class TerminalPanel extends Panel { @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(TERMINAL_PANEL_ID, telemetryService); + this.toDispose = []; } public layout(dimension: Dimension): void { @@ -59,11 +63,12 @@ export class TerminalPanel extends Panel { }); this.terminalDomElement = document.createElement('div'); this.parentDomElement.classList.add('integrated-terminal'); - let terminalScrollable = new DomScrollableElement(this.terminalDomElement, { + let terminalScrollbar = new DomScrollableElement(this.terminalDomElement, { canUseTranslate3d: false, horizontal: ScrollbarVisibility.Hidden, vertical: ScrollbarVisibility.Auto }); + this.toDispose.push(terminalScrollbar); this.terminal = termJs({ cursorBlink: false // term.js' blinking cursor breaks selection }); @@ -82,21 +87,21 @@ export class TerminalPanel extends Panel { // repaint correctly. this.createTerminal(); }); - this.parentDomElement.addEventListener('mousedown', (event) => { + this.toDispose.push(DOM.addDisposableListener(this.parentDomElement, 'mousedown', (event) => { // Drop selection and focus terminal on Linux to enable middle button paste when click // occurs on the selection itself. if (event.which === 2 && platform.isLinux) { this.focusTerminal(true); } - }); - this.parentDomElement.addEventListener('mouseup', (event) => { + })); + this.toDispose.push(DOM.addDisposableListener(this.parentDomElement, 'mouseup', (event) => { if (event.which !== 3) { this.focusTerminal(); } - }); + })); this.terminal.open(this.terminalDomElement); - this.parentDomElement.appendChild(terminalScrollable.getDomNode()); + this.parentDomElement.appendChild(terminalScrollbar.getDomNode()); let config = this.configurationService.getConfiguration(); this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily; @@ -145,4 +150,9 @@ export class TerminalPanel extends Panel { ]; return colors; } + + public dispose(): void { + this.toDispose = lifecycle.dispose(this.toDispose); + super.dispose(); + } } From 36acfe6b177614b001cb1d0cb697bcf5696085e3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 12:09:08 -0700 Subject: [PATCH 035/255] Enable integrated terminal in alpha channel only --- .../electron-browser/terminal.contribution.ts | 238 +++++++++--------- 1 file changed, 121 insertions(+), 117 deletions(-) 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 b8e2425cf91..f805c9d9714 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -5,6 +5,7 @@ import 'vs/css!./media/terminal.contribution'; import nls = require('vs/nls'); +import product from 'vs/platform/product'; //import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; import {registerSingleton} from 'vs/platform/instantiation/common/extensions'; @@ -16,124 +17,127 @@ import * as panel from 'vs/workbench/browser/panel'; import {Registry} from 'vs/platform/platform'; import {Extensions, IConfigurationRegistry} from 'vs/platform/configuration/common/configurationRegistry'; -let configurationRegistry = Registry.as(Extensions.Configuration); -configurationRegistry.registerConfiguration({ - 'id': 'terminal', - 'order': 100, - 'title': nls.localize('integratedTerminalConfigurationTitle', "(Experimental) Integrated terminal configuration"), - 'type': 'object', - 'properties': { - 'integratedTerminal.shell.unixLike': { - 'description': nls.localize('integratedTerminal.shell.unixLike', "The path of the shell that the terminal uses on Linux and OS X."), - 'type': 'string', - 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE - }, - 'integratedTerminal.shell.windows': { - 'description': nls.localize('integratedTerminal.shell.windows', "The path of the shell that the terminal uses on Windows."), - 'type': 'string', - 'default': TERMINAL_DEFAULT_SHELL_WINDOWS - }, - 'integratedTerminal.fontFamily': { - 'description': nls.localize('integratedTerminal.fontFamily', "The font family used by the terminal (CSS font-family format)."), - 'type': 'string', - 'default': 'Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"' - }, - 'integratedTerminal.ansiColors.black': { - 'description': nls.localize('integratedTerminal.ansiColors.black', "Black color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#000000' - }, - 'integratedTerminal.ansiColors.red': { - 'description': nls.localize('integratedTerminal.ansiColors.red', "Red color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#cd3131' - }, - 'integratedTerminal.ansiColors.green': { - 'description': nls.localize('integratedTerminal.ansiColors.green', "Green color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#09885a' - }, - 'integratedTerminal.ansiColors.yellow': { - 'description': nls.localize('integratedTerminal.ansiColors.yellow', "Yellow color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#e5e510' - }, - 'integratedTerminal.ansiColors.blue': { - 'description': nls.localize('integratedTerminal.ansiColors.blue', "Blue color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#0451a5' - }, - 'integratedTerminal.ansiColors.magenta': { - 'description': nls.localize('integratedTerminal.ansiColors.magenta', "Magenta color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#bc05bc' - }, - 'integratedTerminal.ansiColors.cyan': { - 'description': nls.localize('integratedTerminal.ansiColors.cyan', "Cyan color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#0598bc' - }, - 'integratedTerminal.ansiColors.white': { - 'description': nls.localize('integratedTerminal.ansiColors.white', "White color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#e5e5e5' - }, - 'integratedTerminal.ansiColors.brightBlack': { - 'description': nls.localize('integratedTerminal.ansiColors.brightBlack', "Bright black color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#000000' - }, - 'integratedTerminal.ansiColors.brightRed': { - 'description': nls.localize('integratedTerminal.ansiColors.brightRed', "Bright red color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#cd3131' - }, - 'integratedTerminal.ansiColors.brightGreen': { - 'description': nls.localize('integratedTerminal.ansiColors.brightGreen', "Bright green color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#09885a' - }, - 'integratedTerminal.ansiColors.brightYellow': { - 'description': nls.localize('integratedTerminal.ansiColors.brightYellow', "Bright yellow color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#e5e510' - }, - 'integratedTerminal.ansiColors.brightBlue': { - 'description': nls.localize('integratedTerminal.ansiColors.brightBlue', "Bright blue color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#0451a5' - }, - 'integratedTerminal.ansiColors.brightMagenta': { - 'description': nls.localize('integratedTerminal.ansiColors.brightMagenta', "Bright magenta color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#bc05bc' - }, - 'integratedTerminal.ansiColors.brightCyan': { - 'description': nls.localize('integratedTerminal.ansiColors.brightCyan', "Bright cyan color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#0598bc' - }, - 'integratedTerminal.ansiColors.brightWhite': { - 'description': nls.localize('integratedTerminal.ansiColors.brightWhite', "Bright white color for terminals that support ANSI escape sequences (format: #rrggbb)"), - 'type': 'string', - 'default': '#e5e5e5' +// Only enable in the alpha channel until more stable +if (product.quality === 'alpha') { + let configurationRegistry = Registry.as(Extensions.Configuration); + configurationRegistry.registerConfiguration({ + 'id': 'terminal', + 'order': 100, + 'title': nls.localize('integratedTerminalConfigurationTitle', "(Experimental) Integrated terminal configuration"), + 'type': 'object', + 'properties': { + 'integratedTerminal.shell.unixLike': { + 'description': nls.localize('integratedTerminal.shell.unixLike', "The path of the shell that the terminal uses on Linux and OS X."), + 'type': 'string', + 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE + }, + 'integratedTerminal.shell.windows': { + 'description': nls.localize('integratedTerminal.shell.windows', "The path of the shell that the terminal uses on Windows."), + 'type': 'string', + 'default': TERMINAL_DEFAULT_SHELL_WINDOWS + }, + 'integratedTerminal.fontFamily': { + 'description': nls.localize('integratedTerminal.fontFamily', "The font family used by the terminal (CSS font-family format)."), + 'type': 'string', + 'default': 'Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"' + }, + 'integratedTerminal.ansiColors.black': { + 'description': nls.localize('integratedTerminal.ansiColors.black', "Black color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#000000' + }, + 'integratedTerminal.ansiColors.red': { + 'description': nls.localize('integratedTerminal.ansiColors.red', "Red color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#cd3131' + }, + 'integratedTerminal.ansiColors.green': { + 'description': nls.localize('integratedTerminal.ansiColors.green', "Green color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#09885a' + }, + 'integratedTerminal.ansiColors.yellow': { + 'description': nls.localize('integratedTerminal.ansiColors.yellow', "Yellow color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e510' + }, + 'integratedTerminal.ansiColors.blue': { + 'description': nls.localize('integratedTerminal.ansiColors.blue', "Blue color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0451a5' + }, + 'integratedTerminal.ansiColors.magenta': { + 'description': nls.localize('integratedTerminal.ansiColors.magenta', "Magenta color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#bc05bc' + }, + 'integratedTerminal.ansiColors.cyan': { + 'description': nls.localize('integratedTerminal.ansiColors.cyan', "Cyan color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0598bc' + }, + 'integratedTerminal.ansiColors.white': { + 'description': nls.localize('integratedTerminal.ansiColors.white', "White color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e5e5' + }, + 'integratedTerminal.ansiColors.brightBlack': { + 'description': nls.localize('integratedTerminal.ansiColors.brightBlack', "Bright black color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#000000' + }, + 'integratedTerminal.ansiColors.brightRed': { + 'description': nls.localize('integratedTerminal.ansiColors.brightRed', "Bright red color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#cd3131' + }, + 'integratedTerminal.ansiColors.brightGreen': { + 'description': nls.localize('integratedTerminal.ansiColors.brightGreen', "Bright green color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#09885a' + }, + 'integratedTerminal.ansiColors.brightYellow': { + 'description': nls.localize('integratedTerminal.ansiColors.brightYellow', "Bright yellow color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e510' + }, + 'integratedTerminal.ansiColors.brightBlue': { + 'description': nls.localize('integratedTerminal.ansiColors.brightBlue', "Bright blue color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0451a5' + }, + 'integratedTerminal.ansiColors.brightMagenta': { + 'description': nls.localize('integratedTerminal.ansiColors.brightMagenta', "Bright magenta color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#bc05bc' + }, + 'integratedTerminal.ansiColors.brightCyan': { + 'description': nls.localize('integratedTerminal.ansiColors.brightCyan', "Bright cyan color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#0598bc' + }, + 'integratedTerminal.ansiColors.brightWhite': { + 'description': nls.localize('integratedTerminal.ansiColors.brightWhite', "Bright white color for terminals that support ANSI escape sequences (format: #rrggbb)"), + 'type': 'string', + 'default': '#e5e5e5' + } } - } -}); + }); -// Register Service -registerSingleton(ITerminalService, TerminalService); + // Register Service + registerSingleton(ITerminalService, TerminalService); -// Register Output Panel -(Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( - 'vs/workbench/parts/terminal/electron-browser/terminalPanel', - 'TerminalPanel', - TERMINAL_PANEL_ID, - nls.localize('terminal', "Terminal"), - 'terminal' -)); + // Register Output Panel + (Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( + 'vs/workbench/parts/terminal/electron-browser/terminalPanel', + 'TerminalPanel', + TERMINAL_PANEL_ID, + nls.localize('terminal', "Terminal"), + 'terminal' + )); -// Register toggle output action globally -let actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -// { primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK } -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), 'View: ' + ToggleTerminalAction.LABEL, nls.localize('viewCategory', "View")); + // Register toggle output action globally + let actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); + // { primary: KeyMod.CtrlCmd | KeyCode.US_BACKTICK } + actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL), 'View: ' + ToggleTerminalAction.LABEL, nls.localize('viewCategory', "View")); +} \ No newline at end of file From 9cff38ac885b2baf833a6346ff5fa23ac32ae2c8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 19:07:14 -0700 Subject: [PATCH 036/255] Improve external terminal support on xfce Fixes #5780 --- src/vs/workbench/parts/execution/electron-browser/terminal.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/parts/execution/electron-browser/terminal.ts b/src/vs/workbench/parts/execution/electron-browser/terminal.ts index f8651232c0b..5e7fe0e8a82 100644 --- a/src/vs/workbench/parts/execution/electron-browser/terminal.ts +++ b/src/vs/workbench/parts/execution/electron-browser/terminal.ts @@ -11,6 +11,10 @@ if (env.isLinux) { defaultTerminalLinux = 'x-terminal-emulator'; } else if (process.env.DESKTOP_SESSION === 'gnome' || process.env.DESKTOP_SESSION === 'gnome-classic') { defaultTerminalLinux = 'gnome-terminal'; + } else if (process.env.COLORTERM) { + defaultTerminalLinux = process.env.COLORTERM; + } else if (process.env.TERM) { + defaultTerminalLinux = process.env.TERM; } } From cd1d4d8f551ec3d025d60a89ee8eb1b7dff4641f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 May 2016 19:35:42 -0700 Subject: [PATCH 037/255] Clearing WorkingFilesModel should only add file types to recently closed files Fixes #5997 --- .../parts/files/common/workingFilesModel.ts | 8 ++++---- .../files/test/browser/workingFilesModel.test.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/files/common/workingFilesModel.ts b/src/vs/workbench/parts/files/common/workingFilesModel.ts index b981bb04fba..8bb487e736b 100644 --- a/src/vs/workbench/parts/files/common/workingFilesModel.ts +++ b/src/vs/workbench/parts/files/common/workingFilesModel.ts @@ -355,14 +355,14 @@ export class WorkingFilesModel implements IWorkingFilesModel { // Put the active entry on the top of the stack let input = this.editorService.getActiveEditorInput(); - let resource: uri = getUntitledOrFileResource(input); + let activeResource: uri = getUntitledOrFileResource(input); let activeEntry: WorkingFileEntry; - if (resource) { - activeEntry = this.findEntry(resource); + if (activeResource && activeResource.scheme === 'file') { + activeEntry = this.findEntry(activeResource); } this.recentlyClosedEntries = this.recentlyClosedEntries.concat(resources.filter(e => { - return !activeEntry || e.resource.path !== activeEntry.resource.path; + return (!activeEntry || e.resource.path !== activeEntry.resource.path) && e.resource.scheme === 'file'; })); if (activeEntry) { diff --git a/src/vs/workbench/parts/files/test/browser/workingFilesModel.test.ts b/src/vs/workbench/parts/files/test/browser/workingFilesModel.test.ts index e946926e65e..e43289f062e 100644 --- a/src/vs/workbench/parts/files/test/browser/workingFilesModel.test.ts +++ b/src/vs/workbench/parts/files/test/browser/workingFilesModel.test.ts @@ -116,6 +116,21 @@ suite('Files - WorkingFilesModel', () => { assert.equal(model.popLastClosedEntry(), null); }); + test("Clearing the model only adds files to the closed entries", function() { + let model = baseInstantiationService.createInstance(WorkingFilesModel); + + model.addEntry(URI.create('untitled', null, '/foo')); + assert.equal(model.popLastClosedEntry(), null); + model.clear(); + assert.equal(model.popLastClosedEntry(), null); + + model.addEntry(URI.create('file', null, '/foo')); + model.addEntry(URI.create('untitled', null, '/bar')); + model.clear(); + assert.ok(model.popLastClosedEntry().isFile); + assert.equal(model.popLastClosedEntry(), null); + }); + test("Reopening multiple files will open the editor in the previously opened file", function() { let model = baseInstantiationService.createInstance(WorkingFilesModel); From f2ff1361344bec4bfa08af359c4d5132b1d0772d Mon Sep 17 00:00:00 2001 From: J/A Date: Sat, 14 May 2016 23:03:47 -0500 Subject: [PATCH 038/255] Do not autoclose `'` `'` is used to denote a lifetime, as in `fn foo<'a>(bar: &'a Baz) { ...` and it isn't helpful to have it automatically closed. --- extensions/rust/rust.configuration.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/extensions/rust/rust.configuration.json b/extensions/rust/rust.configuration.json index e4656d0babb..34396c3121e 100644 --- a/extensions/rust/rust.configuration.json +++ b/extensions/rust/rust.configuration.json @@ -12,8 +12,7 @@ ["{", "}"], ["[", "]"], ["(", ")"], - ["\"", "\""], - ["'", "'"] + ["\"", "\""] ], "surroundingPairs": [ ["{", "}"], @@ -22,4 +21,4 @@ ["\"", "\""], ["'", "'"] ] -} \ No newline at end of file +} From 3c748fa1955ade5578df9a2f3dab922aa722ebc7 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Sun, 15 May 2016 21:03:21 +0200 Subject: [PATCH 039/255] html.ts: Typo in comment --- src/vs/languages/html/common/html.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/languages/html/common/html.ts b/src/vs/languages/html/common/html.ts index adbc95bf164..cb3679a0562 100644 --- a/src/vs/languages/html/common/html.ts +++ b/src/vs/languages/html/common/html.ts @@ -24,8 +24,8 @@ import {ParameterHintsSupport} from 'vs/editor/common/modes/supports/parameterHi import {SuggestSupport} from 'vs/editor/common/modes/supports/suggestSupport'; import {IThreadService} from 'vs/platform/thread/common/thread'; -export { htmlTokenTypes }; // export to be used by Razor. We are the main module, so Razor should get ot from use. -export { EMPTY_ELEMENTS }; // export to be used by Razor. We are the main module, so Razor should get ot from use. +export { htmlTokenTypes }; // export to be used by Razor. We are the main module, so Razor should get it from us. +export { EMPTY_ELEMENTS }; // export to be used by Razor. We are the main module, so Razor should get it from us. export enum States { Content, From 48e8164164c91f91e8085ac5305e1bb5acf23f26 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Sun, 15 May 2016 21:19:22 +0200 Subject: [PATCH 040/255] Update json.ts to latest jsonc-parser --- src/vs/base/common/json.ts | 536 ++++++++++++++---- src/vs/base/test/common/json.test.ts | 8 +- src/vs/editor/node/textMate/TMSnippets.ts | 6 +- .../json/common/jsonSchemaService.ts | 6 +- .../json/common/parser/jsonParser.ts | 2 +- src/vs/workbench/node/extensionPoints.ts | 8 +- .../themes/electron-browser/themeService.ts | 4 +- 7 files changed, 449 insertions(+), 121 deletions(-) diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index 6b578d2c8a9..fbec4a76493 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import nls = require('vs/nls'); +import {localize} from 'vs/nls'; export enum ScanError { None, @@ -35,19 +35,50 @@ export enum SyntaxKind { EOF } +/** + * The scanner object, representing a JSON scanner at a position in the input string. + */ export interface JSONScanner { + /** + * Sets the scan position to a new offset. A call to 'scan' is needed to get the first token. + */ + setPosition(pos: number); + /** + * Read the next token. Returns the tolen code. + */ scan(): SyntaxKind; + /** + * Returns the current scan position, which is after the last read token. + */ getPosition(): number; + /** + * Returns the last read token. + */ getToken(): SyntaxKind; + /** + * Returns the last read token value. The value for strings is the decoded string content. For numbers its of type number, for boolean it's true or false. + */ getTokenValue(): string; + /** + * The start offset of the last read token. + */ getTokenOffset(): number; + /** + * The length of the last read token. + */ getTokenLength(): number; + /** + * An error code of the last scan. + */ getTokenError(): ScanError; } - +/** + * Creates a JSON scanner on the given text. + * If ignoreTrivia is set, whitespaces or comments are ignored. + */ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONScanner { - var pos = 0, + let pos = 0, len = text.length, value:string = '', tokenOffset = 0, @@ -55,10 +86,10 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca scanError:ScanError = ScanError.None; function scanHexDigits(count: number, exact?: boolean): number { - var digits = 0; - var value = 0; + let digits = 0; + let value = 0; while (digits < count || !exact) { - var ch = text.charCodeAt(pos); + let ch = text.charCodeAt(pos); if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) { value = value * 16 + ch - CharacterCodes._0; } @@ -80,8 +111,16 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca return value; } + function setPosition(newPosition: number) { + pos = newPosition; + value = ''; + tokenOffset = 0; + token = SyntaxKind.Unknown; + scanError = ScanError.None; + } + function scanNumber(): string { - var start = pos; + let start = pos; if (text.charCodeAt(pos) === CharacterCodes._0) { pos++; } else { @@ -99,10 +138,10 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca } } else { scanError = ScanError.UnexpectedEndOfNumber; - return text.substring(start, end); + return text.substring(start, pos); } } - var end = pos; + let end = pos; if (pos < text.length && (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e)) { pos++; if (pos < text.length && text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) { @@ -123,7 +162,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca function scanString(): string { - var result = '', + let result = '', start = pos; while (true) { @@ -132,7 +171,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca scanError = ScanError.UnexpectedEndOfString; break; } - var ch = text.charCodeAt(pos); + let ch = text.charCodeAt(pos); if (ch === CharacterCodes.doubleQuote) { result += text.substring(start, pos); pos++; @@ -172,7 +211,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca result += '\t'; break; case CharacterCodes.u: - var ch = scanHexDigits(4, true); + let ch = scanHexDigits(4, true); if (ch >= 0) { result += String.fromCharCode(ch); } else { @@ -208,7 +247,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca return token = SyntaxKind.EOF; } - var code = text.charCodeAt(pos); + let code = text.charCodeAt(pos); // trivia: whitespace if (isWhiteSpace(code)) { do { @@ -260,7 +299,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca // comments case CharacterCodes.slash: - var start = pos - 1; + let start = pos - 1; // Single-line comment if (text.charCodeAt(pos + 1) === CharacterCodes.slash) { pos += 2; @@ -280,10 +319,10 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { pos += 2; - var safeLength = len - 1; // For lookahead. - var commentClosed = false; + let safeLength = len - 1; // For lookahead. + let commentClosed = false; while (pos < safeLength) { - var ch = text.charCodeAt(pos); + let ch = text.charCodeAt(pos); if (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { pos += 2; @@ -371,7 +410,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca function scanNextNonTrivia():SyntaxKind { - var result : SyntaxKind; + let result : SyntaxKind; do { result = scanNext(); } while (result >= SyntaxKind.LineCommentTrivia && result <= SyntaxKind.Trivia); @@ -379,6 +418,7 @@ export function createScanner(text:string, ignoreTrivia:boolean = false):JSONSca } return { + setPosition: setPosition, getPosition: () => pos, scan: ignoreTrivia ? scanNextNonTrivia : scanNext, getToken: () => token, @@ -403,10 +443,6 @@ function isDigit(ch: number): boolean { return ch >= CharacterCodes._0 && ch <= CharacterCodes._9; } -export function isLetter(ch: number): boolean { - return ch >= CharacterCodes.a && ch <= CharacterCodes.z || ch >= CharacterCodes.A && ch <= CharacterCodes.Z; -} - enum CharacterCodes { nullCharacter = 0, maxAsciiCharacter = 0x7F, @@ -552,7 +588,7 @@ enum CharacterCodes { */ export function stripComments(text:string, replaceCh?:string):string { - var _scanner = createScanner(text), + let _scanner = createScanner(text), parts: string[] = [], kind:SyntaxKind, offset = 0, @@ -579,23 +615,285 @@ export function stripComments(text:string, replaceCh?:string):string { return parts.join(''); } -export function parse(text:string, errors: string[] = []) : any { - var noMatch = Object(); - var _scanner = createScanner(text, true); +export interface ParseError { + error: ParseErrorCode; +} - function scanNext() : SyntaxKind { - var token = _scanner.scan(); - while (token === SyntaxKind.Unknown) { - handleError(nls.localize('UnknownSymbol', 'Invalid symbol')); - token = _scanner.scan(); +export enum ParseErrorCode { + InvalidSymbol, + InvalidNumberFormat, + PropertyNameExpected, + ValueExpected, + ColonExpected, + CommaExpected, + CloseBraceExpected, + CloseBracketExpected, + EndOfFileExpected +} + +export function getParseErrorMessage(errorCode: ParseErrorCode) : string { + switch (errorCode) { + case ParseErrorCode.InvalidSymbol: return localize('error.invalidSymbol', 'Invalid symbol'); + case ParseErrorCode.InvalidNumberFormat: return localize('error.invalidNumberFormat', 'Invalid number format'); + case ParseErrorCode.PropertyNameExpected: return localize('error.propertyNameExpected', 'Property name expected'); + case ParseErrorCode.ValueExpected: return localize('error.valueExpected', 'Value expected'); + case ParseErrorCode.ColonExpected: return localize('error.colonExpected', 'Colon expected'); + case ParseErrorCode.CommaExpected: return localize('error.commaExpected', 'Comma expected'); + case ParseErrorCode.CloseBraceExpected: return localize('error.closeBraceExpected', 'Closing brace expected'); + case ParseErrorCode.CloseBracketExpected: return localize('error.closeBracketExpected', 'Closing bracket expected'); + case ParseErrorCode.EndOfFileExpected: return localize('error.endOfFileExpected', 'End of file expected'); + default: + return ''; + } +} + +export type NodeType = "object" | "array" | "property" | "string" | "number" | "null"; + +export interface Node { + type: NodeType; + value: any; + offset: number; + length: number; + columnOffset?: number; +} + +export interface Location { + previousNode?: Node; + segments: string[]; + matches: (segments: string[]) => boolean; + completeProperty: boolean; +} + + +/** + * For a given offset, evaluate the location in the JSON document. Each segment in a location is either a property names or an array accessors. + */ +export function getLocation(text:string, position: number) : Location { + let segments: string[] = []; + let earlyReturnException = new Object(); + let previousNode : Node = void 0; + const previousNodeInst : Node = { + value: void 0, + offset: void 0, + length: void 0, + type: void 0 + }; + let completeProperty = false; + let hasComma = false; + function setPreviousNode(value: string, offset: number, length: number, type: NodeType) { + previousNodeInst.value = value; + previousNodeInst.offset = offset; + previousNodeInst.length = length; + previousNodeInst.type = type; + previousNodeInst.columnOffset = void 0; + previousNode = previousNodeInst; + } + try { + + visit(text, { + onObjectBegin: (offset: number, length: number) => { + if (position <= offset) { + throw earlyReturnException; + } + previousNode = void 0; + completeProperty = position > offset; + hasComma = false; + }, + onObjectProperty: (name: string, offset: number, length: number) => { + if (position < offset) { + throw earlyReturnException; + } + setPreviousNode(name, offset, length, 'property'); + hasComma = false; + segments.push(name); + if (position <= offset + length) { + throw earlyReturnException; + } + }, + onObjectEnd: (offset: number, length: number) => { + if (position <= offset) { + throw earlyReturnException; + } + previousNode = void 0; + if (!hasComma) { + segments.pop(); + } + hasComma = false; + }, + onArrayBegin: (offset: number, length: number) => { + if (position <= offset) { + throw earlyReturnException; + } + previousNode = void 0; + segments.push('[0]'); + hasComma = false; + }, + onArrayEnd: (offset: number, length: number) => { + if (position <= offset) { + throw earlyReturnException; + } + previousNode = void 0; + if (!hasComma) { + segments.pop(); + } + hasComma = false; + }, + onLiteralValue: (value: any, offset: number, length: number) => { + if (position < offset) { + throw earlyReturnException; + } + setPreviousNode(value, offset, length, value === null ? 'null' : (typeof value === 'string' ? 'string' : 'number')); + if (position <= offset + length) { + throw earlyReturnException; + } + }, + onSeparator: (sep: string, offset: number, length: number) => { + if (position <= offset) { + throw earlyReturnException; + } + if (sep === ':' && previousNode.type === 'property') { + previousNode.columnOffset = offset; + completeProperty = false; + previousNode = void 0; + } else if (sep === ',') { + let last = segments.pop(); + if (last[0] === '[' && last[last.length - 1] === ']') { + segments.push('[' + (parseInt(last.substr(1, last.length - 2)) + 1) + ']'); + } else { + completeProperty = true; + } + previousNode = void 0; + hasComma = true; + } + } + }); + } catch (e) { + if (e !== earlyReturnException) { + throw e; + } + } + return { + segments, + previousNode, + completeProperty, + matches: (pattern: string[]) => { + let k = 0; + for (let i = 0; k < pattern.length && i < segments.length; i++) { + if (pattern[k] === segments[i] || pattern[k] === '*') { + k++; + } else if (pattern[k] !== '**') { + return false; + } + } + return k === pattern.length; + } + }; +} + +export interface ParseOptions { + disallowComments?: boolean; +} + +/** + * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault lolerant as possible, but still return a result. + * Therefore always check the errors list to find out if the input was valid. + */ +export function parse(text:string, errors: ParseError[] = [], options?: ParseOptions) : any { + let currentProperty : string = null; + let currentParent : any = []; + let previousParents : any[] = []; + + function onValue(value: any) { + if (Array.isArray(currentParent)) { + ( currentParent).push(value); + } else if (currentProperty) { + currentParent[currentProperty] = value; } - return token; } - function handleError(message:string, skipUntilAfter: SyntaxKind[] = [], skipUntil: SyntaxKind[] = []) : void { - errors.push(message); + let visitor = { + onObjectBegin: () => { + let object = {}; + onValue(object); + previousParents.push(currentParent); + currentParent = object; + currentProperty = null; + }, + onObjectProperty: (name: string) => { + currentProperty = name; + }, + onObjectEnd: () => { + currentParent = previousParents.pop(); + }, + onArrayBegin: () => { + let array = []; + onValue(array); + previousParents.push(currentParent); + currentParent = array; + currentProperty = null; + }, + onArrayEnd: () => { + currentParent = previousParents.pop(); + }, + onLiteralValue: onValue, + onError:(error:ParseErrorCode) => { + errors.push({error: error}); + } + }; + visit(text, visitor, options); + return currentParent[0]; +} + +/** + * Parses the given text and invokes the visitor functions for each object, array and literal reached. + */ +export function visit(text:string, visitor: JSONVisitor, options?: ParseOptions) : any { + + let _scanner = createScanner(text, false); + + function toNoArgVisit(visitFunction: (offset: number, length: number) => void) : () => void { + return visitFunction ? () => visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true; + } + function toOneArgVisit(visitFunction: (arg: T, offset: number, length: number) => void) : (arg: T) => void { + return visitFunction ? (arg: T) => visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true; + } + + let onObjectBegin = toNoArgVisit(visitor.onObjectBegin), + onObjectProperty = toOneArgVisit(visitor.onObjectProperty), + onObjectEnd = toNoArgVisit(visitor.onObjectEnd), + onArrayBegin = toNoArgVisit(visitor.onArrayBegin), + onArrayEnd = toNoArgVisit(visitor.onArrayEnd), + onLiteralValue = toOneArgVisit(visitor.onLiteralValue), + onSeparator = toOneArgVisit(visitor.onSeparator), + onError = toOneArgVisit(visitor.onError); + + let disallowComments = options && options.disallowComments; + function scanNext() : SyntaxKind { + while (true) { + let token = _scanner.scan(); + switch (token) { + case SyntaxKind.LineCommentTrivia: + case SyntaxKind.BlockCommentTrivia: + if (disallowComments) { + handleError(ParseErrorCode.InvalidSymbol); + } + break; + case SyntaxKind.Unknown: + handleError(ParseErrorCode.InvalidSymbol); + break; + case SyntaxKind.Trivia: + case SyntaxKind.LineBreakTrivia: + break; + default: + return token; + } + } + } + + function handleError(error:ParseErrorCode, skipUntilAfter: SyntaxKind[] = [], skipUntil: SyntaxKind[] = []) : void { + onError(error); if (skipUntilAfter.length + skipUntil.length > 0) { - var token = _scanner.getToken(); + let token = _scanner.getToken(); while (token !== SyntaxKind.EOF) { if (skipUntilAfter.indexOf(token) !== -1) { scanNext(); @@ -608,156 +906,186 @@ export function parse(text:string, errors: string[] = []) : any { } } - function parseString() : any { + function parseString(isValue: boolean) : boolean { if (_scanner.getToken() !== SyntaxKind.StringLiteral) { - return noMatch; + return false; + } + let value = _scanner.getTokenValue(); + if (isValue) { + onLiteralValue(value); + } else { + onObjectProperty(value); } - var value = _scanner.getTokenValue(); scanNext(); - return value; + return true; } - function parseLiteral() : any { - var value : any; + function parseLiteral() : boolean { switch (_scanner.getToken()) { case SyntaxKind.NumericLiteral: + let value = 0; try { value = JSON.parse(_scanner.getTokenValue()); if (typeof value !== 'number') { - handleError(nls.localize('InvalidNumberFormat', 'Invalid number format')); + handleError(ParseErrorCode.InvalidNumberFormat); value = 0; } } catch (e) { - value = 0; + handleError(ParseErrorCode.InvalidNumberFormat); } + onLiteralValue(value); break; case SyntaxKind.NullKeyword: - value = null; + onLiteralValue(null); break; case SyntaxKind.TrueKeyword: - value = true; + onLiteralValue(true); break; case SyntaxKind.FalseKeyword: - value = false; + onLiteralValue(false); break; default: - return noMatch; + return false; } scanNext(); - return value; + return true; } - function parseProperty(result: any) : any { - var key = parseString(); - if (key === noMatch) { - handleError(nls.localize('PropertyExpected', 'Property name expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); + function parseProperty() : boolean { + if (!parseString(false)) { + handleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); return false; } if (_scanner.getToken() === SyntaxKind.ColonToken) { + onSeparator(':'); scanNext(); // consume colon - var value = parseValue(); - if (value !== noMatch) { - result[key] = value; - } else { - handleError(nls.localize('ValueExpected', 'Value expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); + if (!parseValue()) { + handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); } } else { - handleError(nls.localize('ColonExpected', 'Colon expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); + handleError(ParseErrorCode.ColonExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); } return true; } - function parseObject() : any { + function parseObject() : boolean { if (_scanner.getToken() !== SyntaxKind.OpenBraceToken) { - return noMatch; + return false; } - var obj = {}; + onObjectBegin(); scanNext(); // consume open brace - var needsComma = false; + let needsComma = false; while (_scanner.getToken() !== SyntaxKind.CloseBraceToken && _scanner.getToken() !== SyntaxKind.EOF) { if (_scanner.getToken() === SyntaxKind.CommaToken) { if (!needsComma) { - handleError(nls.localize('ValueExpected', 'Value expected'), [], [] ); + handleError(ParseErrorCode.ValueExpected, [], [] ); } + onSeparator(','); scanNext(); // consume comma } else if (needsComma) { - handleError(nls.localize('CommaExpected', 'Comma expected'), [], [] ); + handleError(ParseErrorCode.CommaExpected, [], [] ); } - var propertyParsed = parseProperty(obj); - if (!propertyParsed) { - handleError(nls.localize('ValueExpected', 'Value expected'), [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); + if (!parseProperty()) { + handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] ); } needsComma = true; } - + onObjectEnd(); if (_scanner.getToken() !== SyntaxKind.CloseBraceToken) { - handleError(nls.localize('CloseBraceExpected', 'Closing brace expected'), [SyntaxKind.CloseBraceToken], []); + handleError(ParseErrorCode.CloseBraceExpected, [SyntaxKind.CloseBraceToken], []); } else { scanNext(); // consume close brace } - return obj; + return true; } - function parseArray() : any { + function parseArray() : boolean { if (_scanner.getToken() !== SyntaxKind.OpenBracketToken) { - return noMatch; + return false; } - var arr: any[] = []; + onArrayBegin(); scanNext(); // consume open bracket - var needsComma = false; + let needsComma = false; while (_scanner.getToken() !== SyntaxKind.CloseBracketToken && _scanner.getToken() !== SyntaxKind.EOF) { if (_scanner.getToken() === SyntaxKind.CommaToken) { if (!needsComma) { - handleError(nls.localize('ValeExpected', 'Value expected'), [], [] ); + handleError(ParseErrorCode.ValueExpected, [], [] ); } + onSeparator(','); scanNext(); // consume comma } else if (needsComma) { - handleError(nls.localize('CommaExpected', 'Comma expected'), [], [] ); + handleError(ParseErrorCode.CommaExpected, [], [] ); } - var value = parseValue(); - if (value === noMatch) { - handleError(nls.localize('ValueExpected', 'Value expected'), [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken] ); - } else { - arr.push(value); + if (!parseValue()) { + handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken] ); } needsComma = true; } - + onArrayEnd(); if (_scanner.getToken() !== SyntaxKind.CloseBracketToken) { - handleError(nls.localize('CloseBracketExpected', 'Closing bracket expected'), [SyntaxKind.CloseBracketToken], []); + handleError(ParseErrorCode.CloseBracketExpected, [SyntaxKind.CloseBracketToken], []); } else { scanNext(); // consume close bracket } - return arr; + return true; } - function parseValue() : any { - var result = parseArray(); - if (result !== noMatch) { - return result; - } - result = parseObject(); - if (result !== noMatch) { - return result; - } - result = parseString(); - if (result !== noMatch) { - return result; - } - return parseLiteral(); + function parseValue() : boolean { + return parseArray() || parseObject() || parseString(true) || parseLiteral(); } scanNext(); - var value = parseValue(); - if (value === noMatch) { - handleError(nls.localize('ValueExpected', 'Value expected'), [], []); - return void 0; + if (!parseValue()) { + handleError(ParseErrorCode.ValueExpected, [], []); + return false; } if (_scanner.getToken() !== SyntaxKind.EOF) { - handleError(nls.localize('EOFExpected', 'End of content expected'), [], []); + handleError(ParseErrorCode.EndOfFileExpected, [], []); } - return value; + return true; } + +export interface JSONVisitor { + /** + * Invoked when an open brace is encountered and an object is started. The offset and length represent the location of the open brace. + */ + onObjectBegin?: (offset:number, length:number) => void; + + /** + * Invoked when a property is encountered. The offset and length represent the location of the property name. + */ + onObjectProperty?: (property: string, offset:number, length:number) => void; + + /** + * Invoked when a closing brace is encountered and an object is completed. The offset and length represent the location of the closing brace. + */ + onObjectEnd?: (offset:number, length:number) => void; + + /** + * Invoked when an open bracket is encountered. The offset and length represent the location of the open bracket. + */ + onArrayBegin?: (offset:number, length:number) => void; + + /** + * Invoked when a closing bracket is encountered. The offset and length represent the location of the closing bracket. + */ + onArrayEnd?: (offset:number, length:number) => void; + + /** + * Invoked when a literal value is encountered. The offset and length represent the location of the literal value. + */ + onLiteralValue?: (value: any, offset:number, length:number) => void; + + /** + * Invoked when a comma or colon separator is encountered. The offset and length represent the location of the separator. + */ + onSeparator?: (charcter: string, offset:number, length:number) => void; + + /** + * Invoked on an error. + */ + onError?: (error: ParseErrorCode, offset:number, length:number) => void; +} \ No newline at end of file diff --git a/src/vs/base/test/common/json.test.ts b/src/vs/base/test/common/json.test.ts index d0dd7e06a46..74f4211419c 100644 --- a/src/vs/base/test/common/json.test.ts +++ b/src/vs/base/test/common/json.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { SyntaxKind, createScanner, parse } from 'vs/base/common/json'; +import { SyntaxKind, createScanner, parse, ParseError, getParseErrorMessage } from 'vs/base/common/json'; function assertKinds(text:string, ...kinds:SyntaxKind[]):void { var _json = createScanner(text); @@ -18,17 +18,17 @@ function assertKinds(text:string, ...kinds:SyntaxKind[]):void { function assertValidParse(input:string, expected:any) : void { - var errors : string[] = []; + var errors : ParseError[] = []; var actual = parse(input, errors); if (errors.length !== 0) { - assert(false, errors[0]); + assert(false, getParseErrorMessage(errors[0].error)); } assert.deepEqual(actual, expected); } function assertInvalidParse(input:string, expected:any) : void { - var errors : string[] = []; + var errors : ParseError[] = []; var actual = parse(input, errors); assert(errors.length > 0); diff --git a/src/vs/editor/node/textMate/TMSnippets.ts b/src/vs/editor/node/textMate/TMSnippets.ts index d7ddd45d9d9..bef5e357c19 100644 --- a/src/vs/editor/node/textMate/TMSnippets.ts +++ b/src/vs/editor/node/textMate/TMSnippets.ts @@ -5,7 +5,7 @@ 'use strict'; import * as nls from 'vs/nls'; -import {parse} from 'vs/base/common/json'; +import {parse, ParseError} from 'vs/base/common/json'; import * as paths from 'vs/base/common/paths'; import {TPromise} from 'vs/base/common/winjs.base'; import {readFile} from 'vs/base/node/pfs'; @@ -23,7 +23,7 @@ export interface ITMSnippetsExtensionPoint { export function snippetUpdated(modeId: string, filePath: string): TPromise { return readFile(filePath).then((fileContents) => { - var errors: string[] = []; + var errors: ParseError[] = []; var snippetsObj = parse(fileContents.toString(), errors); var adaptedSnippets = TMSnippetsAdaptor.adapt(snippetsObj); SnippetsRegistry.registerSnippets(modeId, filePath, adaptedSnippets); @@ -98,7 +98,7 @@ export class MainProcessTextMateSnippet { public registerDefinition(modeId: string, filePath: string): void { readFile(filePath).then((fileContents) => { - var errors: string[] = []; + var errors: ParseError[] = []; var snippetsObj = parse(fileContents.toString(), errors); var adaptedSnippets = TMSnippetsAdaptor.adapt(snippetsObj); SnippetsRegistry.registerDefaultSnippets(modeId, adaptedSnippets); diff --git a/src/vs/languages/json/common/jsonSchemaService.ts b/src/vs/languages/json/common/jsonSchemaService.ts index e63e19bd27c..582f7066ddd 100644 --- a/src/vs/languages/json/common/jsonSchemaService.ts +++ b/src/vs/languages/json/common/jsonSchemaService.ts @@ -342,9 +342,9 @@ export class JSONSchemaService implements IJSONSchemaService { } var schemaContent: IJSONSchema = {}; - var jsonErrors = []; - schemaContent = Json.parse(content, errors); - var errors = jsonErrors.length ? [ nls.localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': {1}.', toDisplayString(url), jsonErrors[0])] : []; + var jsonErrors: Json.ParseError[] = []; + schemaContent = Json.parse(content, jsonErrors); + var errors = jsonErrors.length ? [ nls.localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': {1}.', toDisplayString(url), Json.getParseErrorMessage(jsonErrors[0].error))] : []; return new UnresolvedSchema(schemaContent, errors); }, (error : http.IXHRResponse) => { diff --git a/src/vs/languages/json/common/parser/jsonParser.ts b/src/vs/languages/json/common/parser/jsonParser.ts index df73072da3b..36f7ebce115 100644 --- a/src/vs/languages/json/common/parser/jsonParser.ts +++ b/src/vs/languages/json/common/parser/jsonParser.ts @@ -898,7 +898,7 @@ export class JSONParser { if (_scanner.getToken() === Json.SyntaxKind.Unknown) { // give a more helpful error message var value = _scanner.getTokenValue(); - if (value.length > 0 && (value.charAt(0) === '\'' || Json.isLetter(value.charAt(0).charCodeAt(0)))) { + if (value.match(/^['\w]/)) { _error(nls.localize('DoubleQuotesExpected', 'Property keys must be doublequoted')); } } diff --git a/src/vs/workbench/node/extensionPoints.ts b/src/vs/workbench/node/extensionPoints.ts index f99043133a4..94d46ceb446 100644 --- a/src/vs/workbench/node/extensionPoints.ts +++ b/src/vs/workbench/node/extensionPoints.ts @@ -83,11 +83,11 @@ abstract class ExtensionManifestHandler { class ExtensionManifestParser extends ExtensionManifestHandler { public parse(): TPromise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { - let errors: string[] = []; + let errors: json.ParseError[] = []; let extensionDescription: IExtensionDescription = json.parse(manifestContents.toString(), errors); if (errors.length > 0) { errors.forEach((error) => { - this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, error)); + this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, json.getParseErrorMessage(error.error))); }); return null; } @@ -114,11 +114,11 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { return extensionDescription; } return pfs.readFile(messageBundle).then(messageBundleContent => { - let errors: string[] = []; + let errors: json.ParseError[] = []; let messages: { [key: string]: string; } = json.parse(messageBundleContent.toString(), errors); if (errors.length > 0) { errors.forEach((error) => { - this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", messageBundle, error)); + this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", messageBundle, json.getParseErrorMessage(error.error))); }); return extensionDescription; } diff --git a/src/vs/workbench/services/themes/electron-browser/themeService.ts b/src/vs/workbench/services/themes/electron-browser/themeService.ts index 3ca2cb6e367..066593f0b65 100644 --- a/src/vs/workbench/services/themes/electron-browser/themeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/themeService.ts @@ -262,10 +262,10 @@ function applyTheme(theme: IThemeData, onApply: (themeId:string) => void): TProm function _loadThemeDocument(themePath: string) : TPromise { return pfs.readFile(themePath).then(content => { if (Paths.extname(themePath) === '.json') { - let errors: string[] = []; + let errors: Json.ParseError[] = []; let contentValue = Json.parse(content.toString(), errors); if (errors.length > 0) { - return TPromise.wrapError(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.join(', ')))); + return TPromise.wrapError(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.map(e => Json.getParseErrorMessage(e.error)).join(', ')))); } if (contentValue.include) { return _loadThemeDocument(Paths.join(Paths.dirname(themePath), contentValue.include)).then(includedValue => { From 1b31ce6babd7f20462d4c2047bd5fe6d64456687 Mon Sep 17 00:00:00 2001 From: rebornix Date: Sun, 15 May 2016 14:24:38 -0700 Subject: [PATCH 041/255] add touch screen tap support for reference search --- .../referenceSearch/browser/referencesWidget.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts index d184968b0c6..143176d21d6 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts @@ -19,6 +19,7 @@ import * as dom from 'vs/base/browser/dom'; import {Sash, ISashEvent, IVerticalSashLayoutProvider} from 'vs/base/browser/ui/sash/sash'; import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent'; import {IMouseEvent} from 'vs/base/browser/mouseEvent'; +import {GestureEvent} from 'vs/base/browser/touch'; import {CountBadge} from 'vs/base/browser/ui/countBadge/countBadge'; import {FileLabel} from 'vs/base/browser/ui/filelabel/fileLabel'; import {LeftRightWidget} from 'vs/base/browser/ui/leftRightWidget/leftRightWidget'; @@ -212,6 +213,18 @@ class Controller extends DefaultController { OPEN_TO_SIDE: 'events/custom/opentoside' }; + public onTap(tree: tree.ITree, element: any, event: GestureEvent):boolean { + if (element instanceof FileReferences) { + event.preventDefault(); + event.stopPropagation(); + return this._expandCollapse(tree, element); + } + + var result = super.onTap(tree, element, event); + tree.emit(Controller.Events.FOCUSED, element); + return result; + } + public onMouseDown(tree:tree.ITree, element:any, event:IMouseEvent):boolean { if (event.leftButton) { if (element instanceof FileReferences) { From 323dec0c511fa76cf0849cf7585096e86c3ef1b0 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 10:08:14 +0200 Subject: [PATCH 042/255] debug: reveal auto expanded element in repl fixes #6343 --- src/vs/workbench/parts/debug/browser/repl.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/repl.ts b/src/vs/workbench/parts/debug/browser/repl.ts index 5c860f6fb68..c19d92a1239 100644 --- a/src/vs/workbench/parts/debug/browser/repl.ts +++ b/src/vs/workbench/parts/debug/browser/repl.ts @@ -106,7 +106,9 @@ export class Repl extends Panel { const elements = this.debugService.getModel().getReplElements(); const lastElement = elements.length > 0 ? elements[elements.length - 1] : null; if (lastElement instanceof Expression && lastElement.reference > 0) { - return this.tree.expand(elements[elements.length - 1]); + return this.tree.expand(elements[elements.length - 1]).then(() => + this.tree.reveal(elements[elements.length - 1], 0) + ); } }, errors.onUnexpectedError); }, Repl.REFRESH_DELAY); From 60fe78cfa981f271c1930b4fbc0b4fdd91bdf8a2 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 10:21:31 +0200 Subject: [PATCH 043/255] fixes #6297 --- src/vs/workbench/parts/debug/browser/debugActionItems.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index ae050357f6f..578dfc3dd1d 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -73,7 +73,7 @@ export class SelectConfigActionItem extends BaseActionItem { if (!config || !config.configurations) { this.select.add(this.createOption(nls.localize('noConfigurations', "No Configurations"))); this.select.disabled = true; - return this.actionRunner.run(this._action, null); + return changeDebugConfiguration ? this.actionRunner.run(this._action, null) : null; } const configurations = config.configurations; From d1236f740f68a6de99523edcf94b8c182ee5e6d8 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 12:07:22 +0200 Subject: [PATCH 044/255] debug: do not trim whitespace in repl fixes #6275 --- src/vs/workbench/parts/debug/browser/media/repl.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/media/repl.css b/src/vs/workbench/parts/debug/browser/media/repl.css index 800158210ff..4c751078d84 100644 --- a/src/vs/workbench/parts/debug/browser/media/repl.css +++ b/src/vs/workbench/parts/debug/browser/media/repl.css @@ -27,9 +27,10 @@ .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content { line-height: 18px; - word-wrap: break-word; - white-space: initial; -webkit-user-select: text; + /* Wrap words but also do not trim whitespace #6275 */ + word-wrap: break-word; + white-space: pre-wrap; } .monaco-workbench .repl .repl-tree .monaco-tree-row .input.expression.mac, From 8a3a8d0f676ee4a4f11113f8f85b94962736275b Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 14:41:11 +0200 Subject: [PATCH 045/255] debug: move show more stack frames logic to call stack controller fixes #6299 --- .../parts/debug/browser/debugViewer.ts | 32 +++++++++++++++++++ .../parts/debug/browser/debugViews.ts | 15 +-------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugViewer.ts b/src/vs/workbench/parts/debug/browser/debugViewer.ts index 087e70fcbbc..1a1d5b87dea 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewer.ts @@ -193,6 +193,38 @@ export class BaseDebugController extends treedefaults.DefaultController { // call stack +export class CallStackController extends BaseDebugController { + + protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { + if (typeof element === 'number') { + return this.showMoreStackFrames(tree, element); + } + + return super.onLeftClick(tree, element, event); + } + + protected onEnter(tree: tree.ITree, event: IKeyboardEvent): boolean { + const element = tree.getFocus(); + if (typeof element === 'number') { + return this.showMoreStackFrames(tree, element); + } + + return super.onEnter(tree, event); + } + + // user clicked / pressed on 'Load More Stack Frames', get those stack frames and refresh the tree. + private showMoreStackFrames(tree: tree.ITree, threadId: number): boolean { + const thread = this.debugService.getModel().getThreads()[threadId]; + if (thread) { + thread.getCallStack(this.debugService, true) + .done(() => tree.refresh(), errors.onUnexpectedError); + } + + return true; + } +} + + export class CallStackActionProvider implements renderer.IActionProvider { constructor( @IInstantiationService private instantiationService: IInstantiationService) { diff --git a/src/vs/workbench/parts/debug/browser/debugViews.ts b/src/vs/workbench/parts/debug/browser/debugViews.ts index f86536cfb6c..30d85f69867 100644 --- a/src/vs/workbench/parts/debug/browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/browser/debugViews.ts @@ -224,7 +224,7 @@ export class CallStackView extends viewlet.CollapsibleViewletView { dataSource: this.instantiationService.createInstance(viewer.CallStackDataSource), renderer: this.instantiationService.createInstance(viewer.CallStackRenderer), accessibilityProvider: this.instantiationService.createInstance(viewer.CallstackAccessibilityProvider), - controller: new viewer.BaseDebugController(this.debugService, this.contextMenuService, actionProvider) + controller: new viewer.CallStackController(this.debugService, this.contextMenuService, actionProvider) }, debugTreeOptions(nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel'}, "Debug Call Stack"))); this.toDispose.push(this.tree.addListener2('selection', (e: tree.ISelectionEvent) => { @@ -251,19 +251,6 @@ export class CallStackView extends viewlet.CollapsibleViewletView { const sideBySide = (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)); this.debugService.openOrRevealSource(stackFrame.source, stackFrame.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError); } - - // user clicked on 'Load More Stack Frames', get those stack frames and refresh the tree. - if (typeof element === 'number') { - const thread = this.debugService.getModel().getThreads()[element]; - if (thread) { - thread.getCallStack(this.debugService, true) - .then(() => this.tree.refresh()) - .then(() => { - this.tree.clearFocus(); - this.tree.clearSelection(); - }).done(null, errors.onUnexpectedError); - } - } })); this.toDispose.push(this.tree.addListener2(events.EventType.FOCUS, (e: tree.IFocusEvent) => { From 8877119bd62fb4d4211e88cf78b1bd88f6adbe38 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 14:56:30 +0200 Subject: [PATCH 046/255] debug: move more logic to call stack controller --- .../parts/debug/browser/debugViewer.ts | 21 ++++++++++++--- .../parts/debug/browser/debugViews.ts | 26 ------------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugViewer.ts b/src/vs/workbench/parts/debug/browser/debugViewer.ts index 1a1d5b87dea..f6c5abf9726 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewer.ts @@ -13,7 +13,7 @@ import errors = require('vs/base/common/errors'); import strings = require('vs/base/common/strings'); import { isMacintosh } from 'vs/base/common/platform'; import dom = require('vs/base/browser/dom'); -import mouse = require('vs/base/browser/mouseEvent'); +import {IMouseEvent} from 'vs/base/browser/mouseEvent'; import labels = require('vs/base/common/labels'); import actions = require('vs/base/common/actions'); import actionbar = require('vs/base/browser/ui/actionbar/actionbar'); @@ -195,10 +195,13 @@ export class BaseDebugController extends treedefaults.DefaultController { export class CallStackController extends BaseDebugController { - protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { + protected onLeftClick(tree: tree.ITree, element: any, event: IMouseEvent): boolean { if (typeof element === 'number') { return this.showMoreStackFrames(tree, element); } + if (element instanceof model.StackFrame) { + this.focusStackFrame(element, event, true); + } return super.onLeftClick(tree, element, event); } @@ -208,6 +211,9 @@ export class CallStackController extends BaseDebugController { if (typeof element === 'number') { return this.showMoreStackFrames(tree, element); } + if (element instanceof model.StackFrame) { + this.focusStackFrame(element, event, false); + } return super.onEnter(tree, event); } @@ -222,6 +228,13 @@ export class CallStackController extends BaseDebugController { return true; } + + private focusStackFrame(stackFrame: debug.IStackFrame, event: IKeyboardEvent|IMouseEvent, preserveFocus: boolean): void { + this.debugService.setFocusedStackFrameAndEvaluate(stackFrame).done(null, errors.onUnexpectedError); + + const sideBySide = (event && (event.ctrlKey || event.metaKey)); + this.debugService.openOrRevealSource(stackFrame.source, stackFrame.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError); + } } @@ -804,7 +817,7 @@ export class WatchExpressionsController extends BaseDebugController { } } - protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { + protected onLeftClick(tree: tree.ITree, element: any, event: IMouseEvent): boolean { // double click on primitive value: open input box to be able to select and copy value. if (element instanceof model.Expression && event.detail === 2) { const expression = element; @@ -1088,7 +1101,7 @@ export class BreakpointsAccessibilityProvider implements tree.IAccessibilityProv export class BreakpointsController extends BaseDebugController { - protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { + protected onLeftClick(tree: tree.ITree, element: any, event: IMouseEvent): boolean { if (element instanceof model.FunctionBreakpoint && event.detail === 2) { this.debugService.getViewModel().setSelectedFunctionBreakpoint(element); return true; diff --git a/src/vs/workbench/parts/debug/browser/debugViews.ts b/src/vs/workbench/parts/debug/browser/debugViews.ts index 30d85f69867..01859dc3490 100644 --- a/src/vs/workbench/parts/debug/browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/browser/debugViews.ts @@ -227,32 +227,6 @@ export class CallStackView extends viewlet.CollapsibleViewletView { controller: new viewer.CallStackController(this.debugService, this.contextMenuService, actionProvider) }, debugTreeOptions(nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel'}, "Debug Call Stack"))); - this.toDispose.push(this.tree.addListener2('selection', (e: tree.ISelectionEvent) => { - if (!e.selection.length || !e.payload) { - // Ignore the event if it was not initated by user. - // Debug sometimes automaticaly sets the selected frame, and those events we need to ignore. - return; - } - const element = e.selection[0]; - - if (element instanceof StackFrame) { - const stackFrame = element; - this.debugService.setFocusedStackFrameAndEvaluate(stackFrame).done(null, errors.onUnexpectedError); - - const isMouse = (e.payload && e.payload.origin === 'mouse'); - let preserveFocus = isMouse; - - const originalEvent:KeyboardEvent|MouseEvent = e && e.payload && e.payload.originalEvent; - if (originalEvent && isMouse && originalEvent.detail === 2) { - preserveFocus = false; - originalEvent.preventDefault(); // focus moves to editor, we need to prevent default - } - - const sideBySide = (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)); - this.debugService.openOrRevealSource(stackFrame.source, stackFrame.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError); - } - })); - this.toDispose.push(this.tree.addListener2(events.EventType.FOCUS, (e: tree.IFocusEvent) => { const isMouseClick = (e.payload && e.payload.origin === 'mouse'); const isStackFrameType = (e.focus instanceof StackFrame); From f2baddbf2f7e9013e3415772985bc468141a0ada Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 15:05:12 +0200 Subject: [PATCH 047/255] debug: move more logic into breakpoints controller --- .../parts/debug/browser/debugViewer.ts | 24 ++++++++++++++++- .../parts/debug/browser/debugViews.ts | 27 +------------------ 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugViewer.ts b/src/vs/workbench/parts/debug/browser/debugViewer.ts index f6c5abf9726..cd2f0df3997 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewer.ts @@ -1106,10 +1106,26 @@ export class BreakpointsController extends BaseDebugController { this.debugService.getViewModel().setSelectedFunctionBreakpoint(element); return true; } + if (element instanceof model.Breakpoint) { + this.openBreakpointSource(element, event, true); + } return super.onLeftClick(tree, element, event); } + protected onEnter(tree: tree.ITree, event: IKeyboardEvent): boolean { + const element = tree.getFocus(); + if (element instanceof model.FunctionBreakpoint) { + this.debugService.getViewModel().setSelectedFunctionBreakpoint(element); + return true; + } + if (element instanceof model.Breakpoint) { + this.openBreakpointSource(element, event, false); + } + + return super.onEnter(tree, event); + } + protected onSpace(tree: tree.ITree, event: IKeyboardEvent): boolean { super.onSpace(tree, event); const element = tree.getFocus(); @@ -1118,7 +1134,6 @@ export class BreakpointsController extends BaseDebugController { return true; } - protected onDelete(tree: tree.ITree, event: IKeyboardEvent): boolean { const element = tree.getFocus(); if (element instanceof model.Breakpoint) { @@ -1133,4 +1148,11 @@ export class BreakpointsController extends BaseDebugController { return false; } + + private openBreakpointSource(breakpoint: debug.IBreakpoint, event: IKeyboardEvent|IMouseEvent, preserveFocus: boolean): void { + if (!breakpoint.source.inMemory) { + const sideBySide = (event && (event.ctrlKey || event.metaKey)); + this.debugService.openOrRevealSource(breakpoint.source, breakpoint.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError); + } + } } diff --git a/src/vs/workbench/parts/debug/browser/debugViews.ts b/src/vs/workbench/parts/debug/browser/debugViews.ts index 01859dc3490..09fae0331e1 100644 --- a/src/vs/workbench/parts/debug/browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/browser/debugViews.ts @@ -16,7 +16,7 @@ import treeimpl = require('vs/base/parts/tree/browser/treeImpl'); import splitview = require('vs/base/browser/ui/splitview/splitview'); import viewlet = require('vs/workbench/browser/viewlet'); import debug = require('vs/workbench/parts/debug/common/debug'); -import { StackFrame, Expression, Variable, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint } from 'vs/workbench/parts/debug/common/debugModel'; +import { StackFrame, Expression, Variable, ExceptionBreakpoint, FunctionBreakpoint } from 'vs/workbench/parts/debug/common/debugModel'; import viewer = require('vs/workbench/parts/debug/browser/debugViewer'); import debugactions = require('vs/workbench/parts/debug/electron-browser/debugActions'); import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -347,31 +347,6 @@ export class BreakpointsView extends viewlet.AdaptiveCollapsibleViewletView { this.tree.setInput(debugModel); - this.toDispose.push(this.tree.addListener2('selection', (e: tree.ISelectionEvent) => { - if (!e.selection.length) { - return; - } - const element = e.selection[0]; - if (!(element instanceof Breakpoint)) { - return; - } - - const breakpoint = element; - if (!breakpoint.source.inMemory) { - const isMouse = (e.payload.origin === 'mouse'); - let preserveFocus = isMouse; - - const originalEvent:KeyboardEvent|MouseEvent = e && e.payload && e.payload.originalEvent; - if (originalEvent && isMouse && originalEvent.detail === 2) { - preserveFocus = false; - originalEvent.preventDefault(); // focus moves to editor, we need to prevent default - } - - const sideBySide = (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)); - this.debugService.openOrRevealSource(breakpoint.source, breakpoint.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError); - } - })); - this.toDispose.push(this.debugService.getViewModel().onDidSelectFunctionBreakpoint(fbp => { if (!fbp || !(fbp instanceof FunctionBreakpoint)) { return; From 97f7bdd677804456e28bb1dd51d69bf724aafa41 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 16:01:35 +0200 Subject: [PATCH 048/255] debug: allow to set focussed thread with no call stack fixes #6214 --- .../debug/browser/debugEditorModelManager.ts | 5 +++-- .../parts/debug/common/debugViewModel.ts | 6 ++++-- .../parts/debug/electron-browser/debugService.ts | 15 ++++++++++----- .../debug/test/common/debugViewModel.test.ts | 4 ++-- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts index 9b163317f94..93407a49c27 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts @@ -134,13 +134,14 @@ export class DebugEditorModelManager implements IWorkbenchContribution { private createCallStackDecorations(modelUrlStr: string): editorcommon.IModelDeltaDecoration[] { const result: editorcommon.IModelDeltaDecoration[] = []; const focusedStackFrame = this.debugService.getViewModel().getFocusedStackFrame(); + const focusedThreadId = this.debugService.getViewModel().getFocusedThreadId(); const allThreads = this.debugService.getModel().getThreads(); - if (!focusedStackFrame || !allThreads[focusedStackFrame.threadId] || !allThreads[focusedStackFrame.threadId].getCachedCallStack()) { + if (!focusedStackFrame || !allThreads[focusedThreadId] || !allThreads[focusedThreadId].getCachedCallStack()) { return result; } // only show decorations for the currently focussed thread. - const thread = allThreads[focusedStackFrame.threadId]; + const thread = allThreads[focusedThreadId]; thread.getCachedCallStack().filter(sf => sf.source.uri.toString() === modelUrlStr).forEach(sf => { const wholeLineRange = createRange(sf.lineNumber, sf.column, sf.lineNumber, Number.MAX_VALUE); diff --git a/src/vs/workbench/parts/debug/common/debugViewModel.ts b/src/vs/workbench/parts/debug/common/debugViewModel.ts index 2701081a441..5de4b50287f 100644 --- a/src/vs/workbench/parts/debug/common/debugViewModel.ts +++ b/src/vs/workbench/parts/debug/common/debugViewModel.ts @@ -9,6 +9,7 @@ import debug = require('vs/workbench/parts/debug/common/debug'); export class ViewModel implements debug.IViewModel { private focusedStackFrame: debug.IStackFrame; + private focusedThread: debug.IThread; private selectedExpression: debug.IExpression; private selectedFunctionBreakpoint: debug.IFunctionBreakpoint; private _onDidFocusStackFrame: Emitter; @@ -31,8 +32,9 @@ export class ViewModel implements debug.IViewModel { return this.focusedStackFrame; } - public setFocusedStackFrame(focusedStackFrame: debug.IStackFrame): void { + public setFocusedStackFrame(focusedStackFrame: debug.IStackFrame, focusedThread: debug.IThread): void { this.focusedStackFrame = focusedStackFrame; + this.focusedThread = focusedThread; this._onDidFocusStackFrame.fire(focusedStackFrame); } @@ -41,7 +43,7 @@ export class ViewModel implements debug.IViewModel { } public getFocusedThreadId(): number { - return this.focusedStackFrame ? this.focusedStackFrame.threadId : 0; + return this.focusedThread ? this.focusedThread.threadId : 0; } public getSelectedExpression(): debug.IExpression { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 30c5fc809eb..0886a3850c3 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -251,17 +251,18 @@ export class DebugService implements debug.IDebugService { allThreadsStopped: event.body.allThreadsStopped }); - this.model.getThreads()[threadId].getCallStack(this).then(callStack => { + const thread = this.model.getThreads()[threadId]; + thread.getCallStack(this).then(callStack => { if (callStack.length > 0) { // focus first stack frame from top that has source location const stackFrameToFocus = arrays.first(callStack, sf => sf.source && sf.source.available, callStack[0]); - this.setFocusedStackFrameAndEvaluate(stackFrameToFocus).done(null, errors.onUnexpectedError); + this.setFocusedStackFrameAndEvaluate(stackFrameToFocus, thread).done(null, errors.onUnexpectedError); this.windowService.getWindow().focus(); aria.alert(nls.localize('debuggingPaused', "Debugging paused, reason {0}, {1} {2}", event.body.reason, stackFrameToFocus.source ? stackFrameToFocus.source.name : '', stackFrameToFocus.lineNumber)); return this.openOrRevealSource(stackFrameToFocus.source, stackFrameToFocus.lineNumber, false, false); } else { - this.setFocusedStackFrameAndEvaluate(null).done(null, errors.onUnexpectedError); + this.setFocusedStackFrameAndEvaluate(null, thread).done(null, errors.onUnexpectedError); } }); }, errors.onUnexpectedError); @@ -394,8 +395,12 @@ export class DebugService implements debug.IDebugService { return !!this.contextService.getWorkspace(); } - public setFocusedStackFrameAndEvaluate(focusedStackFrame: debug.IStackFrame): TPromise { - this.viewModel.setFocusedStackFrame(focusedStackFrame); + public setFocusedStackFrameAndEvaluate(focusedStackFrame: debug.IStackFrame, thread?: debug.IThread): TPromise { + if (!thread && focusedStackFrame) { + thread = this.model.getThreads()[focusedStackFrame.threadId]; + } + + this.viewModel.setFocusedStackFrame(focusedStackFrame, thread); if (focusedStackFrame) { return this.model.evaluateWatchExpressions(this.session, focusedStackFrame); } else { diff --git a/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts b/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts index a60ac72fd44..9f961b9db3e 100644 --- a/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts +++ b/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts @@ -5,7 +5,7 @@ import assert = require('assert'); import { ViewModel } from 'vs/workbench/parts/debug/common/debugViewModel'; -import { StackFrame, Expression } from 'vs/workbench/parts/debug/common/debugModel'; +import { StackFrame, Expression, Thread } from 'vs/workbench/parts/debug/common/debugModel'; suite('Debug - View Model', () => { var model: ViewModel; @@ -22,7 +22,7 @@ suite('Debug - View Model', () => { assert.equal(model.getFocusedStackFrame(), null); assert.equal(model.getFocusedThreadId(), 0); const frame = new StackFrame(1, 1, null, 'app.js', 1, 1); - model.setFocusedStackFrame(frame); + model.setFocusedStackFrame(frame, new Thread('myThread', 1)); assert.equal(model.getFocusedStackFrame(), frame); assert.equal(model.getFocusedThreadId(), 1); From df0e5235c5ed00421a247b650a4b08402ef527ef Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 May 2016 13:23:37 +0200 Subject: [PATCH 049/255] clean up some todos --- src/vs/code/electron-main/menus.ts | 4 ---- src/vs/code/electron-main/windows.ts | 4 ---- src/vs/workbench/electron-browser/media/shell.css | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 74cb9d3e79a..c5c16a0650a 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -409,10 +409,6 @@ export class VSCodeMenu { // Files let files = recentList.files; - if (platform.isMacintosh && recentList.files.length > 0) { - files = recentList.files.filter(f => recentList.folders.indexOf(f) < 0); // TODO@Ben migration (remove in the future) - } - if (files.length > 0) { openRecentMenu.append(__separator__()); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 8bf3c942a9c..f55f87d46e4 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -789,10 +789,6 @@ export class WindowsManager implements IWindowsService { files = arrays.distinct(files); folders = arrays.distinct(folders); - if (platform.isMacintosh && files.length > 0) { - files = files.filter(f => folders.indexOf(f) < 0); // TODO@Ben migration (remove in the future) - } - // Make sure it is bounded files = files.slice(0, 10); folders = folders.slice(0, 10); diff --git a/src/vs/workbench/electron-browser/media/shell.css b/src/vs/workbench/electron-browser/media/shell.css index 524dbf1887d..cdd8eabf705 100644 --- a/src/vs/workbench/electron-browser/media/shell.css +++ b/src/vs/workbench/electron-browser/media/shell.css @@ -171,7 +171,7 @@ .monaco-shell .part.editor .iframe-container, .monaco-shell .part.editor .binary-container { - outline: 0 !important; /* TODO@Ben we need focus indication for those too */ + outline: 0 !important; } /* END Keyboard Focus Indication Styles */ From e1f9857424c779de250824a9a5a446898941adb6 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 16:47:35 +0200 Subject: [PATCH 050/255] debug: smarter lazy transition to running state fixes #5966 fixes #5812 --- .../debug/electron-browser/debugService.ts | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 0886a3850c3..b57113a0bf3 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -9,6 +9,7 @@ import lifecycle = require('vs/base/common/lifecycle'); import mime = require('vs/base/common/mime'); import Event, { Emitter } from 'vs/base/common/event'; import uri from 'vs/base/common/uri'; +import { RunOnceScheduler } from 'vs/base/common/async'; import { Action } from 'vs/base/common/actions'; import arrays = require('vs/base/common/arrays'); import types = require('vs/base/common/types'); @@ -857,41 +858,41 @@ export class DebugService implements debug.IDebugService { return this.session.pause({ threadId }); } - private lazyTransitionToRunningState(threadId?: number): void { - let cancelTransitionToRunningState = false; + let setNewFocusedStackFrameScheduler: RunOnceScheduler; const toDispose = this.session.onDidStop(e => { if (e.body.threadId === threadId || e.body.allThreadsStopped || !threadId) { - cancelTransitionToRunningState = true; + setNewFocusedStackFrameScheduler.cancel(); } }); - // Do not immediatly transition to running state since that might cause unnecessery flickering - // of the tree in the debug viewlet. Only transition if no stopped event has arrived in 500ms. - setTimeout(() => { + // TODO@Isidor temporary workaround for #1703 + if (this.session && strings.equalsIgnoreCase(this.session.configuration.type, 'php')) { + this.model.clearThreads(false, threadId); + } else { + this.model.clearThreads(false); + } + + // Get a top stack frame of a stopped thread if there is any. + const threads = this.model.getThreads(); + const stoppedReference = Object.keys(threads).filter(ref => threads[ref].stopped).pop(); + const stoppedThread = stoppedReference ? threads[parseInt(stoppedReference)] : null; + const callStack = stoppedThread ? stoppedThread.getCachedCallStack() : null; + const stackFrameToFocus = callStack && callStack.length > 0 ? callStack[0] : null; + + if (!stoppedThread) { + this.setStateAndEmit(this.configurationManager.configuration.noDebug ? debug.State.RunningNoDebug : debug.State.Running); + } + + // Do not immediatly set a new focused stack frame since that might cause unnecessery flickering + // of the tree in the debug viewlet. Only set focused stack frame if no stopped event has arrived in 500ms. + setNewFocusedStackFrameScheduler = new RunOnceScheduler(() => { toDispose.dispose(); - if (!cancelTransitionToRunningState) { - aria.status(nls.localize('debuggingContinued', "Debugging continued.")); - // TODO@Isidor temporary workaround for #1703 - if (this.session && strings.equalsIgnoreCase(this.session.configuration.type, 'php')) { - this.model.clearThreads(false, threadId); - } else { - this.model.clearThreads(false); - } + aria.status(nls.localize('debuggingContinued', "Debugging continued.")); - // Get a top stack frame of a stopped thread if there is any. - const threads = this.model.getThreads(); - const stoppedReference = Object.keys(threads).filter(ref => threads[ref].stopped).pop(); - const stoppedThread = stoppedReference ? threads[parseInt(stoppedReference)] : null; - const callStack = stoppedThread ? stoppedThread.getCachedCallStack() : null; - const stackFrameToFocus = callStack && callStack.length > 0 ? callStack[0] : null; - - this.setFocusedStackFrameAndEvaluate(stackFrameToFocus).done(null, errors.onUnexpectedError); - if (!stoppedThread) { - this.setStateAndEmit(this.configurationManager.configuration.noDebug ? debug.State.RunningNoDebug : debug.State.Running); - } - } + this.setFocusedStackFrameAndEvaluate(stackFrameToFocus).done(null, errors.onUnexpectedError); }, 500); + setNewFocusedStackFrameScheduler.schedule(); } private getDebugStringEditorInput(source: Source, value: string, mtype: string): DebugStringEditorInput { From 1460f60c1860f6173a12dd2632d324aa608ea160 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Mon, 16 May 2016 18:04:37 +0200 Subject: [PATCH 051/255] node-debug: limit the number of locals transmitted by the scopes request; addresses #5645 --- extensions/node-debug/node-debug.azure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/node-debug/node-debug.azure.json b/extensions/node-debug/node-debug.azure.json index 63c268656a8..1738a5dbafc 100644 --- a/extensions/node-debug/node-debug.azure.json +++ b/extensions/node-debug/node-debug.azure.json @@ -1,6 +1,6 @@ { "account": "monacobuild", "container": "debuggers", - "zip": "48428c0/node-debug.zip", + "zip": "624d700/node-debug.zip", "output": "" } From 593122fe025b85da4e9defc3d48ceb6afcca1f44 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 May 2016 19:06:28 +0200 Subject: [PATCH 052/255] fixes #6396 --- src/vs/workbench/parts/debug/browser/media/debugViewlet.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css index ce7e59d2a64..3d5a788f92e 100644 --- a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css @@ -196,7 +196,6 @@ /* Variables & Expression view */ .debug-viewlet .scope { - text-transform: capitalize; font-weight: bold; font-size: 11px; } From 31a7dbd4e48b24fabe4d72aa5db144a8e503a21a Mon Sep 17 00:00:00 2001 From: Yuki Ueda Date: Tue, 17 May 2016 10:09:07 +0900 Subject: [PATCH 053/255] add xhtml --- src/vs/languages/html/common/html.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/languages/html/common/html.contribution.ts b/src/vs/languages/html/common/html.contribution.ts index 07b3045ba91..4047b5871b5 100644 --- a/src/vs/languages/html/common/html.contribution.ts +++ b/src/vs/languages/html/common/html.contribution.ts @@ -11,7 +11,7 @@ import ConfigurationRegistry = require('vs/platform/configuration/common/configu ModesRegistry.registerCompatMode({ id: 'html', - extensions: ['.html', '.htm', '.shtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm', '.vue'], + extensions: ['.html', '.htm', '.shtml', '.xhtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm', '.vue'], aliases: ['HTML', 'htm', 'html', 'xhtml'], mimetypes: ['text/html', 'text/x-jshtm', 'text/template', 'text/ng-template'], moduleId: 'vs/languages/html/common/html', From 4458bdf5c031534c5b91cf0bb49ce19e9c034708 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 May 2016 11:22:28 +0200 Subject: [PATCH 054/255] merge tuples of equal Uri, #6373 --- .../vscode-api-tests/src/languages.test.ts | 49 +++++++++++++++++++ .../workbench/api/node/extHostDiagnostics.ts | 13 ++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/languages.test.ts b/extensions/vscode-api-tests/src/languages.test.ts index dc2d933e4c1..fe6200c00a3 100644 --- a/extensions/vscode-api-tests/src/languages.test.ts +++ b/extensions/vscode-api-tests/src/languages.test.ts @@ -79,6 +79,55 @@ suite('languages namespace tests', () => { collection.dispose(); }); + test('diagnostics collection, set with dupliclated tuples', function () { + let collection = languages.createDiagnosticCollection('test'); + let uri = Uri.parse('sc:hightower'); + collection.set([ + [uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]], + [Uri.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]], + [uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-2')]], + ]); + + let array = collection.get(uri); + assert.equal(array.length, 2); + let [first, second] = array; + assert.equal(first.message, 'message-1'); + assert.equal(second.message, 'message-2'); + + // clear + collection.delete(uri); + assert.ok(!collection.has(uri)); + + // bad tuple clears 1/2 + collection.set([ + [uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]], + [Uri.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]], + [uri, undefined] + ]); + assert.ok(!collection.has(uri)); + + // clear + collection.delete(uri); + assert.ok(!collection.has(uri)); + + // bad tuple clears 2/2 + collection.set([ + [uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]], + [Uri.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]], + [uri, undefined], + [uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-2')]], + [uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-3')]], + ]); + + array = collection.get(uri); + assert.equal(array.length, 2); + [first, second] = array; + assert.equal(first.message, 'message-2'); + assert.equal(second.message, 'message-3'); + + collection.dispose(); + }); + test('diagnostics & CodeActionProvider', function (done) { class D2 extends Diagnostic { diff --git a/src/vs/workbench/api/node/extHostDiagnostics.ts b/src/vs/workbench/api/node/extHostDiagnostics.ts index 278050aae9b..3c9ca692e22 100644 --- a/src/vs/workbench/api/node/extHostDiagnostics.ts +++ b/src/vs/workbench/api/node/extHostDiagnostics.ts @@ -72,8 +72,19 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { toSync = []; for (let entry of first) { let [uri, diagnostics] = entry; - this._data[uri.toString()] = diagnostics; toSync.push(uri); + if (!diagnostics) { + // [Uri, undefined] means clear this + delete this._data[uri.toString()]; + } else { + // set or merge diagnostics + let existing = this._data[uri.toString()]; + if (existing) { + existing.push(...diagnostics); + } else { + this._data[uri.toString()] = diagnostics; + } + } } } From a16a9a2f46221ca2d78c1e8f39fd0c74c8d763eb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 May 2016 11:27:50 +0200 Subject: [PATCH 055/255] update jsdoc for DiagnosticCollection#set and tuples, #6373 --- src/vs/vscode.d.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index b07f77b49c8..26c3df7bb6b 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2486,6 +2486,18 @@ declare namespace vscode { */ set(uri: Uri, diagnostics: Diagnostic[]): void; + /** + * Replace all entries in this collection. + * + * Diagnostics of multiple tuples of the same uri will be merged, e.g + * `[[file1, [d1]], [file1, [d2]]]` is equivalent to `[[file1, [d1, d2]]]`. + * If a diagnostics item is `undefined` as in `[file1, undefined]` + * all previous but not subsequent diagnostics are removed. + * + * @param entries An array of tuples, like `[[file1, [d1, d2]], [file2, [d3, d4, d5]]]`, or `undefined`. + */ + set(entries: [Uri, Diagnostic[]][]): void; + /** * Remove all diagnostics from this collection that belong * to the provided `uri`. The same as `#set(uri, undefined)`. @@ -2494,13 +2506,6 @@ declare namespace vscode { */ delete(uri: Uri): void; - /** - * Replace all entries in this collection. - * - * @param entries An array of tuples, like `[[file1, [d1, d2]], [file2, [d3, d4, d5]]]`, or `undefined`. - */ - set(entries: [Uri, Diagnostic[]][]): void; - /** * Remove all diagnostics from this collection. The same * as calling `#set(undefined)`; From a3f3b7562b1058614e56851ca7b15a03ba0932bd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 May 2016 11:59:29 +0200 Subject: [PATCH 056/255] Revert "quick open: do not handle Enter on key_down, otherwise it bubbles to editor on key_up" This reverts commit ce3fb81e221457b0f8b404ac04f90a0fcac38d58. --- .../quickopen/browser/quickOpenWidget.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 4527892af4e..97500cc6efb 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -111,7 +111,7 @@ export class QuickOpenWidget implements IModelProvider { this.builder = $().div((div: Builder) => { // Eventing - div.on(DOM.EventType.KEY_UP, (e: KeyboardEvent) => { + div.on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { let keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); if (keyboardEvent.keyCode === KeyCode.Escape) { DOM.EventHelper.stop(e, true); @@ -141,7 +141,6 @@ export class QuickOpenWidget implements IModelProvider { this.inputElement.setAttribute('aria-haspopup', 'false'); this.inputElement.setAttribute('aria-autocomplete', 'list'); - // Listen to some keys on key-down for faster type feedback DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { let keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); @@ -157,17 +156,8 @@ export class QuickOpenWidget implements IModelProvider { this.navigateInTree(keyboardEvent.keyCode, keyboardEvent.shiftKey); } - // Bug in IE 9: onInput is not fired for Backspace or Delete keys - else if (browser.isIE9 && (keyboardEvent.keyCode === KeyCode.Backspace || keyboardEvent.keyCode === KeyCode.Delete)) { - this.onType(); - } - }); - - DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { - let keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); - // Select element on Enter - if (keyboardEvent.keyCode === KeyCode.Enter) { + else if (keyboardEvent.keyCode === KeyCode.Enter) { DOM.EventHelper.stop(e, true); let focus = this.tree.getFocus(); @@ -175,6 +165,11 @@ export class QuickOpenWidget implements IModelProvider { this.elementSelected(focus, e); } } + + // Bug in IE 9: onInput is not fired for Backspace or Delete keys + else if (browser.isIE9 && (keyboardEvent.keyCode === KeyCode.Backspace || keyboardEvent.keyCode === KeyCode.Delete)) { + this.onType(); + } }); DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.INPUT, (e: Event) => { From 11d1eb090e8bc9a5114ebac485876b4a6919b52e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 May 2016 12:09:16 +0200 Subject: [PATCH 057/255] Insiders Build: Add message to switch over to the alpha build (fixes #6416) --- .../electron-browser/update.contribution.ts | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/update/electron-browser/update.contribution.ts b/src/vs/workbench/parts/update/electron-browser/update.contribution.ts index 85ccc1594f8..fdc144e7952 100644 --- a/src/vs/workbench/parts/update/electron-browser/update.contribution.ts +++ b/src/vs/workbench/parts/update/electron-browser/update.contribution.ts @@ -12,12 +12,14 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import { ShowReleaseNotesAction } from 'vs/workbench/electron-browser/update'; import { Action } from 'vs/base/common/actions'; import { shell } from 'electron'; import * as semver from 'semver'; +import product from 'vs/platform/product'; const CloseAction = new Action('close', nls.localize('close', "Close"), '', true, () => null); @@ -29,6 +31,14 @@ const ShowLicenseAction = (licenseUrl: string) => new Action( () => { shell.openExternal(licenseUrl); return TPromise.as(null); } ); +const ReadAnnouncementAction = (url: string) => new Action( + 'read.announcement', + nls.localize('announcement', "Read Announcement"), + null, + true, + () => { shell.openExternal(url); return TPromise.as(null); } +); + export class UpdateContribution implements IWorkbenchContribution { private static KEY = 'releaseNotes/lastVersion'; @@ -37,14 +47,15 @@ export class UpdateContribution implements IWorkbenchContribution { constructor( @IStorageService storageService: IStorageService, @IWorkspaceContextService contextService: IWorkspaceContextService, - @IMessageService messageService: IMessageService + @IMessageService messageService: IMessageService, + @IPartService private partService: IPartService ) { const env = contextService.getConfiguration().env; const lastVersion = storageService.get(UpdateContribution.KEY, StorageScope.GLOBAL, ''); // was there an update? if (env.releaseNotesUrl && lastVersion && env.version !== lastVersion) { - setTimeout(() => { + partService.joinCreation().then(() => { messageService.show(Severity.Info, { message: nls.localize('releaseNotes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", env.appName, env.version), actions: [ @@ -52,13 +63,12 @@ export class UpdateContribution implements IWorkbenchContribution { ShowReleaseNotesAction(env.releaseNotesUrl, true) ] }); - - }, 0); + }); } // should we show the new license? if (env.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(env.version, '>=1.0.0')) { - setTimeout(() => { + partService.joinCreation().then(() => { messageService.show(Severity.Info, { message: nls.localize('licenseChanged', "Our license terms have changed, please go through them.", env.appName, env.version), actions: [ @@ -66,8 +76,20 @@ export class UpdateContribution implements IWorkbenchContribution { ShowLicenseAction(env.licenseUrl) ] }); + }); + } - }, 0); + // insider retirement (TODO@ben remove) + if (product.quality === 'insider') { + partService.joinCreation().then(() => { + messageService.show(Severity.Info, { + message: nls.localize('insiderMsg', "The insiders channel is retired, please switch over to the new 'Alpha' channel"), + actions: [ + CloseAction, + ReadAnnouncementAction('http://go.microsoft.com/fwlink/?LinkId=798816') + ] + }); + }); } storageService.store(UpdateContribution.KEY, env.version, StorageScope.GLOBAL); From d301b07e4762e615586d84da65dbba2b298e1f50 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 May 2016 15:07:09 +0200 Subject: [PATCH 058/255] move id generator to core --- src/vs/{editor/common/core => base/common}/idGenerator.ts | 0 src/vs/editor/common/model/textModelWithDecorations.ts | 2 +- src/vs/editor/common/model/textModelWithMarkers.ts | 2 +- src/vs/editor/common/model/textModelWithTrackedRanges.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/vs/{editor/common/core => base/common}/idGenerator.ts (100%) diff --git a/src/vs/editor/common/core/idGenerator.ts b/src/vs/base/common/idGenerator.ts similarity index 100% rename from src/vs/editor/common/core/idGenerator.ts rename to src/vs/base/common/idGenerator.ts diff --git a/src/vs/editor/common/model/textModelWithDecorations.ts b/src/vs/editor/common/model/textModelWithDecorations.ts index a2839b67fd6..339287ba7b9 100644 --- a/src/vs/editor/common/model/textModelWithDecorations.ts +++ b/src/vs/editor/common/model/textModelWithDecorations.ts @@ -8,7 +8,7 @@ import {onUnexpectedError} from 'vs/base/common/errors'; import {IHTMLContentElement, htmlContentElementArrEquals} from 'vs/base/common/htmlContent'; import * as strings from 'vs/base/common/strings'; import {TPromise} from 'vs/base/common/winjs.base'; -import {IdGenerator} from 'vs/editor/common/core/idGenerator'; +import {IdGenerator} from 'vs/base/common/idGenerator'; import {Range} from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {TextModelWithTrackedRanges} from 'vs/editor/common/model/textModelWithTrackedRanges'; diff --git a/src/vs/editor/common/model/textModelWithMarkers.ts b/src/vs/editor/common/model/textModelWithMarkers.ts index 0e4aae8f7fb..7b4c3364b8f 100644 --- a/src/vs/editor/common/model/textModelWithMarkers.ts +++ b/src/vs/editor/common/model/textModelWithMarkers.ts @@ -5,7 +5,7 @@ 'use strict'; import {TPromise} from 'vs/base/common/winjs.base'; -import {IdGenerator} from 'vs/editor/common/core/idGenerator'; +import {IdGenerator} from 'vs/base/common/idGenerator'; import {Position} from 'vs/editor/common/core/position'; import {IEditorPosition, IModelContentChangedFlushEvent, IRawText, IReadOnlyLineMarker, ITextModelWithMarkers} from 'vs/editor/common/editorCommon'; import {ILineMarker, ModelLine} from 'vs/editor/common/model/modelLine'; diff --git a/src/vs/editor/common/model/textModelWithTrackedRanges.ts b/src/vs/editor/common/model/textModelWithTrackedRanges.ts index 06e5701cd42..08f8d10ed9b 100644 --- a/src/vs/editor/common/model/textModelWithTrackedRanges.ts +++ b/src/vs/editor/common/model/textModelWithTrackedRanges.ts @@ -5,7 +5,7 @@ 'use strict'; import {TPromise} from 'vs/base/common/winjs.base'; -import {IdGenerator} from 'vs/editor/common/core/idGenerator'; +import {IdGenerator} from 'vs/base/common/idGenerator'; import {Range} from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import {ILineMarker} from 'vs/editor/common/model/modelLine'; From 372dbdb7bd76382e69a29bf755ee071c0e1e539c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 May 2016 15:11:43 +0200 Subject: [PATCH 059/255] use idGenerator --- src/vs/base/common/idGenerator.ts | 4 +++- src/vs/editor/common/model/textModelWithDecorations.ts | 4 ++-- src/vs/editor/common/model/textModelWithMarkers.ts | 4 ++-- src/vs/editor/common/model/textModelWithTrackedRanges.ts | 4 ++-- .../editor/contrib/referenceSearch/browser/referencesModel.ts | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/vs/base/common/idGenerator.ts b/src/vs/base/common/idGenerator.ts index 6a66c7da582..34ce058ff84 100644 --- a/src/vs/base/common/idGenerator.ts +++ b/src/vs/base/common/idGenerator.ts @@ -14,7 +14,9 @@ export class IdGenerator { this._lastId = 0; } - public generate(): string { + public nextId(): string { return this._prefix + (++this._lastId); } } + +export const defaultGenerator = new IdGenerator('id#'); \ No newline at end of file diff --git a/src/vs/editor/common/model/textModelWithDecorations.ts b/src/vs/editor/common/model/textModelWithDecorations.ts index 339287ba7b9..092eb35d318 100644 --- a/src/vs/editor/common/model/textModelWithDecorations.ts +++ b/src/vs/editor/common/model/textModelWithDecorations.ts @@ -415,7 +415,7 @@ export class TextModelWithDecorations extends TextModelWithTrackedRanges impleme private _addDecorationImpl(eventBuilder:DeferredEventsBuilder, ownerId:number, range:editorCommon.IEditorRange, options:ModelDecorationOptions): string { var rangeId = this.addTrackedRange(range, options.stickiness); - var decoration = new ModelInternalDecoration(this._decorationIdGenerator.generate(), ownerId, rangeId, options); + var decoration = new ModelInternalDecoration(this._decorationIdGenerator.nextId(), ownerId, rangeId, options); this.decorations[decoration.id] = decoration; this.rangeIdToDecorationId[rangeId] = decoration.id; @@ -432,7 +432,7 @@ export class TextModelWithDecorations extends TextModelWithTrackedRanges impleme for (let i = 0, len = newDecorations.length; i < len; i++) { let rangeId = rangeIds[i]; - var decoration = new ModelInternalDecoration(this._decorationIdGenerator.generate(), ownerId, rangeId, newDecorations[i].options); + var decoration = new ModelInternalDecoration(this._decorationIdGenerator.nextId(), ownerId, rangeId, newDecorations[i].options); this.decorations[decoration.id] = decoration; this.rangeIdToDecorationId[rangeId] = decoration.id; diff --git a/src/vs/editor/common/model/textModelWithMarkers.ts b/src/vs/editor/common/model/textModelWithMarkers.ts index 7b4c3364b8f..66b61109bc8 100644 --- a/src/vs/editor/common/model/textModelWithMarkers.ts +++ b/src/vs/editor/common/model/textModelWithMarkers.ts @@ -72,7 +72,7 @@ export class TextModelWithMarkers extends TextModelWithTokens implements ITextMo _addMarker(lineNumber:number, column:number, stickToPreviousCharacter:boolean): string { var pos = this.validatePosition(new Position(lineNumber, column)); - var marker = new LineMarker(this._markerIdGenerator.generate(), pos.column, stickToPreviousCharacter); + var marker = new LineMarker(this._markerIdGenerator.nextId(), pos.column, stickToPreviousCharacter); this._markerIdToMarker[marker.id] = marker; this._lines[pos.lineNumber - 1].addMarker(marker); @@ -89,7 +89,7 @@ export class TextModelWithMarkers extends TextModelWithTokens implements ITextMo for (let i = 0, len = newMarkers.length; i < len; i++) { let newMarker = newMarkers[i]; - let marker = new LineMarker(this._markerIdGenerator.generate(), newMarker.column, newMarker.stickToPreviousCharacter); + let marker = new LineMarker(this._markerIdGenerator.nextId(), newMarker.column, newMarker.stickToPreviousCharacter); this._markerIdToMarker[marker.id] = marker; if (!addMarkersPerLine[newMarker.lineNumber]) { diff --git a/src/vs/editor/common/model/textModelWithTrackedRanges.ts b/src/vs/editor/common/model/textModelWithTrackedRanges.ts index 08f8d10ed9b..21ccd3b9154 100644 --- a/src/vs/editor/common/model/textModelWithTrackedRanges.ts +++ b/src/vs/editor/common/model/textModelWithTrackedRanges.ts @@ -140,7 +140,7 @@ export class TextModelWithTrackedRanges extends TextModelWithMarkers implements var startMarkerId = this._addMarker(textRange.startLineNumber, textRange.startColumn, startMarkerSticksToPreviousCharacter); var endMarkerId = this._addMarker(textRange.endLineNumber, textRange.endColumn, endMarkerSticksToPreviousCharacter); - var range = new TrackedRange(this._rangeIdGenerator.generate(), startMarkerId, endMarkerId); + var range = new TrackedRange(this._rangeIdGenerator.nextId(), startMarkerId, endMarkerId); this._ranges[range.id] = range; this._markerIdToRangeId[startMarkerId] = range.id; this._markerIdToRangeId[endMarkerId] = range.id; @@ -176,7 +176,7 @@ export class TextModelWithTrackedRanges extends TextModelWithMarkers implements let startMarkerId = markerIds[2 * i]; let endMarkerId = markerIds[2 * i + 1]; - let range = new TrackedRange(this._rangeIdGenerator.generate(), startMarkerId, endMarkerId); + let range = new TrackedRange(this._rangeIdGenerator.nextId(), startMarkerId, endMarkerId); this._ranges[range.id] = range; this._markerIdToRangeId[startMarkerId] = range.id; this._markerIdToRangeId[endMarkerId] = range.id; diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts index e281f462bd5..454dc15b12b 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts @@ -9,7 +9,7 @@ import Event, {fromEventEmitter} from 'vs/base/common/event'; import {basename, dirname} from 'vs/base/common/paths'; import * as strings from 'vs/base/common/strings'; import URI from 'vs/base/common/uri'; -import {generateUuid} from 'vs/base/common/uuid'; +import {defaultGenerator} from 'vs/base/common/idGenerator'; import {TPromise} from 'vs/base/common/winjs.base'; import {IEditorService} from 'vs/platform/editor/common/editor'; import {Range} from 'vs/editor/common/core/range'; @@ -25,7 +25,7 @@ export class OneReference { private _range: IRange, private _eventBus: EventEmitter ) { - this._id = generateUuid(); + this._id = defaultGenerator.nextId(); } public get id(): string { From 856fb636c75ce7014a7aa6ae29f5f9b975f41fa0 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 17 May 2016 15:41:36 +0200 Subject: [PATCH 060/255] update node-debug --- extensions/node-debug/node-debug.azure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/node-debug/node-debug.azure.json b/extensions/node-debug/node-debug.azure.json index 1738a5dbafc..ff103612c70 100644 --- a/extensions/node-debug/node-debug.azure.json +++ b/extensions/node-debug/node-debug.azure.json @@ -1,6 +1,6 @@ { "account": "monacobuild", "container": "debuggers", - "zip": "624d700/node-debug.zip", + "zip": "3c7ed19/node-debug.zip", "output": "" } From 6af3db5d8d76e2c59e33189bec1206d93d81fb95 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 May 2016 15:58:33 +0200 Subject: [PATCH 061/255] fixes #6425 --- .../parts/debug/electron-browser/debug.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e21596887d6..3d1481735ec 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -124,7 +124,7 @@ KeybindingsRegistry.registerCommandDesc({ .then(() => debugService.createSession(false)); } - return debugService.createSession(false, configuration); + return debugService.createSession(!!configuration.noDebug, configuration); }, when: KbExpr.not(debug.CONTEXT_IN_DEBUG_MODE), primary: undefined From 3354ae92f75fc86994ef7eb85fdd7537d078b21f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 May 2016 15:59:59 +0200 Subject: [PATCH 062/255] fix #5918 --- .../src/features/jsonContributions.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/extensions/javascript/src/features/jsonContributions.ts b/extensions/javascript/src/features/jsonContributions.ts index 1926b38fab7..e33ff6d1e91 100644 --- a/extensions/javascript/src/features/jsonContributions.ts +++ b/extensions/javascript/src/features/jsonContributions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {Location, getLocation, createScanner, SyntaxKind} from 'jsonc-parser'; +import {Location, getLocation, createScanner, SyntaxKind, ScanError} from 'jsonc-parser'; import {basename} from 'path'; import {BowerJSONContribution} from './bowerJSONContribution'; import {PackageJSONContribution} from './packageJSONContribution'; @@ -122,10 +122,7 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { if (location.isAtPropertyKey) { let addValue = !location.previousNode || !location.previousNode.columnOffset; - let scanner = createScanner(document.getText(), true); - scanner.setPosition(offset); - scanner.scan(); - let isLast = scanner.getToken() === SyntaxKind.CloseBraceToken || scanner.getToken() === SyntaxKind.EOF; + let isLast = this.isLast(document, position); collectPromise = this.jsonContribution.collectPropertySuggestions(fileName, location, currentWord, addValue, isLast, collector); } else { if (location.path.length === 0) { @@ -153,4 +150,14 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { } return text.substring(i+1, position.character); } + + private isLast(document: TextDocument, position: Position):boolean { + let scanner = createScanner(document.getText(), true); + scanner.setPosition(document.offsetAt(position)); + let nextToken = scanner.scan(); + if (nextToken === SyntaxKind.StringLiteral && scanner.getTokenError() === ScanError.UnexpectedEndOfString) { + nextToken= scanner.scan(); + } + return nextToken === SyntaxKind.CloseBraceToken || nextToken === SyntaxKind.EOF; + } } \ No newline at end of file From d8f6ac3501b6cfcc5db528ddc556dd3869355f82 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 May 2016 16:21:51 +0200 Subject: [PATCH 063/255] add new api command to compare two resources, fixes #1865 --- .../vscode-api-tests/src/commands.test.ts | 59 +++++++++++++------ .../workbench/api/node/extHostApiCommands.ts | 11 ++++ src/vs/workbench/electron-browser/actions.ts | 28 +++++++++ 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/extensions/vscode-api-tests/src/commands.test.ts b/extensions/vscode-api-tests/src/commands.test.ts index 5ffd6fd2ac7..495de2d1d96 100644 --- a/extensions/vscode-api-tests/src/commands.test.ts +++ b/extensions/vscode-api-tests/src/commands.test.ts @@ -40,23 +40,6 @@ suite('commands namespace tests', () => { }, done); }); - test('api-command: workbench.html.preview', function () { - - let registration = workspace.registerTextDocumentContentProvider('speciale', { - provideTextDocumentContent(uri) { - return `content of URI ${uri.toString()}`; - } - }); - - let virtualDocumentUri = Uri.parse('speciale://authority/path'); - - return commands.executeCommand('vscode.previewHtml', virtualDocumentUri).then(success => { - assert.ok(success); - registration.dispose(); - }); - - }); - test('editorCommand with extra args', function () { let args: IArguments; @@ -77,4 +60,46 @@ suite('commands namespace tests', () => { }); }); + + test('api-command: vscode.previewHtm', function () { + + let registration = workspace.registerTextDocumentContentProvider('speciale', { + provideTextDocumentContent(uri) { + return `content of URI ${uri.toString()}`; + } + }); + + let virtualDocumentUri = Uri.parse('speciale://authority/path'); + + return commands.executeCommand('vscode.previewHtml', virtualDocumentUri).then(success => { + assert.ok(success); + registration.dispose(); + }); + + }); + + test('api-command: vscode.diff', function () { + + let registration = workspace.registerTextDocumentContentProvider('sc', { + provideTextDocumentContent(uri) { + return `content of URI ${uri.toString()}#${Math.random()}`; + } + }); + + + let a = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b'), 'DIFF').then(value => { + assert.ok(value === void 0); + registration.dispose(); + }); + + let b = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b')).then(value => { + assert.ok(value === void 0); + registration.dispose(); + }); + + let c = commands.executeCommand('vscode.diff').then(() => assert.ok(false), () => assert.ok(true)); + let d = commands.executeCommand('vscode.diff', 1, 2, 3).then(() => assert.ok(false), () => assert.ok(true)); + + return Promise.all([a, b, c]); + }); }); diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index 92c8a164e52..666c57b577e 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -197,6 +197,17 @@ class ExtHostApiCommands { { name: 'configuration', description: '(optional) Name of the debug configuration from \'launch.json\' to use. Or a configuration json object to use.' } ] }); + + this._register('vscode.diff', (left: URI, right: URI, label: string) => { + return this._commands.executeCommand('_workbench.diff', [left, right, label]); + }, { + description: 'Opens the provided resources in the diff editor to compare their contents.', + args: [ + { name: 'left', description: 'Left-hand side resource of the diff editor', constraint: URI }, + { name: 'right', description: 'Right-hand side resource of the diff editor', constraint: URI }, + { name: 'title', description: '(optional) Human readable title for the diff editor', constraint: v => v === void 0 || typeof v === 'string' } + ] + }); } // --- command impl diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 217820b5640..635937fcf9f 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -5,12 +5,15 @@ 'use strict'; +import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; import timer = require('vs/base/common/timer'); import paths = require('vs/base/common/paths'); import {Action} from 'vs/base/common/actions'; import {IWindowService} from 'vs/workbench/services/window/electron-browser/windowService'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; +import {EditorInput} from 'vs/workbench/common/editor'; +import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; import nls = require('vs/nls'); import {IMessageService, Severity} from 'vs/platform/message/common/message'; import {IWindowConfiguration} from 'vs/workbench/electron-browser/window'; @@ -459,4 +462,29 @@ KeybindingsRegistry.registerCommandDesc({ }, when: undefined, primary: undefined +}); + +KeybindingsRegistry.registerCommandDesc({ + id: '_workbench.diff', + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(0), + handler(accessor: ServicesAccessor, args: [URI, URI, string]) { + + const editorService = accessor.get(IWorkbenchEditorService); + let [left, right, label] = args; + + if (!label) { + label = nls.localize('diffLeftRightLabel', "{0} ⟷ {1}", left.toString(true), right.toString(true)); + } + + return TPromise.join([editorService.inputToType({ resource: left }), editorService.inputToType({ resource: right })]).then(inputs => { + const [left, right] = inputs; + + const diff = new DiffEditorInput(label, undefined, left, right); + return editorService.openEditor(diff); + }).then(() => { + return void 0; + }); + }, + when: undefined, + primary: undefined }); \ No newline at end of file From e78309f17eb2d36e56b75c9ca376606e84025025 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 May 2016 18:01:56 +0200 Subject: [PATCH 064/255] add a new config to enable word-based suggestions, fixes #5574 --- src/vs/editor/common/modes/abstractMode.ts | 6 +++-- .../common/modes/supports/suggestSupport.ts | 26 +++++++++++++++++-- src/vs/languages/php/common/php.ts | 4 ++- src/vs/languages/php/test/common/php.test.ts | 1 + 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/common/modes/abstractMode.ts b/src/vs/editor/common/modes/abstractMode.ts index 99c2892c2ec..7a0ca2d7ec1 100644 --- a/src/vs/editor/common/modes/abstractMode.ts +++ b/src/vs/editor/common/modes/abstractMode.ts @@ -9,6 +9,7 @@ import {IDisposable} from 'vs/base/common/lifecycle'; import {TPromise} from 'vs/base/common/winjs.base'; import {AsyncDescriptor1, createAsyncDescriptor1} from 'vs/platform/instantiation/common/descriptors'; import {IInstantiationService, optional} from 'vs/platform/instantiation/common/instantiation'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {IModeSupportChangedEvent} from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import {NullMode} from 'vs/editor/common/modes/nullMode'; @@ -251,13 +252,14 @@ export class FrankensteinMode extends AbstractMode { public suggestSupport:modes.ISuggestSupport; constructor( - descriptor:modes.IModeDescriptor, + descriptor: modes.IModeDescriptor, + @IConfigurationService configurationService: IConfigurationService, @optional(IEditorWorkerService) editorWorkerService: IEditorWorkerService ) { super(descriptor.id); if (editorWorkerService) { - this.suggestSupport = new TextualSuggestSupport(this.getId(), editorWorkerService); + this.suggestSupport = new TextualSuggestSupport(this.getId(), editorWorkerService, configurationService); } } } diff --git a/src/vs/editor/common/modes/supports/suggestSupport.ts b/src/vs/editor/common/modes/supports/suggestSupport.ts index d9b63f54f23..2e0bc9cfe9a 100644 --- a/src/vs/editor/common/modes/supports/suggestSupport.ts +++ b/src/vs/editor/common/modes/supports/suggestSupport.ts @@ -12,6 +12,10 @@ import {IFilter, matchesStrictPrefix, fuzzyContiguousFilter} from 'vs/base/commo import {handleEvent, isLineToken} from 'vs/editor/common/modes/supports'; import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; import {IModelService} from 'vs/editor/common/services/modelService'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; +import {IConfigurationRegistry, Extensions} from 'vs/platform/configuration/common/configurationRegistry'; +import {Registry} from 'vs/platform/platform'; +import {localize} from 'vs/nls'; export interface ISuggestContribution { triggerCharacters: string[]; @@ -67,16 +71,34 @@ export class SuggestSupport implements ISuggestSupport { export class TextualSuggestSupport implements ISuggestSupport { + /* tslint:disable */ + private static _c = Registry.as(Extensions.Configuration).registerConfiguration({ + type: 'object', + properties: { + 'editor.wordBasedSuggestions': { + 'type': 'boolean', + 'description': localize('editor.wordBasedSuggestions', "Enable word based suggestions."), + 'default': true + } + } + }); + /* tslint:enable */ + private _modeId: string; private _editorWorkerService: IEditorWorkerService; + private _configurationService: IConfigurationService; - constructor(modeId: string, editorWorkerService: IEditorWorkerService) { + constructor(modeId: string, editorWorkerService: IEditorWorkerService, configurationService: IConfigurationService) { this._modeId = modeId; this._editorWorkerService = editorWorkerService; + this._configurationService = configurationService; } public suggest(resource: URI, position: IPosition, triggerCharacter?: string): TPromise { - return this._editorWorkerService.textualSuggest(resource, position); + let config = this._configurationService.getConfiguration<{ wordBasedSuggestions: boolean }>('editor'); + return (!config || config.wordBasedSuggestions) + ? this._editorWorkerService.textualSuggest(resource, position) + : TPromise.as([]); } public get filter(): IFilter { diff --git a/src/vs/languages/php/common/php.ts b/src/vs/languages/php/common/php.ts index 0221efe5b09..7f0e87d1bbe 100644 --- a/src/vs/languages/php/common/php.ts +++ b/src/vs/languages/php/common/php.ts @@ -14,6 +14,7 @@ import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; import {TokenizationSupport, ILeavingNestedModeData, ITokenizationCustomization} from 'vs/editor/common/modes/supports/tokenizationSupport'; import {TextualSuggestSupport} from 'vs/editor/common/modes/supports/suggestSupport'; import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; var brackets = (function() { @@ -460,6 +461,7 @@ export class PHPMode extends AbstractMode implements ITokenizationCustomization constructor( descriptor:Modes.IModeDescriptor, @IModeService modeService: IModeService, + @IConfigurationService configurationService: IConfigurationService, @IEditorWorkerService editorWorkerService: IEditorWorkerService ) { super(descriptor.id); @@ -493,7 +495,7 @@ export class PHPMode extends AbstractMode implements ITokenizationCustomization }); if (editorWorkerService) { - this.suggestSupport = new TextualSuggestSupport(this.getId(), editorWorkerService); + this.suggestSupport = new TextualSuggestSupport(this.getId(), editorWorkerService, configurationService); } } diff --git a/src/vs/languages/php/test/common/php.test.ts b/src/vs/languages/php/test/common/php.test.ts index 865cfdea340..e81f2d5f135 100644 --- a/src/vs/languages/php/test/common/php.test.ts +++ b/src/vs/languages/php/test/common/php.test.ts @@ -69,6 +69,7 @@ suite('Syntax Highlighting - PHP', () => { let mode = new PHPMode( { id: 'php' }, modeService, + null, null ); From 71dcb8069d67ca5f8bd2c82007eecf27b6d48646 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 17 May 2016 18:22:15 +0200 Subject: [PATCH 065/255] Adopt latest loader that adds `nodeModules` option to disambiguate node modules from AMD modules at bundle time and adopt it in the gulp tasks --- build/gulpfile.common.js | 4 ++-- src/vs/css.js | 14 ++++++-------- src/vs/loader.js | 38 ++++++++++++++++++++++---------------- src/vs/nls.js | 4 ++-- src/vs/text.js | 8 ++++---- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/build/gulpfile.common.js b/build/gulpfile.common.js index 23b1480a418..47f24f687ef 100644 --- a/build/gulpfile.common.js +++ b/build/gulpfile.common.js @@ -40,10 +40,10 @@ exports.loaderConfig = function (emptyPaths) { paths: { 'vs/extensions': 'extensions' } - } + }, + nodeModules: emptyPaths||[] }; - (emptyPaths || []).forEach(function(m) { result.paths[m] = 'empty:'; }); return result; }; diff --git a/src/vs/css.js b/src/vs/css.js index 710116c0651..eaa5d6d8e47 100644 --- a/src/vs/css.js +++ b/src/vs/css.js @@ -13,8 +13,6 @@ *--------------------------------------------------------------------------------------------- *--------------------------------------------------------------------------------------------- *--------------------------------------------------------------------------------------------*/ -/// -/// 'use strict'; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; @@ -100,7 +98,7 @@ var CSSLoaderPlugin; this._insertLinkNode(linkNode); }; return BrowserCSSLoader; - })(); + }()); /** * Prior to IE10, IE could not go above 31 stylesheets in a page * http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/internet-explorer-stylesheet-rule-selector-import-sheet-limit-maximum.aspx @@ -201,7 +199,7 @@ var CSSLoaderPlugin; } }; return IE9CSSLoader; - })(BrowserCSSLoader); + }(BrowserCSSLoader)); var IE8CSSLoader = (function (_super) { __extends(IE8CSSLoader, _super); function IE8CSSLoader() { @@ -214,7 +212,7 @@ var CSSLoaderPlugin; }; }; return IE8CSSLoader; - })(IE9CSSLoader); + }(IE9CSSLoader)); var NodeCSSLoader = (function () { function NodeCSSLoader() { this.fs = require.nodeRequire('fs'); @@ -229,7 +227,7 @@ var CSSLoaderPlugin; }; NodeCSSLoader.BOM_CHAR_CODE = 65279; return NodeCSSLoader; - })(); + }()); // ------------------------------ Finally, the plugin var CSSPlugin = (function () { function CSSPlugin(cssLoader) { @@ -279,7 +277,7 @@ var CSSLoaderPlugin; }; CSSPlugin.BUILD_MAP = {}; return CSSPlugin; - })(); + }()); CSSLoaderPlugin.CSSPlugin = CSSPlugin; var Utilities = (function () { function Utilities() { @@ -411,7 +409,7 @@ var CSSLoaderPlugin; }); }; return Utilities; - })(); + }()); CSSLoaderPlugin.Utilities = Utilities; (function () { var cssLoader = null; diff --git a/src/vs/loader.js b/src/vs/loader.js index b7d5f30c3a1..49317011d21 100644 --- a/src/vs/loader.js +++ b/src/vs/loader.js @@ -13,7 +13,6 @@ *--------------------------------------------------------------------------------------------- *--------------------------------------------------------------------------------------------- *--------------------------------------------------------------------------------------------*/ -/// 'use strict'; // Limitation: To load jquery through the loader, always require 'jquery' and add a path for it in the loader configuration var _amdLoaderGlobal = this, define; @@ -123,7 +122,7 @@ var AMDLoader; }; Utilities.NEXT_ANONYMOUS_ID = 1; return Utilities; - })(); + }()); AMDLoader.Utilities = Utilities; var ConfigurationOptionsUtil = (function () { function ConfigurationOptionsUtil() { @@ -189,6 +188,9 @@ var AMDLoader; options.baseUrl += '/'; } } + if (!Array.isArray(options.nodeModules)) { + options.nodeModules = []; + } return options; }; ConfigurationOptionsUtil.mergeConfigurationOptions = function (overwrite, base) { @@ -232,7 +234,7 @@ var AMDLoader; return ConfigurationOptionsUtil.validateConfigurationOptions(result); }; return ConfigurationOptionsUtil; - })(); + }()); AMDLoader.ConfigurationOptionsUtil = ConfigurationOptionsUtil; var Configuration = (function () { function Configuration(options) { @@ -428,6 +430,10 @@ var AMDLoader; * Transform a module id to a location. Appends .js to module ids */ Configuration.prototype.moduleIdToPaths = function (moduleId) { + if (this.isBuild() && this.options.nodeModules.indexOf(moduleId) >= 0) { + // This is a node module and we are at build time, drop it + return ['empty:']; + } var result = moduleId; if (this.overwriteModuleIdToPath.hasOwnProperty(result)) { result = this.overwriteModuleIdToPath[result]; @@ -522,7 +528,7 @@ var AMDLoader; this.options.onError(err); }; return Configuration; - })(); + }()); AMDLoader.Configuration = Configuration; // ------------------------------------------------------------------------ // ModuleIdResolver @@ -602,7 +608,7 @@ var AMDLoader; this._config.onError(err); }; return ModuleIdResolver; - })(); + }()); AMDLoader.ModuleIdResolver = ModuleIdResolver; // ------------------------------------------------------------------------ // Module @@ -832,7 +838,7 @@ var AMDLoader; return this._unresolvedDependenciesCount === 0; }; return Module; - })(); + }()); AMDLoader.Module = Module; // ------------------------------------------------------------------------ // LoaderEvent @@ -859,7 +865,7 @@ var AMDLoader; this.timestamp = timestamp; } return LoaderEvent; - })(); + }()); AMDLoader.LoaderEvent = LoaderEvent; var LoaderEventRecorder = (function () { function LoaderEventRecorder(loaderAvailableTimestamp) { @@ -872,7 +878,7 @@ var AMDLoader; return this._events; }; return LoaderEventRecorder; - })(); + }()); AMDLoader.LoaderEventRecorder = LoaderEventRecorder; var NullLoaderEventRecorder = (function () { function NullLoaderEventRecorder() { @@ -885,7 +891,7 @@ var AMDLoader; }; NullLoaderEventRecorder.INSTANCE = new NullLoaderEventRecorder(); return NullLoaderEventRecorder; - })(); + }()); AMDLoader.NullLoaderEventRecorder = NullLoaderEventRecorder; var ModuleManager = (function () { function ModuleManager(scriptLoader) { @@ -1520,7 +1526,7 @@ var AMDLoader; } }; return ModuleManager; - })(); + }()); AMDLoader.ModuleManager = ModuleManager; /** * Load `scriptSrc` only once (avoid multiple