Skip to content

Commit

Permalink
Add TerminalLinkProvider for absolute paths
Browse files Browse the repository at this point in the history
  • Loading branch information
SchoofsKelvin committed Dec 17, 2020
1 parent d66e278 commit aa17321
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export function activate(context: vscode.ExtensionContext) {
const connectionsTreeProvider = new ConnectionTreeProvider(manager.connectionManager);
subscribe(vscode.window.createTreeView('sshfs-connections', { treeDataProvider: connectionsTreeProvider, showCollapseAll: true }));
subscribe(vscode.tasks.registerTaskProvider('ssh-shell', manager));
subscribe(vscode.window.registerTerminalLinkProvider(manager));

function registerCommandHandler(name: string, handler: CommandHandler) {
const callback = async (arg?: string | FileSystemConfig | Connection | SSHPseudoTerminal | vscode.Uri) => {
Expand Down
46 changes: 45 additions & 1 deletion src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getConfig, getConfigs, loadConfigsRaw } from './config';
import { Connection, ConnectionManager } from './connection';
import type { FileSystemConfig } from './fileSystemConfig';
import { Logging } from './logging';
import { isSSHPseudoTerminal } from './pseudoTerminal';
import type { SSHFileSystem } from './sshFileSystem';
import { catchingPromise, toPromise } from './toPromise';
import type { Navigation } from './webviewMessages';
Expand Down Expand Up @@ -36,7 +37,11 @@ interface SSHShellTaskOptions {
workingDirectory?: string;
}

export class Manager implements vscode.TaskProvider {
interface TerminalLinkUri extends vscode.TerminalLink {
uri?: vscode.Uri;
}

export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider<TerminalLinkUri> {
protected fileSystems: SSHFileSystem[] = [];
protected creatingFileSystems: { [name: string]: Promise<SSHFileSystem> } = {};
public readonly connectionManager = new ConnectionManager();
Expand Down Expand Up @@ -204,6 +209,45 @@ export class Manager implements vscode.TaskProvider {
})
)
}
/* TerminalLinkProvider */
public provideTerminalLinks(context: vscode.TerminalLinkContext, token: vscode.CancellationToken): TerminalLinkUri[] | undefined {
const { line, terminal } = context;
const { creationOptions } = terminal;
if (!('pty' in creationOptions)) return;
const { pty } = creationOptions;
if (!isSSHPseudoTerminal(pty)) return;
const conn = this.connectionManager.getActiveConnections().find(c => c.terminals.includes(pty));
if (!conn) return; // Connection died, which means the terminal should also be closed already?
console.log('provideTerminalLinks', line, pty.config.root, conn ? conn.filesystems.length : 'No connection?');
const links: TerminalLinkUri[] = [];
const PATH_REGEX = /\/\S+/g;
while (true) {
const match = PATH_REGEX.exec(line);
if (!match) break;
const [filepath] = match;
let relative: string | undefined;
for (const fs of conn.filesystems) {
const rel = path.posix.relative(fs.root, filepath);
if (!rel.startsWith('../') && !path.posix.isAbsolute(rel)) {
relative = rel;
break;
}
}
const uri = relative ? vscode.Uri.parse(`ssh://${conn.actualConfig.name}/${relative}`) : undefined;
// TODO: Support absolute path stuff, maybe `ssh://${conn.actualConfig.name}:root//${filepath}` or so?
links.push({
uri,
startIndex: match.index,
length: filepath.length,
tooltip: uri ? '[SSH FS] Open file' : '[SSH FS] Cannot open remote file outside configured root directory',
});
}
return links;
}
public async handleTerminalLink(link: TerminalLinkUri): Promise<void> {
if (!link.uri) return;
await vscode.window.showTextDocument(link.uri);
}
/* Commands (stuff for e.g. context menu for ssh-configs tree) */
public commandConnect(config: FileSystemConfig) {
Logging.info(`Command received to connect ${config.name}`);
Expand Down
5 changes: 5 additions & 0 deletions src/pseudoTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export interface SSHPseudoTerminal extends vscode.Pseudoterminal {
terminal?: vscode.Terminal;
}

export function isSSHPseudoTerminal(terminal: vscode.Pseudoterminal): terminal is SSHPseudoTerminal {
const term = terminal as SSHPseudoTerminal;
return !!(term.config && term.status && term.client);
}

export interface TerminalOptions {
client: Client;
config: FileSystemConfig;
Expand Down
8 changes: 6 additions & 2 deletions src/sshFileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
this.sftp.end();
}
public relative(relPath: string) {
if (relPath.startsWith('/')) relPath = relPath.substr(1);
return path.posix.resolve(this.root, relPath);
// ssh://a/b/c.d should result in relPath being "/b/c.d"
// So // means absolute path, / means relative path
// NOTE: Apparently VSCode automatically replaces multiple slashes with a single /
// (so the // part is useless right now)
if (relPath.startsWith('//')) return relPath.substr(1);
return path.posix.resolve(this.root, relPath.substr(1));
}
public continuePromise<T>(func: (cb: (err: Error | null | undefined, res?: T) => void) => boolean): Promise<T> {
return new Promise<T>((resolve, reject) => {
Expand Down

0 comments on commit aa17321

Please sign in to comment.