diff --git a/resources/defaultConfig.jsonc b/resources/defaultConfig.jsonc index e6151aa..d676cfb 100644 --- a/resources/defaultConfig.jsonc +++ b/resources/defaultConfig.jsonc @@ -1,5 +1,6 @@ // If you haven't already, associate .jsonc files with "JSON with Comments (jsonc)" { + "label": "An optional label for a good name", "root": "/tmp", "host": "localhost", "port": 22, diff --git a/src/extension.ts b/src/extension.ts index e58ced6..15c20c8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,13 +8,18 @@ const workspace = vscode.workspace; async function pickConfig(manager: Manager, activeOrNot?: boolean) { let names = manager.getActive(); - const others = manager.loadConfigs().map(c => c.name); + const others = manager.loadConfigs(); if (activeOrNot === false) { - names = others.filter(n => names.indexOf(n) === -1); + names = others.filter(c => !names.find(cc => cc.name === c.name)); } else if (activeOrNot === undefined) { others.forEach(n => names.indexOf(n) === -1 && names.push(n)); } - return vscode.window.showQuickPick(names, { placeHolder: 'SSH FS Configuration' }); + const options: vscode.QuickPickItem[] = names.map(config => ({ + label: config.label || config.name, + description: config.label && config.name, + })); + const pick = await vscode.window.showQuickPick(options, { placeHolder: 'SSH FS Configuration' }); + return pick && pick.detail; } export function activate(context: vscode.ExtensionContext) { diff --git a/src/manager.ts b/src/manager.ts index 07d0a4c..339064a 100644 --- a/src/manager.ts +++ b/src/manager.ts @@ -18,6 +18,7 @@ async function assertFs(man: Manager, uri: vscode.Uri) { export interface FileSystemConfig extends ConnectConfig { name: string; + label?: string; root?: string; putty?: string | boolean; } @@ -27,7 +28,7 @@ function createTreeItem(manager: Manager, name: string): vscode.TreeItem { const folders = vscode.workspace.workspaceFolders || []; const active = folders.some(f => f.uri.scheme === 'ssh' && f.uri.authority === name); return { - label: name, + label: config && config.label || name, contextValue: active ? 'active' : 'inactive', tooltip: config ? (active ? 'Active' : 'Inactive') : 'Active but deleted', }; @@ -40,15 +41,14 @@ function createConfigFs(manager: Manager): SSHFileSystem { stat: (uri: vscode.Uri) => ({ type: vscode.FileType.File, ctime: 0, mtime: 0, size: 0 } as vscode.FileStat), readFile: async (uri: vscode.Uri) => { const name = uri.path.substring(1, uri.path.length - 12); - let config = manager.getConfig(name); + const config = manager.getConfig(name); let str; if (config) { - str = JSON.stringify(config, undefined, 4); + str = JSON.stringify({ ...config, name: undefined }, undefined, 4); str = `// If you haven't already, associate .jsonc files with "JSON with Comments (jsonc)"\n${str}`; } else { str = await toPromise(cb => readFile(path.resolve(__dirname, '../resources/defaultConfig.jsonc'), 'utf-8', cb)); } - config = { ...config, name: undefined! }; return new Uint8Array(new Buffer(str)); }, writeFile: (uri: vscode.Uri, content: Uint8Array) => { @@ -112,7 +112,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid public invalidConfigName(name: string) { if (!name) return 'Missing a name for this SSH FS'; if (name.match(/^[\w_\\\/\.@\-+]+$/)) return null; - return `A SSH FS name can only exists of alphanumeric characters, slashes and any of these: _.+-@`; + return `A SSH FS name can only exists of lowercase alphanumeric characters, slashes and any of these: _.+-@`; } public getConfig(name: string) { if (name === '') return null; @@ -135,7 +135,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid let promise = this.creatingFileSystems[name]; if (promise) return promise; // config = config || this.memento.get(`fs.config.${name}`); - config = config || (await this.loadConfigs()).find(c => c.name === name); + config = config || this.loadConfigs().find(c => c.name === name); promise = new Promise(async (resolve, reject) => { if (!config) { throw new Error(`A SSH filesystem with the name '${name}' doesn't exist`); @@ -200,7 +200,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid return reject(err); } sftp.on('end', () => client.end()); - const fs = new SSHFileSystem(name, sftp, config!.root || '/'); + const fs = new SSHFileSystem(name, sftp, config!.root || '/', config!); this.fileSystems.push(fs); delete this.creatingFileSystems[name]; vscode.commands.executeCommand('workbench.files.action.refreshFilesExplorer'); @@ -241,7 +241,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid return this.creatingFileSystems[name] = promise; } public getActive() { - return this.fileSystems.map(fs => fs.authority); + return this.fileSystems.map(fs => fs.config); } public async getFs(uri: vscode.Uri) { const fs = this.fileSystems.find(f => f.authority === uri.authority); @@ -310,7 +310,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid this.commandConnect(name); } public commandConnect(name: string) { - if (this.getActive().indexOf(name) !== -1) return vscode.commands.executeCommand('workbench.files.action.refreshFilesExplorer'); + if (this.getActive().find(fs => fs.name === name)) return vscode.commands.executeCommand('workbench.files.action.refreshFilesExplorer'); const folders = vscode.workspace.workspaceFolders!; const folder = folders && folders.find(f => f.uri.scheme === 'ssh' && f.uri.authority === name); if (folder) { @@ -337,6 +337,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid ...(inspect.workspaceValue || []), ...(inspect.globalValue || []), ]; + configs.forEach(c => c.name = c.name.toLowerCase()); configs = configs.filter((c, i) => configs.findIndex(c2 => c2.name === c.name) === i); for (const index in configs) { if (!configs[index].name) { diff --git a/src/sshFileSystem.ts b/src/sshFileSystem.ts index d6820c6..e5b9dba 100644 --- a/src/sshFileSystem.ts +++ b/src/sshFileSystem.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as ssh2 from 'ssh2'; import * as ssh2s from 'ssh2-streams'; import * as vscode from 'vscode'; - +import { FileSystemConfig } from './manager'; import { toPromise } from './toPromise'; export class SSHFileSystem implements vscode.FileSystemProvider { @@ -11,7 +11,8 @@ export class SSHFileSystem implements vscode.FileSystemProvider { public onDidChangeFile: vscode.Event; protected onDidChangeFileEmitter = new vscode.EventEmitter(); - constructor(public readonly authority: string, protected sftp: ssh2.SFTPWrapper, public readonly root: string) { + constructor(public readonly authority: string, protected sftp: ssh2.SFTPWrapper, + public readonly root: string, public readonly config: FileSystemConfig) { this.onDidChangeFile = this.onDidChangeFileEmitter.event; }