提交 526a88ae 编写于 作者: E Erich Gamma

added npmExplorer

上级 406b33ab
......@@ -7,6 +7,7 @@
"engines": {
"vscode": "0.10.x"
},
"enableProposedApi": true,
"icon": "images/npm_icon.png",
"categories": [
"Other"
......@@ -28,9 +29,53 @@
"main": "./out/main",
"activationEvents": [
"onCommand:workbench.action.tasks.runTask",
"onLanguage:json"
"onLanguage:json",
"onView:npm"
],
"contributes": {
"views": {
"explorer": [
{
"id": "npm",
"name": "npm scripts"
}
]
},
"commands": [
{
"command": "npm.runScript",
"title": "Run Script"
},
{
"command": "npm.openScript",
"title": "Open Script"
},
{
"command": "npm.refresh",
"title": "Refresh",
"icon": {
"light": "resources/light/refresh.svg",
"dark": "resources/dark/refresh.svg"
}
}
],
"menus": {
"view/title": [
{
"command": "npm.refresh",
"when": "view == npm",
"group": "navigation"
}
],
"view/item/context": [
{
"command": "npm.openScript",
"when": "view == npm && viewItem == packageJSON",
"group": "1_navigation"
}
]
},
"configuration": {
"id": "npm",
"type": "object",
......
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#2D2D30"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#C5C5C5"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#F6F6F6"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#424242"/></svg>
\ No newline at end of file
......@@ -14,11 +14,22 @@ import * as minimatch from 'minimatch';
const localize = nls.loadMessageBundle();
import { addJSONProviders } from './features/jsonContributions';
import { NpmScriptsTreeDataProvider } from './npmView';
import { NpmTaskDefinition, ScriptValidator } from './tasks';
type AutoDetect = 'on' | 'off';
let taskProvider: vscode.Disposable | undefined;
class Validator implements ScriptValidator {
async scriptIsValid(_task: vscode.Task): Promise<boolean> {
// let tasks = await provideNpmScriptsForFolder(packageUri);
return true;
}
}
export function activate(context: vscode.ExtensionContext): void {
vscode.window.registerTreeDataProvider('npm', new NpmScriptsTreeDataProvider(context, new Validator()));
if (!vscode.workspace.workspaceFolders) {
return;
}
......@@ -67,11 +78,6 @@ async function readFile(file: string): Promise<string> {
});
}
interface NpmTaskDefinition extends vscode.TaskDefinition {
script: string;
path?: string;
}
const buildNames: string[] = ['build', 'compile', 'watch'];
function isBuildTask(name: string): boolean {
for (let buildName of buildNames) {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
ExtensionContext, Task, TreeDataProvider, TreeItem, TreeItemCollapsibleState,
WorkspaceFolder, workspace, commands, window, EventEmitter, Event,
ThemeIcon, Uri, TextDocument
} from 'vscode';
import { NpmTaskDefinition, ScriptValidator } from './tasks';
import * as path from 'path';
class Folder extends TreeItem {
packages: PackageJSON[] = [];
constructor(folder: WorkspaceFolder) {
super(folder.name, TreeItemCollapsibleState.Collapsed);
this.contextValue = 'folder';
this.resourceUri = folder.uri;
this.iconPath = ThemeIcon.Folder;
}
addPackage(packageJson: PackageJSON) {
this.packages.push(packageJson);
}
}
const packageName = 'package.json';
class PackageJSON extends TreeItem {
path: string;
folder: Folder;
scripts: NpmScript[] = [];
static getLabel(folderName: string, relativePath: string): string {
if (relativePath.length > 0) {
return path.join(relativePath, packageName);
}
return path.join(folderName, packageName);
}
constructor(folder: Folder, relativePath: string) {
super(PackageJSON.getLabel(folder.label!, relativePath), TreeItemCollapsibleState.Collapsed);
this.folder = folder;
this.path = relativePath;
this.contextValue = 'packageJSON';
this.resourceUri = Uri.file(path.join(folder!.resourceUri!.fsPath, relativePath, packageName));
this.iconPath = ThemeIcon.File;
}
addScript(script: NpmScript) {
this.scripts.push(script);
}
}
class NpmScript extends TreeItem {
task: Task;
package: PackageJSON;
constructor(packageJson: PackageJSON, task: Task) {
super(task.name, TreeItemCollapsibleState.None);
this.contextValue = 'script';
this.package = packageJson;
this.task = task;
this.command = {
title: 'Run Script',
command: 'npm.runScript',
arguments: [task]
};
}
}
export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
private taskTree: Folder[] | PackageJSON[] | null = null;
private validator: ScriptValidator;
private _onDidChangeTreeData: EventEmitter<TreeItem | null> = new EventEmitter<TreeItem | null>();
readonly onDidChangeTreeData: Event<TreeItem | null> = this._onDidChangeTreeData.event;
constructor(context: ExtensionContext, validator: ScriptValidator) {
const subscriptions = context.subscriptions;
this.validator = validator;
subscriptions.push(commands.registerCommand('npm.runScript', this.runScript, this));
subscriptions.push(commands.registerCommand('npm.openScript', this.openScript, this));
subscriptions.push(commands.registerCommand('npm.refresh', this.refresh, this));
}
private runScript(task: Task) {
if (!this.validator.scriptIsValid(task)) {
window.showErrorMessage(`Could not find script ${task.name}`);
return;
}
workspace.executeTask(task);
}
private async openScript(packageJSON: PackageJSON) {
let document: TextDocument = await workspace.openTextDocument(packageJSON.resourceUri!);
window.showTextDocument(document);
}
private refresh() {
this.taskTree = null;
this._onDidChangeTreeData.fire();
}
getTreeItem(element: TreeItem): TreeItem {
return element;
}
getParent(element: TreeItem): TreeItem | null {
if (element instanceof Folder) {
return null;
}
if (element instanceof PackageJSON) {
return element.folder;
}
if (element instanceof NpmScript) {
return element.package;
}
return null;
}
async getChildren(element?: TreeItem): Promise<TreeItem[]> {
if (!this.taskTree) {
let tasks = await workspace.fetchTasks();
let npmTasks = tasks.filter(each => each.definition.type === 'npm');
this.taskTree = this.buildTaskTree(npmTasks);
}
if (element instanceof Folder) {
return element.packages;
}
if (element instanceof PackageJSON) {
return element.scripts;
}
if (element instanceof NpmScript) {
return [];
}
return this.taskTree;
}
private isWorkspaceFolder(value: any): value is WorkspaceFolder {
return value && typeof value !== 'number';
}
private buildTaskTree(tasks: Task[]): Folder[] | PackageJSON[] {
let folders: Map<String, Folder> = new Map();
let packages: Map<String, PackageJSON> = new Map();
let folder = null;
let packageJson = null;
tasks.forEach(each => {
if (this.isWorkspaceFolder(each.scope)) {
folder = folders.get(each.scope.name);
if (!folder) {
folder = new Folder(each.scope);
folders.set(each.scope.name, folder);
}
let definition: NpmTaskDefinition = <NpmTaskDefinition>each.definition;
let path = definition.path ? definition.path : '';
packageJson = packages.get(path);
if (!packageJson) {
packageJson = new PackageJSON(folder, path);
folder.addPackage(packageJson);
packages.set(path, packageJson);
}
let script = new NpmScript(packageJson, each);
packageJson.addScript(script);
}
});
if (folders.size === 1) {
return [...packages.values()];
}
return [...folders.values()];
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TaskDefinition, Task } from 'vscode';
export interface NpmTaskDefinition extends TaskDefinition {
script: string;
path?: string;
}
export interface ScriptValidator {
scriptIsValid(task: Task): Promise<boolean>;
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册