diff --git a/extensions/npm/README.md b/extensions/npm/README.md index 007cb59abe6..c3dd9437203 100644 --- a/extensions/npm/README.md +++ b/extensions/npm/README.md @@ -15,11 +15,11 @@ For more information about auto detection of Tasks, see the [documentation](http ### Script Explorer -The Npm Script Explorer shows the npm scripts found in your workspace. The explorer view is enabled by the setting `npm.enableScriptExplorer`. +The Npm Script Explorer shows the npm scripts found in your workspace. The explorer view is enabled by the setting `npm.enableScriptExplorer`. A script can be opened, run, or debug from the explorer. ### Run Scripts from the Editor -The extension provides commands to run the script containing the selection. +The extension provides code lense actions to run or debug a script from the editor. ## Settings @@ -29,3 +29,5 @@ The extension provides commands to run the script containing the selection. - `npm.exclude` - Glob patterns for folders that should be excluded from automatic script detection. The pattern is matched against the **absolute path** of the package.json. For example, to exclude all test folders use '**/test/**'. - `npm.enableScriptExplorer` - Enable an explorer view for npm scripts. - `npm.scriptExplorerAction` - The default click action: `open` or `run`, the default is `open`. +- `npm.scriptCodeLens.enable` - Enable/disable the code lenses to run a script. + diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 8f1b193197b..7f4b794ee0c 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -94,10 +94,6 @@ "command": "npm.runScript", "when": "false" }, - { - "command": "npm.runScriptFromSource", - "when": "false" - }, { "command": "npm.debugScript", "when": "false" @@ -182,6 +178,12 @@ "scope": "resource", "description": "%config.npm.runSilent%" }, + "npm.scriptCodeLens.enable": { + "type": "boolean", + "default": true, + "scope": "resource", + "description": "%config.scriptCodeLens.enable%" + }, "npm.packageManager": { "scope": "resource", "type": "string", diff --git a/extensions/npm/src/lenses.ts b/extensions/npm/src/lenses.ts index 6276cc1e10e..6394fbad5b3 100644 --- a/extensions/npm/src/lenses.ts +++ b/extensions/npm/src/lenses.ts @@ -6,7 +6,7 @@ import { ExtensionContext, CodeLensProvider, TextDocument, commands, ProviderResult, CodeLens, CancellationToken, - workspace, tasks, Range, Command + workspace, tasks, Range, Command, Event, EventEmitter } from 'vscode'; import { createTask, startDebugging, findAllScriptRanges, extractDebugArgFromScript @@ -15,46 +15,59 @@ import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -export class NpmLenseProvider implements CodeLensProvider { +export class NpmLensProvider implements CodeLensProvider { private extensionContext: ExtensionContext; + private _onDidChangeCodeLenses: EventEmitter = new EventEmitter(); + readonly onDidChangeCodeLenses: Event = this._onDidChangeCodeLenses.event; constructor(context: ExtensionContext) { - const subscriptions = context.subscriptions; this.extensionContext = context; - context.subscriptions.push(commands.registerCommand('npm.runScriptFromLense', this.runScriptFromLense, this)); - context.subscriptions.push(commands.registerCommand('npm.debugScriptFromLense', this.debugScriptFromLense, this)); + context.subscriptions.push(commands.registerCommand('npm.runScriptFromLens', this.runScriptFromLens, this)); + context.subscriptions.push(commands.registerCommand('npm.debugScriptFromLens', this.debugScriptFromLens, this)); } - public provideCodeLenses(document: TextDocument, token: CancellationToken): ProviderResult { + public provideCodeLenses(document: TextDocument, _token: CancellationToken): ProviderResult { let result = findAllScriptRanges(document.getText()); + let folder = workspace.getWorkspaceFolder(document.uri); let lenses: CodeLens[] = []; + + if (folder && !workspace.getConfiguration('npm', folder.uri).get('scriptCodeLens.enable', 'true')) { + return lenses; + } + result.forEach((value, key) => { let start = document.positionAt(value[0]); let end = document.positionAt(value[0] + value[1]); - let lens: CodeLens; + let range = new Range(start, end); + let command: Command = { - command: 'npm.runScriptFromLense', + command: 'npm.runScriptFromLens', title: localize('run', "Run"), arguments: [document, key] }; - lens = new CodeLens(new Range(start, end), command); + let lens: CodeLens = new CodeLens(range, command); lenses.push(lens); + let debugArgs = extractDebugArgFromScript(value[2]); if (debugArgs) { command = { - command: 'npm.debugScriptFromLense', + command: 'npm.debugScriptFromLens', title: localize('debug', "Debug"), arguments: [document, key, debugArgs[0], debugArgs[1]] }; - lens = new CodeLens(new Range(start, end), command); + lens = new CodeLens(range, command); lenses.push(lens); } }); return lenses; } - public runScriptFromLense(document: TextDocument, script: string) { + public refresh() { + this._onDidChangeCodeLenses.fire(); + } + + public runScriptFromLens(document: TextDocument, script: string) { let uri = document.uri; let folder = workspace.getWorkspaceFolder(uri); if (folder) { @@ -63,7 +76,7 @@ export class NpmLenseProvider implements CodeLensProvider { } } - public debugScriptFromLense(document: TextDocument, script: string, protocol: string, port: number) { + public debugScriptFromLens(document: TextDocument, script: string, protocol: string, port: number) { let uri = document.uri; let folder = workspace.getWorkspaceFolder(uri); if (folder) { diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 4cd70568192..f2c80f5f476 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -9,16 +9,13 @@ import * as vscode from 'vscode'; import { addJSONProviders } from './features/jsonContributions'; import { NpmScriptsTreeDataProvider } from './npmView'; -import { provideNpmScripts, invalidateScriptsCache } from './tasks'; - -import { NpmLenseProvider } from './lenses'; - -let taskProvider: vscode.Disposable | undefined; +import { invalidateScriptsCache, NpmTaskProvider } from './tasks'; +import { NpmLensProvider } from './lenses'; export async function activate(context: vscode.ExtensionContext): Promise { - taskProvider = registerTaskProvider(context); + const taskProvider = registerTaskProvider(context); const treeDataProvider = registerExplorer(context); - registerLenseProvider(context); + const lensProvider = registerLensProvider(context); configureHttpRequest(); vscode.workspace.onDidChangeConfiguration((e) => { @@ -34,6 +31,11 @@ export async function activate(context: vscode.ExtensionContext): Promise treeDataProvider.refresh(); } } + if (e.affectsConfiguration('npm.scriptCodeLens.enable')) { + if (lensProvider) { + lensProvider.refresh(); + } + } }); context.subscriptions.push(addJSONProviders(httpRequest.xhr)); } @@ -46,15 +48,10 @@ function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposab watcher.onDidCreate((_e) => invalidateScriptsCache()); context.subscriptions.push(watcher); - let provider: vscode.TaskProvider = { - provideTasks: async () => { - return provideNpmScripts(); - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }; - return vscode.workspace.registerTaskProvider('npm', provider); + let provider: vscode.TaskProvider = new NpmTaskProvider(context); + let disposable = vscode.workspace.registerTaskProvider('npm', provider); + context.subscriptions.push(disposable); + return disposable; } return undefined; } @@ -69,16 +66,18 @@ function registerExplorer(context: vscode.ExtensionContext): NpmScriptsTreeDataP return undefined; } -function registerLenseProvider(context: vscode.ExtensionContext) { +function registerLensProvider(context: vscode.ExtensionContext): NpmLensProvider | undefined { if (vscode.workspace.workspaceFolders) { let npmSelector: vscode.DocumentSelector = { language: 'json', scheme: 'file', pattern: '**/package.json' }; - let provider = new NpmLenseProvider(context); + let provider = new NpmLensProvider(context); context.subscriptions.push(vscode.languages.registerCodeLensProvider(npmSelector, provider)); + return provider; } + return undefined; } function configureHttpRequest() { @@ -87,7 +86,4 @@ function configureHttpRequest() { } export function deactivate(): void { - if (taskProvider) { - taskProvider.dispose(); - } } diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index 6798a8cb9e9..5d19a4c4c00 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -6,7 +6,7 @@ import { TaskDefinition, Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace, - DebugConfiguration, debug + DebugConfiguration, debug, TaskProvider, ExtensionContext } from 'vscode'; import * as path from 'path'; import * as fs from 'fs'; @@ -25,6 +25,22 @@ type AutoDetect = 'on' | 'off'; let cachedTasks: Task[] | undefined = undefined; +export class NpmTaskProvider implements TaskProvider { + private extensionContext: ExtensionContext; + + constructor(context: ExtensionContext) { + this.extensionContext = context; + } + + public provideTasks() { + return provideNpmScripts(); + } + + public resolveTask(_task: Task): Task | undefined { + return undefined; + } +} + export function invalidateScriptsCache() { cachedTasks = undefined; } @@ -327,7 +343,6 @@ async function findAllScripts(buffer: string): Promise { let visitor: JSONVisitor = { onError(_error: ParseErrorCode, _offset: number, _length: number) { - // TODO: inform user about the parse error }, onObjectEnd() { if (inScripts) {