提交 81762241 编写于 作者: D Daniel Imms 提交者: GitHub

Merge pull request #22602 from markwpearce/feature/relative_paths

Checks integrated terminal output for more types of relative paths
......@@ -19,15 +19,14 @@ const pathPrefix = '(\\.\\.?|\\~)';
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 + '?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)');
const winPathPrefix = '([a-zA-Z]:|\\.\\.?|\\~)';
/** A regex that matches paths in the form /foo, ~/foo, ./foo, ../foo, foo/bar */
const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('((' + pathPrefix + '|(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)');
const winDrivePrefix = '[a-zA-Z]:';
const winPathPrefix = '(' + winDrivePrefix + '|\\.\\.?|\\~)';
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 + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)');
/** A regex that matches paths in the form c:\foo, ~\foo, .\foo, ..\foo, foo\bar */
const WINDOWS_LOCAL_LINK_REGEX = new RegExp('((' + winPathPrefix + '|(' + winExcludedPathCharactersClause + ')+)?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)');
/** Higher than local link, lower than hypertext */
const CUSTOM_LINK_PRIORITY = -1;
/** Lowest */
......@@ -140,33 +139,42 @@ export class TerminalLinkHandler {
}));
}
private _resolvePath(link: string): TPromise<string> {
protected _preprocessPath(link: string): string {
if (this._platform === platform.Platform.Windows) {
// Resolve ~ -> %HOMEDRIVE%\%HOMEPATH%
if (link.charAt(0) === '~') {
if (!process.env.HOMEDRIVE || !process.env.HOMEPATH) {
return TPromise.as(void 0);
return null;
}
link = `${process.env.HOMEDRIVE}\\${process.env.HOMEPATH + link.substring(1)}`;
}
} else {
// Resolve workspace path . / .. -> <path>/. / <path/..
if (link.charAt(0) === '.') {
if (!this._contextService.hasWorkspace) {
// Resolve relative paths (.\a, ..\a, ~\a, a\b)
if (!link.match('^' + winDrivePrefix)) {
if (!this._contextService.hasWorkspace()) {
// Abort if no workspace is open
return TPromise.as(void 0);
return null;
}
link = path.join(this._contextService.getWorkspace().resource.fsPath, link);
}
}
// Resolve workspace path . / .. -> <path>/. / <path/..
if (link.charAt(0) === '.') {
if (!this._contextService.hasWorkspace) {
// Resolve workspace path . | .. | <relative_path> -> <path>/. | <path>/.. | <path>/<relative_path>
else if (link.charAt(0) !== '/' && link.charAt(0) !== '~') {
if (!this._contextService.hasWorkspace()) {
// Abort if no workspace is open
return TPromise.as(void 0);
return null;
}
link = path.join(this._contextService.getWorkspace().resource.fsPath, link);
}
return link;
}
private _resolvePath(link: string): TPromise<string> {
link = this._preprocessPath(link);
if (!link) {
return TPromise.as(void 0);
}
// Open an editor if the path exists
return pfs.fileExists(link).then(isFile => {
......
......@@ -8,11 +8,18 @@
import * as assert from 'assert';
import { Platform } from 'vs/base/common/platform';
import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler';
import { IWorkspace, WorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
import * as path from 'path';
import * as sinon from 'sinon';
class TestTerminalLinkHandler extends TerminalLinkHandler {
public get localLinkRegex(): RegExp {
return this._localLinkRegex;
}
public preprocessPath(link: string): string {
return this._preprocessPath(link);
}
}
class TestXterm {
......@@ -20,6 +27,23 @@ class TestXterm {
public setHypertextValidationCallback() { }
}
class TestURI extends URI {
constructor(private _fakePath: string) {
super();
};
get fsPath(): string {
return this._fakePath;
}
}
class TestWorkspace implements IWorkspace {
resource: URI;
constructor(basePath: string) {
this.resource = new TestURI(basePath);
}
}
suite('Workbench - TerminalLinkHandler', () => {
suite('localLinkRegex', () => {
test('Windows', () => {
......@@ -41,6 +65,7 @@ suite('Workbench - TerminalLinkHandler', () => {
testLink('c:/a/long/path');
testLink('c:\\a\\long\\path');
testLink('c:\\mixed/slash\\path');
testLink('a/relative/path');
});
test('Linux', () => {
......@@ -56,6 +81,45 @@ suite('Workbench - TerminalLinkHandler', () => {
testLink('./foo');
testLink('../foo');
testLink('/a/long/path');
testLink('a/relative/path');
});
});
suite('preprocessPath', () => {
test('Windows', () => {
const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Windows, null,
new WorkspaceContextService(new TestWorkspace('C:\\base')));
let stub = sinon.stub(path, 'join', function (arg1, arg2) {
return arg1 + '\\' + arg2;
});
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\./src/file1');
assert.equal(linkHandler.preprocessPath('src\\file2'), 'C:\\base\\src\\file2');
assert.equal(linkHandler.preprocessPath('C:\\absolute\\path\\file3'), 'C:\\absolute\\path\\file3');
stub.restore();
});
test('Linux', () => {
const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Linux, null,
new WorkspaceContextService(new TestWorkspace('/base')));
let stub = sinon.stub(path, 'join', function (arg1, arg2) {
return arg1 + '/' + arg2;
});
assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/./src/file1');
assert.equal(linkHandler.preprocessPath('src/file2'), '/base/src/file2');
assert.equal(linkHandler.preprocessPath('/absolute/path/file3'), '/absolute/path/file3');
stub.restore();
});
test('No Workspace', () => {
const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Linux, null, new WorkspaceContextService(null));
assert.equal(linkHandler.preprocessPath('./src/file1'), null);
assert.equal(linkHandler.preprocessPath('src/file2'), null);
assert.equal(linkHandler.preprocessPath('/absolute/path/file3'), '/absolute/path/file3');
});
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册