Skip to content
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 @@ -70,11 +70,11 @@ export class TerminalLinkManager extends DisposableStore {
}

// Setup link detectors in their order of priority
this._setupLinkDetector(TerminalUriLinkDetector.id, this._instantiationService.createInstance(TerminalUriLinkDetector, this._xterm, this._processInfo, this._linkResolver));
if (enableFileLinks) {
this._setupLinkDetector(TerminalMultiLineLinkDetector.id, this._instantiationService.createInstance(TerminalMultiLineLinkDetector, this._xterm, this._processInfo, this._linkResolver));
this._setupLinkDetector(TerminalLocalLinkDetector.id, this._instantiationService.createInstance(TerminalLocalLinkDetector, this._xterm, capabilities, this._processInfo, this._linkResolver));
}
this._setupLinkDetector(TerminalUriLinkDetector.id, this._instantiationService.createInstance(TerminalUriLinkDetector, this._xterm, this._processInfo, this._linkResolver));
this._setupLinkDetector(TerminalWordLinkDetector.id, this.add(this._instantiationService.createInstance(TerminalWordLinkDetector, this._xterm)));

// Setup link openers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ function parseIntOptional(value: string | undefined): number | undefined {
// characters the path is not allowed to _start_ with, the second `[]` includes characters not
// allowed at all in the path. If the characters show up in both regexes the link will stop at that
// character, otherwise it will stop at a space character.
const linkWithSuffixPathCharacters = /(?<path>[^\s\|<>\[\({][^\s\|<>]*)$/;
const linkWithSuffixPathCharacters = /(?<path>(?:file:\/\/\/)?[^\s\|<>\[\({][^\s\|<>]*)$/;

export function detectLinks(line: string, os: OperatingSystem) {
// 1: Detect all links on line via suffixes first
Expand Down Expand Up @@ -303,7 +303,7 @@ function detectLinksViaSuffix(line: string): IParsedLink[] {
}

enum RegexPathConstants {
PathPrefix = '(?:\\.\\.?|\\~)',
PathPrefix = '(?:\\.\\.?|\\~|file:\/\/)',
PathSeparatorClause = '\\/',
// '":; are allowed in paths but they are often separators so ignore them
// Also disallow \\ to prevent a catastropic backtracking case #24795
Expand All @@ -323,10 +323,10 @@ enum RegexPathConstants {
const unixLocalLinkClause = '(?:(?:' + RegexPathConstants.PathPrefix + '|(?:' + RegexPathConstants.ExcludedStartPathCharactersClause + RegexPathConstants.ExcludedPathCharactersClause + '*))?(?:' + RegexPathConstants.PathSeparatorClause + '(?:' + RegexPathConstants.ExcludedPathCharactersClause + ')+)+)';

/**
* A regex clause that matches the start of an absolute path on Windows, such as: `C:`, `c:` and
* `\\?\C` (UNC path).
* A regex clause that matches the start of an absolute path on Windows, such as: `C:`, `c:`,
* `file:///c:` (uri) and `\\?\C:` (UNC path).
*/
export const winDrivePrefix = '(?:\\\\\\\\\\?\\\\)?[a-zA-Z]:';
export const winDrivePrefix = '(?:\\\\\\\\\\?\\\\|file:\\/\\/\\/)?[a-zA-Z]:';

/**
* A regex that matches Windows paths, such as `\\?\c:\foo`, `c:\foo`, `~\foo`, `.\foo`, `..\foo`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ export class TerminalLocalLinkDetector implements ITerminalLinkDetector {
// Get a single link candidate if the cwd of the line is known
const linkCandidates: string[] = [];
const osPath = osPathModule(os);
if (osPath.isAbsolute(parsedLink.path.text) || parsedLink.path.text.startsWith('~')) {
const isUri = parsedLink.path.text.startsWith('file://');
if (osPath.isAbsolute(parsedLink.path.text) || parsedLink.path.text.startsWith('~') || isUri) {
linkCandidates.push(parsedLink.path.text);
} else {
if (this._capabilities.has(TerminalCapability.CommandDetection)) {
Expand Down Expand Up @@ -265,7 +266,11 @@ export class TerminalLocalLinkDetector implements ITerminalLinkDetector {

private async _validateLinkCandidates(linkCandidates: string[]): Promise<ResolvedLink | undefined> {
for (const link of linkCandidates) {
const result = await this._linkResolver.resolveLink(this._processManager, link);
let uri: URI | undefined;
if (link.startsWith('file://')) {
uri = URI.parse(link);
}
const result = await this._linkResolver.resolveLink(this._processManager, link, uri);
if (result) {
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ITerminalLinkDetector, ITerminalLinkResolver, ITerminalSimpleLink, Term
import { convertLinkRangeToBuffer, getXtermLineContent } from 'vs/workbench/contrib/terminalContrib/links/browser/terminalLinkHelpers';
import { ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal';
import type { IBufferLine, Terminal } from '@xterm/xterm';
import { ITerminalBackend } from 'vs/platform/terminal/common/terminal';
import { ITerminalBackend, ITerminalLogService } from 'vs/platform/terminal/common/terminal';

const enum Constants {
/**
Expand All @@ -32,6 +32,7 @@ export class TerminalUriLinkDetector implements ITerminalLinkDetector {
readonly xterm: Terminal,
private readonly _processManager: Pick<ITerminalProcessManager, 'initialCwd' | 'os' | 'remoteAuthority' | 'userHome'> & { backend?: Pick<ITerminalBackend, 'getWslPath'> },
private readonly _linkResolver: ITerminalLinkResolver,
@ITerminalLogService private readonly _logService: ITerminalLogService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService,
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService
) {
Expand All @@ -44,6 +45,7 @@ export class TerminalUriLinkDetector implements ITerminalLinkDetector {
const computedLinks = LinkComputer.computeLinks(linkComputerTarget);

let resolvedLinkCount = 0;
this._logService.trace('terminalUriLinkDetector#detect computedLinks', computedLinks);
for (const computedLink of computedLinks) {
const bufferRange = convertLinkRangeToBuffer(lines, this.xterm.cols, computedLink.range, startLine);

Expand Down Expand Up @@ -88,6 +90,7 @@ export class TerminalUriLinkDetector implements ITerminalLinkDetector {
}

// Iterate over all candidates, pushing the candidate on the first that's verified
this._logService.trace('terminalUriLinkDetector#detect uriCandidates', uriCandidates);
for (const uriCandidate of uriCandidates) {
const linkStat = await this._linkResolver.resolveLink(this._processManager, text, uriCandidate);

Expand All @@ -103,13 +106,15 @@ export class TerminalUriLinkDetector implements ITerminalLinkDetector {
} else {
type = TerminalBuiltinLinkType.LocalFile;
}
links.push({
const simpleLink: ITerminalSimpleLink = {
// Use computedLink.url if it's a string to retain the line/col suffix
text: typeof computedLink.url === 'string' ? computedLink.url : linkStat.link,
uri: uriCandidate,
bufferRange,
type
});
};
this._logService.trace('terminalUriLinkDetector#detect verified link', simpleLink);
links.push(simpleLink);
resolvedLinkCount++;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const unixLinks: (string | { link: string; resource: URI })[] = [
'/foo/[bar].baz',
'/foo/[bar]/baz',
'/foo/bar+more',
// URI file://
{ link: 'file:///foo', resource: URI.file('/foo') },
{ link: 'file:///foo/bar', resource: URI.file('/foo/bar') },
{ link: 'file:///foo/bar%20baz', resource: URI.file('/foo/bar baz') },
// User home
{ link: '~/foo', resource: URI.file('/home/foo') },
// Relative
Expand All @@ -51,6 +55,10 @@ const windowsLinks: (string | { link: string; resource: URI })[] = [
'c:\\foo\\bar',
'c:\\foo\\bar+more',
'c:\\foo/bar\\baz',
// URI file://
{ link: 'file:///c:/foo', resource: URI.file('c:\\foo') },
{ link: 'file:///c:/foo/bar', resource: URI.file('c:\\foo\\bar') },
{ link: 'file:///c:/foo/bar%20baz', resource: URI.file('c:\\foo\\bar baz') },
// User home
{ link: '~\\foo', resource: URI.file('C:\\Home\\foo') },
{ link: '~/foo', resource: URI.file('C:\\Home\\foo') },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import type { Terminal } from '@xterm/xterm';
import { OperatingSystem } from 'vs/base/common/platform';
import { importAMDNodeModule } from 'vs/amdX';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { NullLogService } from 'vs/platform/log/common/log';
import { ITerminalLogService } from 'vs/platform/terminal/common/terminal';

suite('Workbench - TerminalUriLinkDetector', () => {
const store = ensureNoDisposablesAreLeakedInTestSuite();
Expand All @@ -39,6 +41,7 @@ suite('Workbench - TerminalUriLinkDetector', () => {
return createFileStat(resource);
}
});
instantiationService.stub(ITerminalLogService, new NullLogService());
validResources = [];

const TerminalCtor = (await importAMDNodeModule<typeof import('@xterm/xterm')>('@xterm/xterm', 'lib/xterm.js')).Terminal;
Expand Down