提交 f76f79ed 编写于 作者: D Daniel Imms

Open file when terminal word links match a single file in all workspaces

This uses all workspaces as terminals are somewhat divorced from
workspaces with their initial cwd. Because of this I suspect it could
get more confusing in multi-root workspaces if we tried to be clever and
only search a single workspace.

Fixes #95119
上级 8a505159
......@@ -30,6 +30,8 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { isEqualOrParent } from 'vs/base/common/resources';
import { ISearchService } from 'vs/workbench/services/search/common/search';
import { QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
const pathPrefix = '(\\.\\.?|\\~)';
const pathSeparatorClause = '\\/';
......@@ -91,6 +93,7 @@ export class TerminalLinkManager extends DisposableStore {
private _webLinksAddon: ITerminalAddon | undefined;
private _linkProviders: IDisposable[] = [];
private _hasBeforeHandleLinkListeners = false;
private readonly _fileQueryBuilder = this._instantiationService.createInstance(QueryBuilder);
protected static _LINK_INTERCEPT_THRESHOLD = LINK_INTERCEPT_THRESHOLD;
public static readonly LINK_INTERCEPT_THRESHOLD = TerminalLinkManager._LINK_INTERCEPT_THRESHOLD;
......@@ -120,7 +123,8 @@ export class TerminalLinkManager extends DisposableStore {
@IQuickInputService private readonly _quickInputService: IQuickInputService,
@ICommandService private readonly _commandService: ICommandService,
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
@IHostService private readonly _hostService: IHostService
@IHostService private readonly _hostService: IHostService,
@ISearchService private readonly _searchService: ISearchService
) {
super();
......@@ -322,7 +326,24 @@ export class TerminalLinkManager extends DisposableStore {
const tooltipWordCallback = (event: MouseEvent, link: string, location: IViewportRange) => {
this._tooltipCallback(event, link, location, link => this._quickInputService.quickAccess.show(link));
};
const wrappedWordActivateCallback = this._wrapLinkHandler(link => this._quickInputService.quickAccess.show(link));
const wrappedWordActivateCallback = this._wrapLinkHandler(async link => {
const results = await this._searchService.fileSearch(
this._fileQueryBuilder.file(this._workspaceContextService.getWorkspace().folders, {
filePattern: link,
maxResults: 2
})
);
// If there was exactly one match, open it
if (results.results.length === 1) {
const match = results.results[0];
await this._editorService.openEditor({ resource: match.resource, options: { pinned: true } });
return;
}
// Fallback to searching quick access
this._quickInputService.quickAccess.show(link);
});
this._linkProviders.push(this._xterm.registerLinkProvider(
this._instantiationService.createInstance(TerminalWordLinkProvider, this._xterm, wrappedWordActivateCallback, tooltipWordCallback, this._leaveCallback)
));
......
......@@ -11,6 +11,10 @@ import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/
import { Event } from 'vs/base/common/event';
import { ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { TestRemotePathService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices';
import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
class TestTerminalLinkManager extends TerminalLinkManager {
public get localLinkRegex(): RegExp {
......@@ -84,12 +88,20 @@ const testConfigHelper: ITerminalConfigHelper = <any>{
};
suite('Workbench - TerminalLinkHandler', () => {
let instantiationService: TestInstantiationService;
setup(() => {
instantiationService = new TestInstantiationService();
instantiationService.stub(IEnvironmentService, TestEnvironmentService);
instantiationService.stub(IRemotePathService, new TestRemotePathService(TestEnvironmentService));
});
suite('localLinkRegex', () => {
test('Windows', () => {
const terminalLinkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Windows,
userHome: ''
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) {
assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl);
assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl);
......@@ -165,7 +177,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const terminalLinkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) {
assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl);
assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl);
......@@ -233,7 +245,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\Me'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
linkHandler.processCwd = 'C:\\base';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1');
......@@ -246,7 +258,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\M e'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
linkHandler.processCwd = 'C:\\base dir';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1');
......@@ -260,7 +272,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
linkHandler.processCwd = '/base';
assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1');
......@@ -273,7 +285,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
assert.equal(linkHandler.preprocessPath('./src/file1'), null);
assert.equal(linkHandler.preprocessPath('src/file2'), null);
......@@ -287,7 +299,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
function assertAreGoodMatches(matches: RegExpMatchArray | null) {
if (matches) {
......@@ -318,7 +330,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any, testConfigHelper, null!, null!, new TestConfigurationService(), new MockTerminalInstanceService(), null!, null!, null!, null!);
} as any, testConfigHelper, null!, null!, new TestConfigurationService(), new MockTerminalInstanceService(), null!, null!, instantiationService, null!, null!, null!, null!, null!);
linkHandler.onBeforeHandleLink(e => {
if (e.link === 'https://www.microsoft.com') {
intercepted = true;
......
......@@ -8,6 +8,7 @@ import { TerminalValidatedLocalLinkProvider } from 'vs/workbench/contrib/termina
import { Terminal, ILink, IBufferRange, IBufferCellPosition } from 'xterm';
import { OperatingSystem } from 'vs/base/common/platform';
import { format } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
const unixLinks = [
'/foo',
......@@ -66,7 +67,7 @@ const supportedLinkFormats: LinkFormatInfo[] = [
suite('Workbench - TerminalValidatedLocalLinkProvider', () => {
async function assertLink(text: string, os: OperatingSystem, expected: { text: string, range: [number, number][] }) {
const xterm = new Terminal();
const provider = new TerminalValidatedLocalLinkProvider(xterm, os, () => { }, () => { }, () => { }, (_, cb) => { cb(true); });
const provider = new TerminalValidatedLocalLinkProvider(xterm, os, () => { }, () => { }, () => { }, () => { }, (_, cb) => { cb({ uri: URI.file('/'), isDirectory: false }); });
// Write the text and wait for the parser to finish
await new Promise<void>(r => xterm.write(text, r));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册