From 2a7becfbab84e20c1b945a4ade177b40a9cfccf7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 Feb 2017 13:17:47 -0800 Subject: [PATCH 1/8] Get web and relative paths working in terminal Part of #7321 --- .../terminal/electron-browser/media/xterm.css | 10 +++++ .../electron-browser/terminalInstance.ts | 43 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index 9577483746262..5681459545495 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -58,6 +58,16 @@ opacity: 0 !important; } +.monaco-workbench .panel.integrated-terminal .xterm a { + color: inherit; + text-decoration: none; +} + +.monaco-workbench .panel.integrated-terminal .xterm a:hover { + cursor: pointer; + text-decoration: underline; +} + .monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus .reverse-video, .monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar):focus .reverse-video { color: #CCC; } .vs-dark .monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus .reverse-video, diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index f5c87ee09d88f..79c3fdb7aa699 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as path from 'path'; +import * as pfs from 'vs/base/node/pfs'; import DOM = require('vs/base/browser/dom'); import Event, { Emitter } from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; @@ -10,9 +12,9 @@ import cp = require('child_process'); import lifecycle = require('vs/base/common/lifecycle'); import nls = require('vs/nls'); import os = require('os'); -import path = require('path'); import platform = require('vs/base/common/platform'); import xterm = require('xterm'); +import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension } from 'vs/base/browser/builder'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -22,6 +24,7 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { ITerminalInstance, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal'; import { ITerminalProcessFactory } from 'vs/workbench/parts/terminal/electron-browser/terminal'; import { IWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { TabFocus } from 'vs/editor/common/config/commonEditorConfig'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; @@ -29,6 +32,13 @@ import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-brows /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; +/** A regex that matches paths in the form /path, ~/path, ./path, ../path */ +const pathPrefix = '(\\.\\.?|\\~)'; +const pathStartClause = '\\/'; +const excludedPathCharactersClause = '[^\\0\\s!$`&*()+\'":;]'; // '":; are allowed in paths but they are often separators so ignore them +const escapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; +const LOCAL_UNIX_LIKE_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathStartClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); + class StandardTerminalProcessFactory implements ITerminalProcessFactory { public create(env: { [key: string]: string }): cp.ChildProcess { return cp.fork('./terminalProcess', [], { @@ -80,7 +90,8 @@ export class TerminalInstance implements ITerminalInstance { @IKeybindingService private _keybindingService: IKeybindingService, @IMessageService private _messageService: IMessageService, @IPanelService private _panelService: IPanelService, - @IWorkspaceContextService private _contextService: IWorkspaceContextService + @IWorkspaceContextService private _contextService: IWorkspaceContextService, + @IWorkbenchEditorService private _editorService: IWorkbenchEditorService ) { this._instanceDisposables = []; this._processDisposables = []; @@ -139,6 +150,7 @@ export class TerminalInstance implements ITerminalInstance { this._xtermElement = document.createElement('div'); this._xterm.open(this._xtermElement); + this._xterm.registerLinkMatcher(LOCAL_UNIX_LIKE_LINK_REGEX, (url) => this._openRelativeUnixLikeLink(url), 1); this._xterm.attachCustomKeydownHandler((event: KeyboardEvent) => { // Disable all input if the terminal is exiting if (this._isExiting) { @@ -218,6 +230,33 @@ export class TerminalInstance implements ITerminalInstance { this.updateConfig(); } + private _openRelativeUnixLikeLink(link: string): TPromise { + // Resolve ~ -> $HOME + if (link.charAt(0) === '~') { + link = process.env.HOME + link.substring(1); + } + + // Resolve workspace path . / .. -> /. / { + if (!isFile) { + return void 0; + } + return this._editorService.openEditor({ resource }).then(() => void 0); + }); + } + public hasSelection(): boolean { return !document.getSelection().isCollapsed; } From 57fbdeff2958d10f493ca2cf54d84c13d2373e4d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 Feb 2017 13:22:42 -0800 Subject: [PATCH 2/8] Prevent terminal link matcher on Windows for now Only unix-like paths are supported right now --- .../parts/terminal/electron-browser/terminalInstance.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 79c3fdb7aa699..bf41bdd9e6bc8 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -150,7 +150,9 @@ export class TerminalInstance implements ITerminalInstance { this._xtermElement = document.createElement('div'); this._xterm.open(this._xtermElement); - this._xterm.registerLinkMatcher(LOCAL_UNIX_LIKE_LINK_REGEX, (url) => this._openRelativeUnixLikeLink(url), 1); + if (!platform.isWindows) { + this._xterm.registerLinkMatcher(LOCAL_UNIX_LIKE_LINK_REGEX, (url) => this._openRelativeUnixLikeLink(url), 1); + } this._xterm.attachCustomKeydownHandler((event: KeyboardEvent) => { // Disable all input if the terminal is exiting if (this._isExiting) { From 2bfb0f301ad4153b6a1ea119cb48d431d6b03663 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 Feb 2017 13:53:05 -0800 Subject: [PATCH 3/8] Pull link handling code into object owned by service --- .../electron-browser/terminalInstance.ts | 42 +--------- .../electron-browser/terminalLinkHandler.ts | 80 +++++++++++++++++++ .../electron-browser/terminalService.ts | 6 +- 3 files changed, 88 insertions(+), 40 deletions(-) create mode 100644 src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index bf41bdd9e6bc8..ab7cba198388e 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; -import * as pfs from 'vs/base/node/pfs'; import DOM = require('vs/base/browser/dom'); import Event, { Emitter } from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; @@ -14,7 +13,6 @@ import nls = require('vs/nls'); import os = require('os'); import platform = require('vs/base/common/platform'); import xterm = require('xterm'); -import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension } from 'vs/base/browser/builder'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -28,17 +26,11 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { TabFocus } from 'vs/editor/common/config/commonEditorConfig'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; +import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; -/** A regex that matches paths in the form /path, ~/path, ./path, ../path */ -const pathPrefix = '(\\.\\.?|\\~)'; -const pathStartClause = '\\/'; -const excludedPathCharactersClause = '[^\\0\\s!$`&*()+\'":;]'; // '":; are allowed in paths but they are often separators so ignore them -const escapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; -const LOCAL_UNIX_LIKE_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathStartClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); - class StandardTerminalProcessFactory implements ITerminalProcessFactory { public create(env: { [key: string]: string }): cp.ChildProcess { return cp.fork('./terminalProcess', [], { @@ -84,6 +76,7 @@ export class TerminalInstance implements ITerminalInstance { public constructor( private _terminalFocusContextKey: IContextKey, private _configHelper: TerminalConfigHelper, + private _linkHandler: TerminalLinkHandler, private _container: HTMLElement, private _shellLaunchConfig: IShellLaunchConfig, @IContextKeyService private _contextKeyService: IContextKeyService, @@ -150,9 +143,7 @@ export class TerminalInstance implements ITerminalInstance { this._xtermElement = document.createElement('div'); this._xterm.open(this._xtermElement); - if (!platform.isWindows) { - this._xterm.registerLinkMatcher(LOCAL_UNIX_LIKE_LINK_REGEX, (url) => this._openRelativeUnixLikeLink(url), 1); - } + this._xterm.registerLinkMatcher(this._linkHandler.localLinkRegex, (url) => this._linkHandler.handleLocalLink(url), 1); this._xterm.attachCustomKeydownHandler((event: KeyboardEvent) => { // Disable all input if the terminal is exiting if (this._isExiting) { @@ -232,33 +223,6 @@ export class TerminalInstance implements ITerminalInstance { this.updateConfig(); } - private _openRelativeUnixLikeLink(link: string): TPromise { - // Resolve ~ -> $HOME - if (link.charAt(0) === '~') { - link = process.env.HOME + link.substring(1); - } - - // Resolve workspace path . / .. -> /. / { - if (!isFile) { - return void 0; - } - return this._editorService.openEditor({ resource }).then(() => void 0); - }); - } - public hasSelection(): boolean { return !document.getSelection().isCollapsed; } diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts new file mode 100644 index 0000000000000..b7404c781fd6a --- /dev/null +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'path'; +import * as pfs from 'vs/base/node/pfs'; +import Uri from 'vs/base/common/uri'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { Platform } from 'vs/base/common/platform'; +import { TPromise } from 'vs/base/common/winjs.base'; + +const pathPrefix = '(\\.\\.?|\\~)'; +const pathStartClause = '\\/'; +const excludedPathCharactersClause = '[^\\0\\s!$`&*()+\'":;]'; // '":; are allowed in paths but they are often separators so ignore them +const escapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; +/** A regex that matches paths in the form /path, ~/path, ./path, ../path */ +const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathStartClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); + +const winPathPrefix = '(\\.\\.?|\\~)'; +const winPathStartClause = '\\/'; +const winExcludedPathCharactersClause = '[^\\0\\s!$`&*()+\'":;]'; // '":; are allowed in paths but they are often separators so ignore them +const winEscapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; +/** A regex that matches paths in the form c:\path, ~\path, .\path */ +const WINDOWS_LOCAL_LINK_REGEX = new RegExp('(' + winPathPrefix + '?(' + winPathStartClause + '(' + winExcludedPathCharactersClause + '|' + winEscapedExcludedPathCharactersClause + ')+)+)'); + +export class TerminalLinkHandler { + constructor( + private _platform: Platform, + @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, + @IWorkspaceContextService private _contextService: IWorkspaceContextService + ) { + } + + public get localLinkRegex(): RegExp { + if (this._platform === Platform.Windows) { + return WINDOWS_LOCAL_LINK_REGEX; + } + return UNIX_LIKE_LOCAL_LINK_REGEX; + } + + public handleLocalLink(link: string): TPromise { + if (this._platform === Platform.Windows) { + return this._handleWindowsLocalLink(link); + } + return this._handleUnixLikeLocalLink(link); + } + + private _handleUnixLikeLocalLink(link: string): TPromise { + // Resolve ~ -> $HOME + if (link.charAt(0) === '~') { + link = process.env.HOME + link.substring(1); + } + + // Resolve workspace path . / .. -> /. / { + if (!isFile) { + return void 0; + } + return this._editorService.openEditor({ resource }).then(() => void 0); + }); + } + + private _handleWindowsLocalLink(link: string): TPromise { + return null; + } +} diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts index 5f7640cd8e7f6..0b418320fbde3 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts @@ -15,12 +15,14 @@ import { ITerminalInstance, ITerminalService, IShellLaunchConfig, KEYBINDING_CON import { TPromise } from 'vs/base/common/winjs.base'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance'; +import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler'; export class TerminalService implements ITerminalService { public _serviceBrand: any; private _activeTerminalInstanceIndex: number; private _configHelper: TerminalConfigHelper; + private _linkHandler: TerminalLinkHandler; private _onActiveInstanceChanged: Emitter; private _onInstanceDisposed: Emitter; private _onInstanceProcessIdReady: Emitter; @@ -57,7 +59,8 @@ export class TerminalService implements ITerminalService { this._configurationService.onDidUpdateConfiguration(() => this.updateConfig()); this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); - this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, platform.platform); + this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, platform.platform); + this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, platform.platform); this.onInstanceDisposed((terminalInstance) => { this._removeInstance(terminalInstance); }); } @@ -65,6 +68,7 @@ export class TerminalService implements ITerminalService { let terminalInstance = this._instantiationService.createInstance(TerminalInstance, this._terminalFocusContextKey, this._configHelper, + this._linkHandler, this._terminalContainer, shell); terminalInstance.addDisposable(terminalInstance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); From 78d081356b52887c6cdb2d676a8ade61a5b6e94c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 Feb 2017 14:04:16 -0800 Subject: [PATCH 4/8] Support windows link regex --- .../electron-browser/terminalLinkHandler.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts index b7404c781fd6a..9379a77d6ed45 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts @@ -12,18 +12,18 @@ import { Platform } from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; const pathPrefix = '(\\.\\.?|\\~)'; -const pathStartClause = '\\/'; +const pathSeparatorClause = '\\/'; const excludedPathCharactersClause = '[^\\0\\s!$`&*()+\'":;]'; // '":; are allowed in paths but they are often separators so ignore them const escapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; /** A regex that matches paths in the form /path, ~/path, ./path, ../path */ -const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathStartClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); +const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); -const winPathPrefix = '(\\.\\.?|\\~)'; -const winPathStartClause = '\\/'; -const winExcludedPathCharactersClause = '[^\\0\\s!$`&*()+\'":;]'; // '":; are allowed in paths but they are often separators so ignore them -const winEscapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; +const winPathPrefix = '([a-zA-Z]:|\\.\\.?|\\~)'; +const winPathSeparatorClause = '(\\\\|\\/)'; +const winExcludedPathCharactersClause = '[^\\0<>\\?\\|\\/\\s!$`&*()+\'":;]'; /** A regex that matches paths in the form c:\path, ~\path, .\path */ -const WINDOWS_LOCAL_LINK_REGEX = new RegExp('(' + winPathPrefix + '?(' + winPathStartClause + '(' + winExcludedPathCharactersClause + '|' + winEscapedExcludedPathCharactersClause + ')+)+)'); +console.log('(' + winPathPrefix + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); +const WINDOWS_LOCAL_LINK_REGEX = new RegExp('(' + winPathPrefix + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); export class TerminalLinkHandler { constructor( From 11298b840e16c9ffc9aef46c55496aaf73808337 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 Feb 2017 14:16:10 -0800 Subject: [PATCH 5/8] Add regex tests --- .../electron-browser/terminalLinkHandler.ts | 1 - .../terminalLinkHandler.test.ts | 50 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts index 9379a77d6ed45..95783d3abcb92 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts @@ -22,7 +22,6 @@ const winPathPrefix = '([a-zA-Z]:|\\.\\.?|\\~)'; const winPathSeparatorClause = '(\\\\|\\/)'; const winExcludedPathCharactersClause = '[^\\0<>\\?\\|\\/\\s!$`&*()+\'":;]'; /** A regex that matches paths in the form c:\path, ~\path, .\path */ -console.log('(' + winPathPrefix + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); const WINDOWS_LOCAL_LINK_REGEX = new RegExp('(' + winPathPrefix + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); export class TerminalLinkHandler { diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts new file mode 100644 index 0000000000000..4b4c5ef51187e --- /dev/null +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { Platform } from 'vs/base/common/platform'; +import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler'; + +suite('Workbench - TerminalLinkHandler', () => { + suite('localLinkRegex', () => { + test('Windows', () => { + const regex = new TerminalLinkHandler(Platform.Windows, null, null).localLinkRegex; + function testLink(link: string) { + assert.equal(` ${link} `.match(regex)[1], link); + assert.equal(`:${link}:`.match(regex)[1], link); + assert.equal(`;${link};`.match(regex)[1], link); + assert.equal(`(${link})`.match(regex)[1], link); + } + testLink('c:\\foo'); + testLink('c:/foo'); + testLink('.\\foo'); + testLink('./foo'); + testLink('..\\foo'); + testLink('../foo'); + testLink('~\\foo'); + testLink('~/foo'); + testLink('c:/a/long/path'); + testLink('c:\\a\\long\\path'); + testLink('c:\\mixed/slash\\path'); + }); + + test('Linux', () => { + const regex = new TerminalLinkHandler(Platform.Linux, null, null).localLinkRegex; + function testLink(link: string) { + assert.equal(` ${link} `.match(regex)[1], link); + assert.equal(`:${link}:`.match(regex)[1], link); + assert.equal(`;${link};`.match(regex)[1], link); + assert.equal(`(${link})`.match(regex)[1], link); + } + testLink('/foo'); + testLink('~/foo'); + testLink('./foo'); + testLink('../foo'); + testLink('/a/long/path'); + }); + }); +}); \ No newline at end of file From 2399c2697513d811417e8bc5a240b9752416c91e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 Feb 2017 15:03:13 -0800 Subject: [PATCH 6/8] Support windows links --- .../electron-browser/terminalLinkHandler.ts | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts index 95783d3abcb92..ebf09bf37b61b 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts @@ -49,9 +49,26 @@ export class TerminalLinkHandler { private _handleUnixLikeLocalLink(link: string): TPromise { // Resolve ~ -> $HOME if (link.charAt(0) === '~') { + if (!process.env.HOME) { + return TPromise.as(void 0); + } link = process.env.HOME + link.substring(1); } + return this._handleCommonLocalLink(link); + } + private _handleWindowsLocalLink(link: string): TPromise { + // Resolve ~ -> %HOMEDRIVE%\%HOMEPATH% + if (link.charAt(0) === '~') { + if (!process.env.HOMEDRIVE || !process.env.HOMEPATH) { + return TPromise.as(void 0); + } + link = `${process.env.HOMEDRIVE}\\${process.env.HOMEPATH + link.substring(1)}`; + } + return this._handleCommonLocalLink(link); + } + + private _handleCommonLocalLink(link: string): TPromise { // Resolve workspace path . / .. -> /. / void 0); }); } - - private _handleWindowsLocalLink(link: string): TPromise { - return null; - } } From adf3a29deaebd3a68629b4671b204a60c71041bf Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 13 Feb 2017 19:34:53 -0800 Subject: [PATCH 7/8] Uplevel xterm.js --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 55dc1daaf66b2..5a439df62b1e1 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -432,7 +432,7 @@ "xterm": { "version": "2.2.3", "from": "Tyriar/xterm.js#vscode-release/1.10", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#90cd66bf353b86ad52d7b650760d8d879dd1c7b8" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#51e66b5fe88158aa22ad808071d4fc0f831f3cf6" }, "yauzl": { "version": "2.3.1", From 1a76f05c9d975a37930bb1f0f44a85088e48cee6 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 13 Feb 2017 19:39:53 -0800 Subject: [PATCH 8/8] Uplevel xterm.js --- npm-shrinkwrap.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 5a439df62b1e1..5328da5bca55d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -430,9 +430,9 @@ "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz" }, "xterm": { - "version": "2.2.3", + "version": "2.3.0", "from": "Tyriar/xterm.js#vscode-release/1.10", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#51e66b5fe88158aa22ad808071d4fc0f831f3cf6" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#5513303451202b0135601a2f026602ed391b3906" }, "yauzl": { "version": "2.3.1",