mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
added npmExplorer
This commit is contained in:
parent
406b33ab08
commit
526a88aeb0
|
@ -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",
|
||||
|
|
1
extensions/npm/resources/dark/refresh.svg
Normal file
1
extensions/npm/resources/dark/refresh.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<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>
|
After Width: | Height: | Size: 986 B |
1
extensions/npm/resources/light/refresh.svg
Normal file
1
extensions/npm/resources/light/refresh.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<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>
|
After Width: | Height: | Size: 986 B |
|
@ -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) {
|
||||
|
|
177
extensions/npm/src/npmView.ts
Normal file
177
extensions/npm/src/npmView.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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()];
|
||||
}
|
||||
}
|
15
extensions/npm/src/tasks.ts
Normal file
15
extensions/npm/src/tasks.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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>;
|
||||
}
|
Loading…
Reference in a new issue