From cf6312662f59b8dea1c4ae708f2dc0cc1d12c23b Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 19 Jan 2022 16:07:47 -0600 Subject: [PATCH 1/2] work on #140923 --- .../browser/links/terminalLinkManager.ts | 16 ++++++++-- .../contrib/terminal/browser/terminal.ts | 5 +++ .../terminal/browser/terminalActions.ts | 32 ++++++++++++++++++- .../terminal/browser/terminalInstance.ts | 24 +++++++++++++- .../contrib/terminal/common/terminal.ts | 7 ++-- 5 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts index 88db2388b4ce2..811243cb7da67 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts @@ -101,9 +101,9 @@ export class TerminalLinkManager extends DisposableStore { } async getLinks(y: number): Promise { - let unfilteredWordLinks = (await new Promise(r => this._standardLinkProviders.get(TerminalWordLinkProvider.id)?.provideLinks(y, r))); - const webLinks = (await new Promise(r => this._standardLinkProviders.get(TerminalProtocolLinkProvider.id)?.provideLinks(y, r))); - const fileLinks = (await new Promise(r => this._standardLinkProviders.get(TerminalValidatedLocalLinkProvider.id)?.provideLinks(y, r))); + let unfilteredWordLinks = await this.getLinksForType(y, 'word'); + const webLinks = await this.getLinksForType(y, 'web'); + const fileLinks = await this.getLinksForType(y, 'file'); const words = new Set(); let wordLinks; if (unfilteredWordLinks) { @@ -117,6 +117,16 @@ export class TerminalLinkManager extends DisposableStore { } return { wordLinks, webLinks, fileLinks }; } + async getLinksForType(y: number, type: 'word' | 'web' | 'file'): Promise { + switch (type) { + case 'word': + return (await new Promise(r => this._standardLinkProviders.get(TerminalWordLinkProvider.id)?.provideLinks(y, r))); + case 'web': + return (await new Promise(r => this._standardLinkProviders.get(TerminalProtocolLinkProvider.id)?.provideLinks(y, r))); + case 'file': + return (await new Promise(r => this._standardLinkProviders.get(TerminalValidatedLocalLinkProvider.id)?.provideLinks(y, r))); + } + } private _tooltipCallback(link: TerminalLink, viewportRange: IViewportRange, modifierDownCallback?: () => void, modifierUpCallback?: () => void) { if (!this._widgetManager) { return; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 8fd919d0fd067..022cff2e93f2b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -823,6 +823,11 @@ export interface ITerminalInstance { * re-run it in the active terminal. */ runRecent(type: 'command' | 'cwd'): Promise; + + /** + * Activates the most recent link of the given type. + */ + openRecentLink(type: 'file' | 'web'): Promise; } export interface IXtermTerminal { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index d86abdb1a32a5..48c61c6d7d24e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1918,7 +1918,7 @@ export function registerTerminalActions() { registerAction2(class extends Action2 { constructor() { super({ - id: TerminalCommandId.ShowProtocolLinkQuickpick, + id: TerminalCommandId.SelectDetectedLink, title: { value: localize('workbench.action.terminal.selectDetectedLink', "Select Detected Link"), original: 'Select Detected Link' }, f1: true, category, @@ -1930,6 +1930,36 @@ export function registerTerminalActions() { } }); + registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.OpenWebLink, + title: { value: localize('workbench.action.terminal.openWebLink', "Open Web Link"), original: 'Open Web Link' }, + f1: true, + category, + precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), + }); + } + run(accessor: ServicesAccessor) { + accessor.get(ITerminalService).doWithActiveInstance(t => t.openRecentLink('web')); + } + }); + + registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.OpenFileLink, + title: { value: localize('workbench.action.terminal.openFileLink', "Open File Link"), original: 'Open File Link' }, + f1: true, + category, + precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), + }); + } + run(accessor: ServicesAccessor) { + accessor.get(ITerminalService).doWithActiveInstance(t => t.openRecentLink('file')); + } + }); + registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index e0ba0dba77fc5..4228a9764ffe6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -27,7 +27,7 @@ import { ITerminalProcessManager, ProcessState, TERMINAL_VIEW_ID, INavigationMod import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { ITerminalInstance, ITerminalExternalLinkProvider, IRequestAddInstanceToGroupEvent, TerminalCommand } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalInstance, ITerminalExternalLinkProvider, IRequestAddInstanceToGroupEvent, TerminalCommand, TerminalLinkQuickPickEvent } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; import type { Terminal as XTermTerminal, ITerminalAddon, ILink } from 'xterm'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/xterm/navigationModeAddon'; @@ -700,6 +700,28 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return { wordLinks: wordResults, webLinks: webResults, fileLinks: fileResults }; } + async openRecentLink(type: 'file' | 'web'): Promise { + if (!this.areLinksReady || !this._linkManager) { + throw new Error('terminal links are not ready, cannot open a link'); + } + if (!this.xterm) { + throw new Error('no xterm'); + } + + let links; + let i = this.xterm.raw.buffer.active.viewportY; + while ((!links || links.length === 0) && i <= this.xterm.raw.buffer.active.length) { + links = await this._linkManager.getLinksForType(i, type); + i++; + } + + if (!links || links.length < 1) { + return; + } + const event = new TerminalLinkQuickPickEvent(dom.EventType.CLICK); + links[0].activate(event, links[0].text); + } + async runRecent(type: 'command' | 'cwd'): Promise { const commands = this.xterm?.commandTracker.commands; if (!commands || !this.xterm) { diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 9468747a6fce3..944352e92c0a9 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -453,9 +453,10 @@ export const enum TerminalCommandId { KillAll = 'workbench.action.terminal.killAll', QuickKill = 'workbench.action.terminal.quickKill', ConfigureTerminalSettings = 'workbench.action.terminal.openSettings', - ShowWordLinkQuickpick = 'workbench.action.terminal.showWordLinkQuickpick', - ShowValidatedLinkQuickpick = 'workbench.action.terminal.showValidatedLinkQuickpick', - ShowProtocolLinkQuickpick = 'workbench.action.terminal.showProtocolLinkQuickpick', + SelectDetectedLink = 'workbench.action.terminal.selectDetectedLink', + OpenWordLink = 'workbench.action.terminal.openWordLink', + OpenFileLink = 'workbench.action.terminal.openFileLink', + OpenWebLink = 'workbench.action.terminal.openWebLink', RunRecentCommand = 'workbench.action.terminal.runRecentCommand', GoToRecentDirectory = 'workbench.action.terminal.goToRecentDirectory', CopySelection = 'workbench.action.terminal.copySelection', From b96298bcd3845d12e60dd8ff65bdb4ff0f045a7d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 19 Jan 2022 16:53:52 -0600 Subject: [PATCH 2/2] polish names --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 48c61c6d7d24e..fdf82d1c7d9e2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1934,7 +1934,7 @@ export function registerTerminalActions() { constructor() { super({ id: TerminalCommandId.OpenWebLink, - title: { value: localize('workbench.action.terminal.openWebLink', "Open Web Link"), original: 'Open Web Link' }, + title: { value: localize('workbench.action.terminal.openWebLink', "Open Most Recent Web Link"), original: 'Open Most Recent Web Link' }, f1: true, category, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), @@ -1949,7 +1949,7 @@ export function registerTerminalActions() { constructor() { super({ id: TerminalCommandId.OpenFileLink, - title: { value: localize('workbench.action.terminal.openFileLink', "Open File Link"), original: 'Open File Link' }, + title: { value: localize('workbench.action.terminal.openFileLink', "Open Most Recent File Link"), original: 'Open Most Recent File Link' }, f1: true, category, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),