Ftp tree example

This commit is contained in:
Sandeep Somavarapu
2017-05-29 20:45:52 +02:00
parent 01d032a59a
commit 437fd9da45
7 changed files with 190 additions and 1 deletions

View File

@ -27,6 +27,10 @@
{
"id": "jsonOutline",
"name": "Json Outline"
},
{
"id": "ftpExplorer",
"name": "FTP Explorer"
}
]
},
@ -46,6 +50,10 @@
{
"command": "jsonOutline.deleteEntry",
"title": "Delete"
},
{
"command": "openFtpResource",
"title": "Open FTP Resource"
}
],
"menus": {
@ -83,6 +91,7 @@
"@types/node": "*"
},
"dependencies": {
"jsonc-parser": "^0.4.2"
"jsonc-parser": "^0.4.2",
"ftp": "^0.3.10"
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M15 16H2V0h8.621L15 4.379V16z" id="outline"/><path class="icon-vs-fg" d="M13 14H4V2h5v4h4v8zm-3-9V2.207L12.793 5H10z" id="iconFg"/><path class="icon-vs-bg" d="M3 1v14h11V4.793L10.207 1H3zm10 13H4V2h5v4h4v8zm-3-9V2.207L12.793 5H10z" id="iconBg"/></svg>

After

Width:  |  Height:  |  Size: 552 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-bg{fill:#656565;} .icon-vs-fg{fill:#F0EFF1;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M4 15c-.97 0-2-.701-2-2v-10c0-1.299 1.03-2 2-2h6.061l3.939 3.556v8.444c0 .97-.701 2-2 2h-8z" id="outline"/><path class="icon-vs-bg" d="M9.641,2H3.964C3.964,2,3,2,3,3c0,0.805,0,7.442,0,10c0,1,0.965,1,0.965,1s7,0,8,0S13,13,13,13V5L9.641,2zM12,13H4V3h5v3h3V13z" id="iconBg"/><path class="icon-vs-fg" d="M4 3h5v3h3v7h-8v-10z" id="iconFg"/></svg>

After

Width:  |  Height:  |  Size: 682 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-fg{fill:#F0EFF1;} .icon-folder{fill:#656565;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 2.5v10c0 .827-.673 1.5-1.5 1.5h-11.996c-.827 0-1.5-.673-1.5-1.5v-8c0-.827.673-1.5 1.5-1.5h2.886l1-2h8.11c.827 0 1.5.673 1.5 1.5z" id="outline"/><path class="icon-folder" d="M14.5 2h-7.492l-1 2h-3.504c-.277 0-.5.224-.5.5v8c0 .276.223.5.5.5h11.996c.275 0 .5-.224.5-.5v-10c0-.276-.225-.5-.5-.5zm-.496 2h-6.496l.5-1h5.996v1z" id="iconBg"/><path class="icon-vs-fg" d="M14 3v1h-6.5l.5-1h6z" id="iconFg"/></svg>

After

Width:  |  Height:  |  Size: 750 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-fg{opacity:0;fill:#F0EFF1;} .icon-folder{fill:#C5C5C5;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 2.5v10c0 .827-.673 1.5-1.5 1.5h-11.996c-.827 0-1.5-.673-1.5-1.5v-8c0-.827.673-1.5 1.5-1.5h2.886l1-2h8.11c.827 0 1.5.673 1.5 1.5z" id="outline"/><path class="icon-folder" d="M14.5 2h-7.492l-1 2h-3.504c-.277 0-.5.224-.5.5v8c0 .276.223.5.5.5h11.996c.275 0 .5-.224.5-.5v-10c0-.276-.225-.5-.5-.5zm-.496 2h-6.496l.5-1h5.996v1z" id="iconBg"/><path class="icon-vs-fg" d="M14 3v1h-6.5l.5-1h6z" id="iconFg"/></svg>

After

Width:  |  Height:  |  Size: 760 B

View File

@ -4,6 +4,7 @@ import * as vscode from 'vscode';
import { DepNodeProvider } from './nodeDependencies'
import { JsonOutlineProvider } from './jsonOutline'
import { FtpTreeDataProvider, FtpNode } from './ftpExplorer'
export function activate(context: vscode.ExtensionContext) {
const rootPath = vscode.workspace.rootPath;
@ -24,4 +25,13 @@ export function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('jsonOutline.refreshEntry', () => vscode.window.showInformationMessage('Successfully called refresh'));
vscode.commands.registerCommand('jsonOutline.addEntry', node => vscode.window.showInformationMessage('Successfully called add entry'));
vscode.commands.registerCommand('jsonOutline.deleteEntry', node => vscode.window.showInformationMessage('Successfully called delete entry'));
const provider = new FtpTreeDataProvider();
vscode.window.registerTreeDataProviderForView('ftpExplorer', provider);
vscode.commands.registerCommand('openFtpResource', (node: FtpNode) => {
vscode.workspace.openTextDocument(node.resource).then(document => {
vscode.window.showTextDocument(document);
});
});
}

View File

@ -0,0 +1,166 @@
import { ExtensionContext, TreeDataProvider, EventEmitter, TreeItem, Event, window, TreeItemCollapsibleState, Uri, commands, workspace, TextDocumentContentProvider, CancellationToken, ProviderResult } from 'vscode';
import * as Client from 'ftp';
import * as path from 'path';
interface IEntry {
name: string;
type: string;
}
export class FtpNode {
private _resource: Uri;
constructor(private entry: IEntry, private host: string, private _parent: string) {
this._resource = Uri.parse(`ftp://${host}/${_parent}/${entry.name}`);
}
public get resource(): Uri {
return this._resource;
}
public get path(): string {
return path.join(this._parent, this.name);
}
public get name(): string {
return this.entry.name;
}
public get isFolder(): boolean {
return this.entry.type === 'd' || this.entry.type === 'l';
}
}
export class FtpModel {
private connection: Thenable<FtpNode[]>;
constructor(private host: string, private user: string, private password: string) {
this.connection = this.connect();
}
public connect(): Thenable<Client> {
return new Promise((c, e) => {
const client = new Client();
client.on('ready', () => {
c(client);
});
client.connect({
host: this.host,
username: this.user,
password: this.password
});
});
}
public get roots(): Thenable<FtpNode[]> {
return this.connect().then(client => {
return new Promise((c, e) => {
client.list((err, list) => {
if (err) {
return e(err);
}
client.end();
return c(this.sort(list.map(entry => new FtpNode(entry, this.host, '/'))));
});
});
});
}
public getChildren(node: FtpNode): Thenable<FtpNode[]> {
return this.connect().then(client => {
return new Promise((c, e) => {
client.list(node.path, (err, list) => {
if (err) {
return e(err);
}
client.end();
return c(this.sort(list.map(entry => new FtpNode(entry, this.host, node.path))));
});
});
});
}
private sort(nodes: FtpNode[]): FtpNode[] {
return nodes.sort((n1, n2) => {
if (n1.isFolder && !n2.isFolder) {
return -1;
}
if (!n1.isFolder && n2.isFolder) {
return 1;
}
return n1.name.localeCompare(n2.name);
});
}
public getContent(resource: Uri): Thenable<string> {
return this.connect().then(client => {
return new Promise((c, e) => {
client.get(resource.path.substr(2), (err, stream) => {
if (err) {
return e(err);
}
let string = ''
stream.on('data', function (buffer) {
if (buffer) {
var part = buffer.toString();
string += part;
}
});
stream.on('end', function () {
client.end();
c(string);
});
});
});
});
}
}
export class FtpTreeDataProvider implements TreeDataProvider<FtpNode>, TextDocumentContentProvider {
private _onDidChangeTreeData: EventEmitter<any> = new EventEmitter<any>();
readonly onDidChangeTreeData: Event<any> = this._onDidChangeTreeData.event;
private model: FtpModel;
public getTreeItem(element: FtpNode): TreeItem {
return {
label: element.name,
collapsibleState: element.isFolder ? TreeItemCollapsibleState.Collapsed : void 0,
command: element.isFolder ? void 0 : {
command: 'openFtpResource',
arguments: [element.resource],
title: 'Open FTP Resource'
},
iconPath: {
light: element.isFolder ? path.join(__filename, '..', '..', '..', 'resources', 'Folder_16x.svg') : path.join(__filename, '..', '..', '..', 'resources', 'Document_16x.svg'),
dark: element.isFolder ? path.join(__filename, '..', '..', '..', 'resources', 'Folder_inverse_16x.svg') : path.join(__filename, '..', '..', '..', 'resources', 'Document_inverse_16x.svg')
}
};
}
public getChildren(element?: FtpNode): FtpNode[] | Thenable<FtpNode[]> {
if (!element) {
if (!this.model) {
this.model = new FtpModel('mirror.switch.ch', 'anonymous', 'anonymous@anonymous.de');
}
return this.model.roots;
}
return this.model.getChildren(element);
}
public provideTextDocumentContent(uri: Uri, token: CancellationToken): ProviderResult<string> {
return this.model.getContent(uri);
}
}