Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add open recent web or file link commands #141030

Merged
merged 3 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ export class TerminalLinkManager extends DisposableStore {
}

async getLinks(y: number): Promise<IDetectedLinks | undefined> {
let unfilteredWordLinks = (await new Promise<ILink[] | undefined>(r => this._standardLinkProviders.get(TerminalWordLinkProvider.id)?.provideLinks(y, r)));
const webLinks = (await new Promise<ILink[] | undefined>(r => this._standardLinkProviders.get(TerminalProtocolLinkProvider.id)?.provideLinks(y, r)));
const fileLinks = (await new Promise<ILink[] | undefined>(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) {
Expand All @@ -117,6 +117,16 @@ export class TerminalLinkManager extends DisposableStore {
}
return { wordLinks, webLinks, fileLinks };
}
async getLinksForType(y: number, type: 'word' | 'web' | 'file'): Promise<ILink[] | undefined> {
switch (type) {
case 'word':
return (await new Promise<ILink[] | undefined>(r => this._standardLinkProviders.get(TerminalWordLinkProvider.id)?.provideLinks(y, r)));
case 'web':
return (await new Promise<ILink[] | undefined>(r => this._standardLinkProviders.get(TerminalProtocolLinkProvider.id)?.provideLinks(y, r)));
case 'file':
return (await new Promise<ILink[] | undefined>(r => this._standardLinkProviders.get(TerminalValidatedLocalLinkProvider.id)?.provideLinks(y, r)));
}
}
private _tooltipCallback(link: TerminalLink, viewportRange: IViewportRange, modifierDownCallback?: () => void, modifierUpCallback?: () => void) {
if (!this._widgetManager) {
return;
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/contrib/terminal/browser/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,11 @@ export interface ITerminalInstance {
* re-run it in the active terminal.
*/
runRecent(type: 'command' | 'cwd'): Promise<void>;

/**
* Activates the most recent link of the given type.
*/
openRecentLink(type: 'file' | 'web'): Promise<void>;
}

export interface IXtermTerminal {
Expand Down
32 changes: 31 additions & 1 deletion src/vs/workbench/contrib/terminal/browser/terminalActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1918,7 +1918,7 @@ export function registerTerminalActions() {
registerAction2(class extends Action2 {
constructor() {
super({
id: TerminalCommandId.ShowProtocolLinkQuickpick,
id: TerminalCommandId.SelectDetectedLink,
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
title: { value: localize('workbench.action.terminal.selectDetectedLink', "Select Detected Link"), original: 'Select Detected Link' },
f1: true,
category,
Expand All @@ -1930,6 +1930,36 @@ export function registerTerminalActions() {
}
});

registerAction2(class extends Action2 {
constructor() {
super({
id: TerminalCommandId.OpenWebLink,
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),
});
}
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 Most Recent File Link"), original: 'Open Most Recent 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({
Expand Down
24 changes: 23 additions & 1 deletion src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -700,6 +700,28 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
return { wordLinks: wordResults, webLinks: webResults, fileLinks: fileResults };
}

async openRecentLink(type: 'file' | 'web'): Promise<void> {
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<void> {
const commands = this.xterm?.commandTracker.commands;
if (!commands || !this.xterm) {
Expand Down
7 changes: 4 additions & 3 deletions src/vs/workbench/contrib/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down