mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
fix remote terminal suggest (#286407)
This commit is contained in:
@@ -339,6 +339,15 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// `./` by itself means the current directory, use cwd directly to avoid
|
||||
// trailing slash issues with URI.joinPath on some remote file systems.
|
||||
try {
|
||||
await this._fileService.stat(cwd);
|
||||
lastWordFolderResource = cwd;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +377,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
|
||||
case 'tilde': {
|
||||
const home = this._getHomeDir(useWindowsStylePath, capabilities);
|
||||
if (home) {
|
||||
lastWordFolderResource = URI.joinPath(URI.file(home), lastWordFolder.slice(1).replaceAll('\\ ', ' '));
|
||||
lastWordFolderResource = URI.joinPath(createUriFromLocalPath(cwd, home), lastWordFolder.slice(1).replaceAll('\\ ', ' '));
|
||||
}
|
||||
if (!lastWordFolderResource) {
|
||||
// Use less strong wording here as it's not as strong of a concept on Windows
|
||||
@@ -381,9 +390,9 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
|
||||
}
|
||||
case 'absolute': {
|
||||
if (shellType === WindowsShellType.GitBash) {
|
||||
lastWordFolderResource = URI.file(gitBashToWindowsPath(lastWordFolder, this._processEnv.SystemDrive));
|
||||
lastWordFolderResource = createUriFromLocalPath(cwd, gitBashToWindowsPath(lastWordFolder, this._processEnv.SystemDrive));
|
||||
} else {
|
||||
lastWordFolderResource = URI.file(lastWordFolder.replaceAll('\\ ', ' '));
|
||||
lastWordFolderResource = createUriFromLocalPath(cwd, lastWordFolder.replaceAll('\\ ', ' '));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -549,7 +558,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
|
||||
const cdPathEntries = cdPath.split(useWindowsStylePath ? ';' : ':');
|
||||
for (const cdPathEntry of cdPathEntries) {
|
||||
try {
|
||||
const fileStat = await this._fileService.resolve(URI.file(cdPathEntry), { resolveSingleChildDescendants: true });
|
||||
const fileStat = await this._fileService.resolve(createUriFromLocalPath(cwd, cdPathEntry), { resolveSingleChildDescendants: true });
|
||||
if (fileStat?.children) {
|
||||
for (const child of fileStat.children) {
|
||||
if (!child.isDirectory) {
|
||||
@@ -610,7 +619,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
|
||||
let homeResource: URI | string | undefined;
|
||||
const home = this._getHomeDir(useWindowsStylePath, capabilities);
|
||||
if (home) {
|
||||
homeResource = URI.joinPath(URI.file(home), lastWordFolder.slice(1).replaceAll('\\ ', ' '));
|
||||
homeResource = createUriFromLocalPath(cwd, home);
|
||||
}
|
||||
if (!homeResource) {
|
||||
// Use less strong wording here as it's not as strong of a concept on Windows
|
||||
@@ -685,3 +694,15 @@ function getIsAbsolutePath(shellType: TerminalShellType | undefined, pathSeparat
|
||||
}
|
||||
return useWindowsStylePath ? /^[a-zA-Z]:[\\\/]/.test(lastWord) : lastWord.startsWith(pathSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a URI from an absolute path, preserving the scheme and authority from the cwd.
|
||||
* For local file:// URIs, uses URI.file() which handles Windows path normalization.
|
||||
* For remote URIs (e.g., vscode-remote://wsl+Ubuntu), preserves the remote context.
|
||||
*/
|
||||
function createUriFromLocalPath(cwd: URI, absolutePath: string): URI {
|
||||
if (cwd.scheme === 'file') {
|
||||
return URI.file(absolutePath);
|
||||
}
|
||||
return cwd.with({ path: absolutePath });
|
||||
}
|
||||
|
||||
@@ -801,6 +801,87 @@ suite('TerminalCompletionService', () => {
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!isWindows) {
|
||||
suite('remote file completion (e.g. WSL)', () => {
|
||||
const remoteAuthority = 'wsl+Ubuntu';
|
||||
const remoteTestEnv: IProcessEnvironment = {
|
||||
HOME: '/home/remoteuser',
|
||||
USERPROFILE: '/home/remoteuser'
|
||||
};
|
||||
|
||||
test('/absolute/path should preserve remote authority', async () => {
|
||||
terminalCompletionService.processEnv = remoteTestEnv;
|
||||
const resourceOptions: TerminalCompletionResourceOptions = {
|
||||
cwd: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser' }),
|
||||
showDirectories: true,
|
||||
pathSeparator: '/'
|
||||
};
|
||||
validResources = [
|
||||
URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home' }),
|
||||
URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser' }),
|
||||
];
|
||||
childResources = [
|
||||
{ resource: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser' }), isDirectory: true },
|
||||
];
|
||||
const result = await terminalCompletionService.resolveResources(resourceOptions, '/home/', 6, provider, capabilities);
|
||||
|
||||
// Check that results exist and have the correct scheme/authority
|
||||
assert.ok(result && result.length > 0, 'Should return completions for remote absolute path');
|
||||
// Verify completions contain paths resolved via the remote file service (not local file://)
|
||||
const absoluteCompletion = result?.find(c => c.label === '/home/');
|
||||
assert.ok(absoluteCompletion, 'Should have absolute path completion');
|
||||
assert.ok(absoluteCompletion.detail?.includes('/home/'), 'Detail should show remote path');
|
||||
});
|
||||
|
||||
test('~/ should preserve remote authority for tilde expansion', async () => {
|
||||
terminalCompletionService.processEnv = remoteTestEnv;
|
||||
const resourceOptions: TerminalCompletionResourceOptions = {
|
||||
cwd: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project' }),
|
||||
showDirectories: true,
|
||||
pathSeparator: '/'
|
||||
};
|
||||
validResources = [
|
||||
URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser' }),
|
||||
URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project' }),
|
||||
];
|
||||
childResources = [
|
||||
{ resource: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/Documents' }), isDirectory: true },
|
||||
{ resource: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project' }), isDirectory: true },
|
||||
];
|
||||
const result = await terminalCompletionService.resolveResources(resourceOptions, '~/', 2, provider, capabilities);
|
||||
|
||||
// Check that results exist for remote tilde path
|
||||
assert.ok(result && result.length > 0, 'Should return completions for remote tilde path');
|
||||
// Verify the tilde path was resolved using the remote home directory
|
||||
const documentsCompletion = result?.find(c => c.detail?.includes('Documents'));
|
||||
assert.ok(documentsCompletion, 'Should find Documents folder from remote home');
|
||||
});
|
||||
|
||||
test('./relative should preserve remote authority for relative paths', async () => {
|
||||
terminalCompletionService.processEnv = remoteTestEnv;
|
||||
const resourceOptions: TerminalCompletionResourceOptions = {
|
||||
cwd: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project' }),
|
||||
showDirectories: true,
|
||||
pathSeparator: '/'
|
||||
};
|
||||
validResources = [
|
||||
URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project' }),
|
||||
];
|
||||
childResources = [
|
||||
{ resource: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project/src' }), isDirectory: true },
|
||||
{ resource: URI.from({ scheme: 'vscode-remote', authority: remoteAuthority, path: '/home/remoteuser/project/docs' }), isDirectory: true },
|
||||
];
|
||||
const result = await terminalCompletionService.resolveResources(resourceOptions, './', 2, provider, capabilities);
|
||||
|
||||
// Check that results exist for remote relative path
|
||||
assert.ok(result && result.length > 0, 'Should return completions for remote relative path');
|
||||
// Verify completions are from the remote filesystem
|
||||
const srcCompletion = result?.find(c => c.detail?.includes('/home/remoteuser/project/src'));
|
||||
assert.ok(srcCompletion, 'Should find src folder completion with remote path in detail');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
suite('completion label escaping', () => {
|
||||
test('| should escape special characters in file/folder names for POSIX shells', async () => {
|
||||
const resourceOptions: TerminalCompletionResourceOptions = {
|
||||
|
||||
Reference in New Issue
Block a user