mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-04-27 16:55:44 +08:00
Ftp tree example
This commit is contained in:
@ -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"
|
||||
}
|
||||
}
|
||||
1
tree-explorer-sample/resources/Document_16x.svg
Normal file
1
tree-explorer-sample/resources/Document_16x.svg
Normal 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 |
1
tree-explorer-sample/resources/Document_inverse_16x.svg
Normal file
1
tree-explorer-sample/resources/Document_inverse_16x.svg
Normal 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 |
1
tree-explorer-sample/resources/Folder_16x.svg
Normal file
1
tree-explorer-sample/resources/Folder_16x.svg
Normal 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 |
1
tree-explorer-sample/resources/Folder_inverse_16x.svg
Normal file
1
tree-explorer-sample/resources/Folder_inverse_16x.svg
Normal 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 |
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
166
tree-explorer-sample/src/ftpExplorer.ts
Normal file
166
tree-explorer-sample/src/ftpExplorer.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user