Add group support to the TreeDataProvider

pull/133/head
Kelvin Schoofs 6 years ago
parent 1965f51b08
commit a3891ba026

@ -28,14 +28,18 @@ export function getLocations(configs: FileSystemConfig[]): ConfigLocation[] {
return res; return res;
} }
export function getGroups(configs: FileSystemConfig[]): string[] { export function getGroups(configs: FileSystemConfig[], expanded = false): string[] {
const res: string[] = []; const res: string[] = [];
for (const { group } of configs) { function addGroup(group: string) {
if (!group) continue;
if (!res.find(l => l === group)) { if (!res.find(l => l === group)) {
res.push(group); res.push(group);
} }
} }
for (const { group } of configs) {
if (!group) continue;
const groups = expanded ? group.split('.') : [group];
groups.forEach((g, i) => addGroup([...groups.slice(0, i), g].join('.')));
}
return res; return res;
} }

@ -2,7 +2,7 @@
import { Client, ClientChannel } from 'ssh2'; import { Client, ClientChannel } from 'ssh2';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { getConfig, getConfigs, loadConfigs, loadConfigsRaw, UPDATE_LISTENERS } from './config'; import { getConfig, getConfigs, loadConfigs, loadConfigsRaw, UPDATE_LISTENERS } from './config';
import { FileSystemConfig } from './fileSystemConfig'; import { FileSystemConfig, getGroups } from './fileSystemConfig';
import * as Logging from './logging'; import * as Logging from './logging';
import SSHFileSystem, { EMPTY_FILE_SYSTEM } from './sshFileSystem'; import SSHFileSystem, { EMPTY_FILE_SYSTEM } from './sshFileSystem';
import { catchingPromise, toPromise } from './toPromise'; import { catchingPromise, toPromise } from './toPromise';
@ -53,13 +53,18 @@ export enum ConfigStatus {
Error = 'Error', Error = 'Error',
} }
function createTreeItem(manager: Manager, name: string): vscode.TreeItem { function createTreeItem(manager: Manager, item: string | FileSystemConfig): vscode.TreeItem {
const config = getConfig(name); if (typeof item === 'string') {
return {
label: item.replace(/^.+\./, ''),
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
};
}
const folders = vscode.workspace.workspaceFolders || []; const folders = vscode.workspace.workspaceFolders || [];
const isConnected = folders.some(f => f.uri.scheme === 'ssh' && f.uri.authority === name); const isConnected = folders.some(f => f.uri.scheme === 'ssh' && f.uri.authority === item.name);
const status = manager.getStatus(name); const status = manager.getStatus(item.name);
return { return {
label: config && config.label || name, label: item && item.label || item.name,
contextValue: isConnected ? 'active' : 'inactive', contextValue: isConnected ? 'active' : 'inactive',
tooltip: status === 'Deleted' ? 'Active but deleted' : status, tooltip: status === 'Deleted' ? 'Active but deleted' : status,
iconPath: manager.context.asAbsolutePath(`resources/config/${status}.png`), iconPath: manager.context.asAbsolutePath(`resources/config/${status}.png`),
@ -79,7 +84,7 @@ async function tryGetHome(ssh: Client): Promise<string | null> {
return mat[1]; return mat[1];
} }
export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvider<string> { export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvider<string | FileSystemConfig> {
public onDidChangeTreeData: vscode.Event<string>; public onDidChangeTreeData: vscode.Event<string>;
public onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]>; public onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]>;
protected fileSystems: SSHFileSystem[] = []; protected fileSystems: SSHFileSystem[] = [];
@ -183,7 +188,7 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid
vscode.window.showErrorMessage(`Error while connecting to SSH FS ${name}:\n${e.message}`, 'Retry', 'Configure', 'Ignore').then((chosen) => { vscode.window.showErrorMessage(`Error while connecting to SSH FS ${name}:\n${e.message}`, 'Retry', 'Configure', 'Ignore').then((chosen) => {
delete this.creatingFileSystems[name]; delete this.creatingFileSystems[name];
if (chosen === 'Retry') { if (chosen === 'Retry') {
this.createFileSystem(name).catch(() => {}); this.createFileSystem(name).catch(() => { });
} else if (chosen === 'Configure') { } else if (chosen === 'Configure') {
this.commandConfigure(name); this.commandConfigure(name);
} else { } else {
@ -251,15 +256,22 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid
return fs.rename(oldUri, newUri, options); return fs.rename(oldUri, newUri, options);
} }
/* TreeDataProvider */ /* TreeDataProvider */
public getTreeItem(element: string): vscode.TreeItem | Thenable<vscode.TreeItem> { public getTreeItem(element: string | FileSystemConfig): vscode.TreeItem | Thenable<vscode.TreeItem> {
return createTreeItem(this, element); return createTreeItem(this, element);
} }
public getChildren(element?: string | undefined): vscode.ProviderResult<string[]> { public getChildren(element: string | FileSystemConfig = ''): vscode.ProviderResult<(string | FileSystemConfig)[]> {
const configs = getConfigs().map(c => c.name); if (typeof element === 'object') return []; // FileSystemConfig, has no children
this.fileSystems.forEach(fs => configs.indexOf(fs.authority) === -1 && configs.push(fs.authority)); const configs = this.fileSystems.map(fs => fs.config);
const folders = vscode.workspace.workspaceFolders || []; configs.push(...getConfigs().filter(c => !configs.find(fs => c.name === fs.name)));
folders.filter(f => f.uri.scheme === 'ssh').forEach(f => configs.indexOf(f.uri.authority) === -1 && configs.push(f.uri.authority)); const matching = configs.filter(({ group }) => (group || '') === element);
return configs.filter((c, i) => configs.indexOf(c) === i); matching.sort((a,b) => a.name > b.name ? 1 : -1);
let groups = getGroups(configs, true);
if (element) {
groups = groups.filter(g => g.startsWith(element) && g[element.length] === '.' && !g.includes('.', element.length + 1));
} else {
groups = groups.filter(g => !g.includes('.'));
}
return [...matching, ...groups.sort()];
} }
/* Commands (stuff for e.g. context menu for ssh-configs tree) */ /* Commands (stuff for e.g. context menu for ssh-configs tree) */
public commandDisconnect(name: string) { public commandDisconnect(name: string) {
@ -297,11 +309,15 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid
vscode.workspace.updateWorkspaceFolders(folders ? folders.length : 0, 0, { uri: vscode.Uri.parse(`ssh://${name}/`), name: `SSH FS - ${name}` }); vscode.workspace.updateWorkspaceFolders(folders ? folders.length : 0, 0, { uri: vscode.Uri.parse(`ssh://${name}/`), name: `SSH FS - ${name}` });
this.onDidChangeTreeDataEmitter.fire(); this.onDidChangeTreeDataEmitter.fire();
} }
public async commandConfigure(name: string) { public async commandConfigure(target: string | FileSystemConfig) {
Logging.info(`Command received to configure ${name}`); Logging.info(`Command received to configure ${typeof target === 'string' ? target : target.name}`);
name = name.toLowerCase(); if (typeof target === 'object') {
this.openSettings({ config: target, type: 'editconfig' });
return;
}
target = target.toLowerCase();
let configs = await loadConfigsRaw(); let configs = await loadConfigsRaw();
configs = configs.filter(c => c.name === name); configs = configs.filter(c => c.name === target);
if (configs.length === 0) throw new Error('Unexpectedly found no matching configs?'); if (configs.length === 0) throw new Error('Unexpectedly found no matching configs?');
const config = configs.length === 1 ? configs[0] : configs; const config = configs.length === 1 ? configs[0] : configs;
this.openSettings({ config, type: 'editconfig' }); this.openSettings({ config, type: 'editconfig' });

@ -28,14 +28,18 @@ export function getLocations(configs: FileSystemConfig[]): ConfigLocation[] {
return res; return res;
} }
export function getGroups(configs: FileSystemConfig[]): string[] { export function getGroups(configs: FileSystemConfig[], expanded = false): string[] {
const res: string[] = []; const res: string[] = [];
for (const { group } of configs) { function addGroup(group: string) {
if (!group) continue;
if (!res.find(l => l === group)) { if (!res.find(l => l === group)) {
res.push(group); res.push(group);
} }
} }
for (const { group } of configs) {
if (!group) continue;
const groups = expanded ? group.split('.') : [group];
groups.forEach((g, i) => addGroup([...groups.slice(0, i), g].join('.')));
}
return res; return res;
} }

Loading…
Cancel
Save