From 87998af6185105d6b6fa9b2571bed4681ebbab00 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 22 Oct 2019 15:56:21 +0200 Subject: [PATCH] Add task detail property and adopt in npm extension Fixes #69785 --- extensions/npm/src/npmView.ts | 7 +- extensions/npm/src/tasks.ts | 12 +- extensions/npm/src/vscode.proposed.d.ts | 1068 +++++++++++++++++ src/vs/vscode.proposed.d.ts | 6 +- .../workbench/api/browser/mainThreadTask.ts | 4 + src/vs/workbench/api/common/extHostTask.ts | 4 + src/vs/workbench/api/common/extHostTypes.ts | 12 + src/vs/workbench/api/common/shared/tasks.ts | 1 + .../tasks/browser/abstractTaskService.ts | 8 +- .../tasks/browser/task.contribution.ts | 5 + .../contrib/tasks/common/jsonSchema_v2.ts | 9 +- .../contrib/tasks/common/taskConfiguration.ts | 10 + .../workbench/contrib/tasks/common/tasks.ts | 5 + 13 files changed, 1139 insertions(+), 12 deletions(-) create mode 100644 extensions/npm/src/vscode.proposed.d.ts diff --git a/extensions/npm/src/npmView.ts b/extensions/npm/src/npmView.ts index 4916fd49310..b5234c5fc1b 100644 --- a/extensions/npm/src/npmView.ts +++ b/extensions/npm/src/npmView.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import { - Event, EventEmitter, ExtensionContext, Task, + Event, EventEmitter, ExtensionContext, Task2 as Task, TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, commands, window, workspace, tasks, Selection, TaskGroup } from 'vscode'; @@ -108,6 +108,9 @@ class NpmScript extends TreeItem { dark: context.asAbsolutePath(path.join('resources', 'dark', 'script.svg')) }; } + if (task.detail) { + this.tooltip = task.detail; + } } getFolder(): WorkspaceFolder { @@ -206,7 +209,7 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider { if (!uri) { return; } - let task = createTask('install', 'install', selection.folder.workspaceFolder, uri, []); + let task = createTask('install', 'install', selection.folder.workspaceFolder, uri, undefined, []); tasks.executeTask(task); } diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index cc21ffafc8f..c510b5f2b57 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { - TaskDefinition, Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace, + TaskDefinition, Task2 as Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace, DebugConfiguration, debug, TaskProvider, TextDocument, tasks, TaskScope, QuickPickItem } from 'vscode'; import * as path from 'path'; @@ -237,7 +237,7 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise const prePostScripts = getPrePostScripts(scripts); Object.keys(scripts).forEach(each => { - const task = createTask(each, `run ${each}`, folder!, packageJsonUri); + const task = createTask(each, `run ${each}`, folder!, packageJsonUri, scripts![each]); const lowerCaseTaskName = each.toLowerCase(); if (isBuildTask(lowerCaseTaskName)) { task.group = TaskGroup.Build; @@ -253,7 +253,7 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise result.push(task); }); // always add npm install (without a problem matcher) - result.push(createTask('install', 'install', folder, packageJsonUri, [])); + result.push(createTask('install', 'install', folder, packageJsonUri, undefined, [])); return result; } @@ -264,7 +264,7 @@ export function getTaskName(script: string, relativePath: string | undefined) { return script; } -export function createTask(script: NpmTaskDefinition | string, cmd: string, folder: WorkspaceFolder, packageJsonUri: Uri, matcher?: any): Task { +export function createTask(script: NpmTaskDefinition | string, cmd: string, folder: WorkspaceFolder, packageJsonUri: Uri, detail?: string, matcher?: any): Task { let kind: NpmTaskDefinition; if (typeof script === 'string') { kind = { type: 'npm', script: script }; @@ -292,7 +292,9 @@ export function createTask(script: NpmTaskDefinition | string, cmd: string, fold } let taskName = getTaskName(kind.script, relativePackageJson); let cwd = path.dirname(packageJsonUri.fsPath); - return new Task(kind, folder, taskName, 'npm', new ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); + const task = new Task(kind, folder, taskName, 'npm', new ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); + task.detail = detail; + return task; } diff --git a/extensions/npm/src/vscode.proposed.d.ts b/extensions/npm/src/vscode.proposed.d.ts new file mode 100644 index 00000000000..2fba7968f23 --- /dev/null +++ b/extensions/npm/src/vscode.proposed.d.ts @@ -0,0 +1,1068 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * This is the place for API experiments and proposals. + * These API are NOT stable and subject to change. They are only available in the Insiders + * distribution and CANNOT be used in published extensions. + * + * To test these API in local environment: + * - Use Insiders release of VS Code. + * - Add `"enableProposedApi": true` to your package.json. + * - Copy this file to your project. + */ + +declare module 'vscode' { + + //#region Joh - call hierarchy + + export class CallHierarchyItem { + /** + * The name of this item. + */ + name: string; + + /** + * The kind of this item. + */ + kind: SymbolKind; + + /** + * Tags for this item. + */ + tags?: ReadonlyArray; + + /** + * More detail for this item, e.g. the signature of a function. + */ + detail?: string; + + /** + * The resource identifier of this item. + */ + uri: Uri; + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + */ + range: Range; + + /** + * The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function. + * Must be contained by the [`range`](#CallHierarchyItem.range). + */ + selectionRange: Range; + + constructor(kind: SymbolKind, name: string, detail: string, uri: Uri, range: Range, selectionRange: Range); + } + + export class CallHierarchyIncomingCall { + from: CallHierarchyItem; + fromRanges: Range[]; + constructor(item: CallHierarchyItem, fromRanges: Range[]); + } + + export class CallHierarchyOutgoingCall { + fromRanges: Range[]; + to: CallHierarchyItem; + constructor(item: CallHierarchyItem, fromRanges: Range[]); + } + + export interface CallHierarchyItemProvider { + + /** + * Provide a list of callers for the provided item, e.g. all function calling a function. + */ + provideCallHierarchyIncomingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + + /** + * Provide a list of calls for the provided item, e.g. all functions call from a function. + */ + provideCallHierarchyOutgoingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + + // todo@joh this could return as 'prepareCallHierarchy' (similar to the RenameProvider#prepareRename) + // + // /** + // * + // * Given a document and position compute a call hierarchy item. This is justed as + // * anchor for call hierarchy and then `resolveCallHierarchyItem` is being called. + // */ + // resolveCallHierarchyItem(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + export namespace languages { + export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyItemProvider): Disposable; + } + + //#endregion + + + //#region Alex - resolvers + + export interface RemoteAuthorityResolverContext { + resolveAttempt: number; + } + + export class ResolvedAuthority { + readonly host: string; + readonly port: number; + + constructor(host: string, port: number); + } + + export interface ResolvedOptions { + extensionHostEnv?: { [key: string]: string | null }; + } + + export type ResolverResult = ResolvedAuthority & ResolvedOptions; + + export class RemoteAuthorityResolverError extends Error { + static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError; + static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError; + + constructor(message?: string); + } + + export interface RemoteAuthorityResolver { + resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable; + } + + export interface ResourceLabelFormatter { + scheme: string; + authority?: string; + formatting: ResourceLabelFormatting; + } + + export interface ResourceLabelFormatting { + label: string; // myLabel:/${path} + separator: '/' | '\\' | ''; + tildify?: boolean; + normalizeDriveLetter?: boolean; + workspaceSuffix?: string; + authorityPrefix?: string; + } + + export namespace workspace { + export function registerRemoteAuthorityResolver(authorityPrefix: string, resolver: RemoteAuthorityResolver): Disposable; + export function registerResourceLabelFormatter(formatter: ResourceLabelFormatter): Disposable; + } + + //#endregion + + + // #region Joh - code insets + + export interface WebviewEditorInset { + readonly editor: TextEditor; + readonly line: number; + readonly height: number; + readonly webview: Webview; + readonly onDidDispose: Event; + dispose(): void; + } + + export namespace window { + export function createWebviewTextEditorInset(editor: TextEditor, line: number, height: number, options?: WebviewOptions): WebviewEditorInset; + } + + //#endregion + + //#region Joh - read/write in chunks + + export interface FileSystemProvider { + open?(resource: Uri, options: { create: boolean }): number | Thenable; + close?(fd: number): void | Thenable; + read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable; + write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable; + } + + //#endregion + + //#region Rob: search provider + + /** + * The parameters of a query for text search. + */ + export interface TextSearchQuery { + /** + * The text pattern to search for. + */ + pattern: string; + + /** + * Whether or not `pattern` should match multiple lines of text. + */ + isMultiline?: boolean; + + /** + * Whether or not `pattern` should be interpreted as a regular expression. + */ + isRegExp?: boolean; + + /** + * Whether or not the search should be case-sensitive. + */ + isCaseSensitive?: boolean; + + /** + * Whether or not to search for whole word matches only. + */ + isWordMatch?: boolean; + } + + /** + * A file glob pattern to match file paths against. + * TODO@roblou - merge this with the GlobPattern docs/definition in vscode.d.ts. + * @see [GlobPattern](#GlobPattern) + */ + export type GlobString = string; + + /** + * Options common to file and text search + */ + export interface SearchOptions { + /** + * The root folder to search within. + */ + folder: Uri; + + /** + * Files that match an `includes` glob pattern should be included in the search. + */ + includes: GlobString[]; + + /** + * Files that match an `excludes` glob pattern should be excluded from the search. + */ + excludes: GlobString[]; + + /** + * Whether external files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useIgnoreFiles"`. + */ + useIgnoreFiles: boolean; + + /** + * Whether symlinks should be followed while searching. + * See the vscode setting `"search.followSymlinks"`. + */ + followSymlinks: boolean; + + /** + * Whether global files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useGlobalIgnoreFiles"`. + */ + useGlobalIgnoreFiles: boolean; + } + + /** + * Options to specify the size of the result text preview. + * These options don't affect the size of the match itself, just the amount of preview text. + */ + export interface TextSearchPreviewOptions { + /** + * The maximum number of lines in the preview. + * Only search providers that support multiline search will ever return more than one line in the match. + */ + matchLines: number; + + /** + * The maximum number of characters included per line. + */ + charsPerLine: number; + } + + /** + * Options that apply to text search. + */ + export interface TextSearchOptions extends SearchOptions { + /** + * The maximum number of results to be returned. + */ + maxResults: number; + + /** + * Options to specify the size of the result text preview. + */ + previewOptions?: TextSearchPreviewOptions; + + /** + * Exclude files larger than `maxFileSize` in bytes. + */ + maxFileSize?: number; + + /** + * Interpret files using this encoding. + * See the vscode setting `"files.encoding"` + */ + encoding?: string; + + /** + * Number of lines of context to include before each match. + */ + beforeContext?: number; + + /** + * Number of lines of context to include after each match. + */ + afterContext?: number; + } + + /** + * Information collected when text search is complete. + */ + export interface TextSearchComplete { + /** + * Whether the search hit the limit on the maximum number of search results. + * `maxResults` on [`TextSearchOptions`](#TextSearchOptions) specifies the max number of results. + * - If exactly that number of matches exist, this should be false. + * - If `maxResults` matches are returned and more exist, this should be true. + * - If search hits an internal limit which is less than `maxResults`, this should be true. + */ + limitHit?: boolean; + } + + /** + * The parameters of a query for file search. + */ + export interface FileSearchQuery { + /** + * The search pattern to match against file paths. + */ + pattern: string; + } + + /** + * Options that apply to file search. + */ + export interface FileSearchOptions extends SearchOptions { + /** + * The maximum number of results to be returned. + */ + maxResults?: number; + + /** + * A CancellationToken that represents the session for this search query. If the provider chooses to, this object can be used as the key for a cache, + * and searches with the same session object can search the same cache. When the token is cancelled, the session is complete and the cache can be cleared. + */ + session?: CancellationToken; + } + + /** + * A preview of the text result. + */ + export interface TextSearchMatchPreview { + /** + * The matching lines of text, or a portion of the matching line that contains the match. + */ + text: string; + + /** + * The Range within `text` corresponding to the text of the match. + * The number of matches must match the TextSearchMatch's range property. + */ + matches: Range | Range[]; + } + + /** + * A match from a text search + */ + export interface TextSearchMatch { + /** + * The uri for the matching document. + */ + uri: Uri; + + /** + * The range of the match within the document, or multiple ranges for multiple matches. + */ + ranges: Range | Range[]; + + /** + * A preview of the text match. + */ + preview: TextSearchMatchPreview; + } + + /** + * A line of context surrounding a TextSearchMatch. + */ + export interface TextSearchContext { + /** + * The uri for the matching document. + */ + uri: Uri; + + /** + * One line of text. + * previewOptions.charsPerLine applies to this + */ + text: string; + + /** + * The line number of this line of context. + */ + lineNumber: number; + } + + export type TextSearchResult = TextSearchMatch | TextSearchContext; + + /** + * A FileSearchProvider provides search results for files in the given folder that match a query string. It can be invoked by quickopen or other extensions. + * + * A FileSearchProvider is the more powerful of two ways to implement file search in VS Code. Use a FileSearchProvider if you wish to search within a folder for + * all files that match the user's query. + * + * The FileSearchProvider will be invoked on every keypress in quickopen. When `workspace.findFiles` is called, it will be invoked with an empty query string, + * and in that case, every file in the folder should be returned. + */ + export interface FileSearchProvider { + /** + * Provide the set of files that match a certain file path pattern. + * @param query The parameters for this query. + * @param options A set of options to consider while searching files. + * @param token A cancellation token. + */ + provideFileSearchResults(query: FileSearchQuery, options: FileSearchOptions, token: CancellationToken): ProviderResult; + } + + /** + * A TextSearchProvider provides search results for text results inside files in the workspace. + */ + export interface TextSearchProvider { + /** + * Provide results that match the given text pattern. + * @param query The parameters for this query. + * @param options A set of options to consider while searching. + * @param progress A progress callback that must be invoked for all results. + * @param token A cancellation token. + */ + provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress, token: CancellationToken): ProviderResult; + } + + /** + * Options that can be set on a findTextInFiles search. + */ + export interface FindTextInFilesOptions { + /** + * A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern + * will be matched against the file paths of files relative to their workspace. Use a [relative pattern](#RelativePattern) + * to restrict the search results to a [workspace folder](#WorkspaceFolder). + */ + include?: GlobPattern; + + /** + * A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. When `undefined` only default excludes will + * apply, when `null` no excludes will apply. + */ + exclude?: GlobPattern | null; + + /** + * The maximum number of results to search for + */ + maxResults?: number; + + /** + * Whether external files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useIgnoreFiles"`. + */ + useIgnoreFiles?: boolean; + + /** + * Whether global files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useGlobalIgnoreFiles"`. + */ + useGlobalIgnoreFiles?: boolean; + + /** + * Whether symlinks should be followed while searching. + * See the vscode setting `"search.followSymlinks"`. + */ + followSymlinks?: boolean; + + /** + * Interpret files using this encoding. + * See the vscode setting `"files.encoding"` + */ + encoding?: string; + + /** + * Options to specify the size of the result text preview. + */ + previewOptions?: TextSearchPreviewOptions; + + /** + * Number of lines of context to include before each match. + */ + beforeContext?: number; + + /** + * Number of lines of context to include after each match. + */ + afterContext?: number; + } + + export namespace workspace { + /** + * Register a search provider. + * + * Only one provider can be registered per scheme. + * + * @param scheme The provider will be invoked for workspace folders that have this file scheme. + * @param provider The provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerFileSearchProvider(scheme: string, provider: FileSearchProvider): Disposable; + + /** + * Register a text search provider. + * + * Only one provider can be registered per scheme. + * + * @param scheme The provider will be invoked for workspace folders that have this file scheme. + * @param provider The provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTextSearchProvider(scheme: string, provider: TextSearchProvider): Disposable; + + /** + * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. + * @param callback A callback, called for each result + * @param token A token that can be used to signal cancellation to the underlying search engine. + * @return A thenable that resolves when the search is complete. + */ + export function findTextInFiles(query: TextSearchQuery, callback: (result: TextSearchResult) => void, token?: CancellationToken): Thenable; + + /** + * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. + * @param options An optional set of query options. Include and exclude patterns, maxResults, etc. + * @param callback A callback, called for each result + * @param token A token that can be used to signal cancellation to the underlying search engine. + * @return A thenable that resolves when the search is complete. + */ + export function findTextInFiles(query: TextSearchQuery, options: FindTextInFilesOptions, callback: (result: TextSearchResult) => void, token?: CancellationToken): Thenable; + } + + //#endregion + + //#region Joao: diff command + + /** + * The contiguous set of modified lines in a diff. + */ + export interface LineChange { + readonly originalStartLineNumber: number; + readonly originalEndLineNumber: number; + readonly modifiedStartLineNumber: number; + readonly modifiedEndLineNumber: number; + } + + export namespace commands { + + /** + * Registers a diff information command that can be invoked via a keyboard shortcut, + * a menu item, an action, or directly. + * + * Diff information commands are different from ordinary [commands](#commands.registerCommand) as + * they only execute when there is an active diff editor when the command is called, and the diff + * information has been computed. Also, the command handler of an editor command has access to + * the diff information. + * + * @param command A unique identifier for the command. + * @param callback A command handler function with access to the [diff information](#LineChange). + * @param thisArg The `this` context used when invoking the handler function. + * @return Disposable which unregisters this command on disposal. + */ + export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable; + } + + //#endregion + + //#region Joh: decorations + + export class Decoration { + letter?: string; + title?: string; + color?: ThemeColor; + priority?: number; + bubble?: boolean; + } + + export interface DecorationProvider { + onDidChangeDecorations: Event; + provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; + } + + export namespace window { + export function registerDecorationProvider(provider: DecorationProvider): Disposable; + } + + //#endregion + + //#region André: debug + + // deprecated + + export interface DebugConfigurationProvider { + /** + * Deprecated, use DebugAdapterDescriptorFactory.provideDebugAdapter instead. + * @deprecated Use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead + */ + debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult; + } + + /** + * Debug console mode used by debug session, see [options](#DebugSessionOptions). + */ + export enum DebugConsoleMode { + /** + * Debug session should have a separate debug console. + */ + Separate = 0, + + /** + * Debug session should share debug console with its parent session. + * This value has no effect for sessions which do not have a parent session. + */ + MergeWithParent = 1 + } + + /** + * Options for [starting a debug session](#debug.startDebugging). + */ + export interface DebugSessionOptions { + + /** + * When specified the newly created debug session is registered as a "child" session of this + * "parent" debug session. + */ + parentSession?: DebugSession; + + /** + * Controls whether this session should have a separate debug console or share it + * with the parent session. Has no effect for sessions which do not have a parent session. + * Defaults to Separate. + */ + consoleMode?: DebugConsoleMode; + } + + //#endregion + + //#region Rob, Matt: logging + + /** + * The severity level of a log message + */ + export enum LogLevel { + Trace = 1, + Debug = 2, + Info = 3, + Warning = 4, + Error = 5, + Critical = 6, + Off = 7 + } + + export namespace env { + /** + * Current logging level. + */ + export const logLevel: LogLevel; + + /** + * An [event](#Event) that fires when the log level has changed. + */ + export const onDidChangeLogLevel: Event; + } + + //#endregion + + //#region Joao: SCM validation + + /** + * Represents the validation type of the Source Control input. + */ + export enum SourceControlInputBoxValidationType { + + /** + * Something not allowed by the rules of a language or other means. + */ + Error = 0, + + /** + * Something suspicious but allowed. + */ + Warning = 1, + + /** + * Something to inform about but not a problem. + */ + Information = 2 + } + + export interface SourceControlInputBoxValidation { + + /** + * The validation message to display. + */ + readonly message: string; + + /** + * The validation type. + */ + readonly type: SourceControlInputBoxValidationType; + } + + /** + * Represents the input box in the Source Control viewlet. + */ + export interface SourceControlInputBox { + + /** + * A validation function for the input box. It's possible to change + * the validation provider simply by setting this property to a different function. + */ + validateInput?(value: string, cursorPosition: number): ProviderResult; + } + + //#endregion + + //#region Joao: SCM selected provider + + export interface SourceControl { + + /** + * Whether the source control is selected. + */ + readonly selected: boolean; + + /** + * An event signaling when the selection state changes. + */ + readonly onDidChangeSelection: Event; + } + + //#endregion + + //#region Joao: SCM Input Box + + /** + * Represents the input box in the Source Control viewlet. + */ + export interface SourceControlInputBox { + + /** + * Controls whether the input box is visible (default is `true`). + */ + visible: boolean; + } + + //#endregion + + + //#region Terminal + + /** + * An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change. + */ + export interface TerminalDimensionsChangeEvent { + /** + * The [terminal](#Terminal) for which the dimensions have changed. + */ + readonly terminal: Terminal; + /** + * The new value for the [terminal's dimensions](#Terminal.dimensions). + */ + readonly dimensions: TerminalDimensions; + } + + export interface TerminalDataWriteEvent { + /** + * The [terminal](#Terminal) for which the data was written. + */ + readonly terminal: Terminal; + /** + * The data being written. + */ + readonly data: string; + } + + namespace window { + /** + * An event which fires when the [dimensions](#Terminal.dimensions) of the terminal change. + */ + export const onDidChangeTerminalDimensions: Event; + + /** + * An event which fires when the terminal's pty slave pseudo-device is written to. In other + * words, this provides access to the raw data stream from the process running within the + * terminal, including VT sequences. + */ + export const onDidWriteTerminalData: Event; + } + + export interface Terminal { + /** + * The current dimensions of the terminal. This will be `undefined` immediately after the + * terminal is created as the dimensions are not known until shortly after the terminal is + * created. + */ + readonly dimensions: TerminalDimensions | undefined; + } + + //#endregion + + //#region Joh -> exclusive document filters + + export interface DocumentFilter { + exclusive?: boolean; + } + + //#endregion + + //#region mjbvz,joh: https://github.com/Microsoft/vscode/issues/43768 + export interface FileRenameEvent { + readonly oldUri: Uri; + readonly newUri: Uri; + } + + export interface FileWillRenameEvent { + readonly oldUri: Uri; + readonly newUri: Uri; + waitUntil(thenable: Thenable): void; + } + + export namespace workspace { + export const onWillRenameFile: Event; + export const onDidRenameFile: Event; + } + //#endregion + + //#region Alex - OnEnter enhancement + export interface OnEnterRule { + /** + * This rule will only execute if the text above the this line matches this regular expression. + */ + oneLineAboveText?: RegExp; + } + //#endregion + + //#region Tree View + + export interface TreeView { + /** + * The tree view title is initially taken from the extension package.json + * Changes to the title property will be properly reflected in the UI in the title of the view. + */ + title?: string; + } + + /** + * Label describing the [Tree item](#TreeItem) + */ + export interface TreeItemLabel { + + /** + * A human-readable string describing the [Tree item](#TreeItem). + */ + label: string; + + /** + * Ranges in the label to highlight. A range is defined as a tuple of two number where the + * first is the inclusive start index and the second the exclusive end index + */ + highlights?: [number, number][]; + + } + + export class TreeItem2 extends TreeItem { + /** + * Label describing this item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri). + */ + label?: string | TreeItemLabel | /* for compilation */ any; + + /** + * @param label Label describing this item + * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + */ + constructor(label: TreeItemLabel, collapsibleState?: TreeItemCollapsibleState); + } + //#endregion + + //#region CustomExecution + /** + * Class used to execute an extension callback as a task. + */ + export class CustomExecution { + /** + * Constructs a CustomExecution task object. The callback will be executed the task is run, at which point the + * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until + * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). + * @param process The [Pseudoterminal](#Pseudoterminal) to be used by the task to display output. + * @param callback The callback that will be called when the task is started by a user. + */ + constructor(callback: () => Thenable); + } + + /** + * A task to execute + */ + export class Task2 extends Task { + /** + * Creates a new task. + * + * @param definition The task definition as defined in the taskDefinitions extension point. + * @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder. + * @param name The task's name. Is presented in the user interface. + * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. + * @param execution The process or shell execution. + * @param problemMatchers the names of problem matchers to use, like '$tsc' + * or '$eslint'. Problem matchers can be contributed by an extension using + * the `problemMatchers` extension point. + */ + constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); + + /** + * The task's execution engine + */ + execution2?: ProcessExecution | ShellExecution | CustomExecution; + + detail?: string; + } + + export interface TaskPresentationOptions { + /** + * Controls whether the task is executed in a specific terminal group using split panes. + */ + group?: string; + } + //#endregion + + // #region Ben - status bar item with ID and Name + + export namespace window { + + /** + * Options to configure the status bar item. + */ + export interface StatusBarItemOptions { + + /** + * A unique identifier of the status bar item. The identifier + * is for example used to allow a user to show or hide the + * status bar item in the UI. + */ + id: string; + + /** + * A human readable name of the status bar item. The name is + * for example used as a label in the UI to show or hide the + * status bar item. + */ + name: string; + + /** + * The alignment of the status bar item. + */ + alignment?: StatusBarAlignment; + + /** + * The priority of the status bar item. Higher value means the item should + * be shown more to the left. + */ + priority?: number; + } + + /** + * Creates a status bar [item](#StatusBarItem). + * + * @param options The options of the item. If not provided, some default values + * will be assumed. For example, the `StatusBarItemOptions.id` will be the id + * of the extension and the `StatusBarItemOptions.name` will be the extension name. + * @return A new status bar item. + */ + export function createStatusBarItem(options?: StatusBarItemOptions): StatusBarItem; + } + + //#endregion + + // #region Ben - extension auth flow (desktop+web) + + export interface AppUriOptions { + payload?: { + path?: string; + query?: string; + fragment?: string; + }; + } + + export namespace env { + + /** + * Creates a Uri that - if opened in a browser - will result in a + * registered [UriHandler](#UriHandler) to fire. The handler's + * Uri will be configured with the path, query and fragment of + * [AppUriOptions](#AppUriOptions) if provided, otherwise it will be empty. + * + * Extensions should not make any assumptions about the resulting + * Uri and should not alter it in anyway. Rather, extensions can e.g. + * use this Uri in an authentication flow, by adding the Uri as + * callback query argument to the server to authenticate to. + * + * Note: If the server decides to add additional query parameters to the Uri + * (e.g. a token or secret), it will appear in the Uri that is passed + * to the [UriHandler](#UriHandler). + * + * **Example** of an authentication flow: + * ```typescript + * vscode.window.registerUriHandler({ + * handleUri(uri: vscode.Uri): vscode.ProviderResult { + * if (uri.path === '/did-authenticate') { + * console.log(uri.toString()); + * } + * } + * }); + * + * const callableUri = await vscode.env.createAppUri({ payload: { path: '/did-authenticate' } }); + * await vscode.env.openExternal(callableUri); + * ``` + */ + export function createAppUri(options?: AppUriOptions): Thenable; + } + + //#endregion + + //#region Custom editors, mjbvz + + export interface WebviewEditor extends WebviewPanel { + } + + export interface WebviewEditorProvider { + /** + * Fills out a `WebviewEditor` for a given resource. + * + * The provider should take ownership of passed in `editor`. + */ + resolveWebviewEditor( + resource: Uri, + editor: WebviewEditor + ): Thenable; + } + + namespace window { + export function registerWebviewEditorProvider( + viewType: string, + provider: WebviewEditorProvider, + options?: WebviewPanelOptions + ): Disposable; + } + + //#endregion +} diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 23ea710e6b3..2fba7968f23 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -933,10 +933,10 @@ declare module 'vscode' { * The task's execution engine */ execution2?: ProcessExecution | ShellExecution | CustomExecution; - } - //#endregion - //#region Tasks + detail?: string; + } + export interface TaskPresentationOptions { /** * Controls whether the task is executed in a specific terminal group using split panes. diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index 58d76c01b51..5e9120d8360 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -323,6 +323,9 @@ namespace TaskDTO { if (task.configurationProperties.group) { result.group = task.configurationProperties.group; } + if (task.configurationProperties.detail) { + result.detail = task.configurationProperties.detail; + } if (!ConfiguringTask.is(task) && task.command) { if (task.command.runtime === RuntimeType.Process) { result.execution = ProcessExecutionDTO.from(task.command); @@ -380,6 +383,7 @@ namespace TaskDTO { group: task.group, isBackground: !!task.isBackground, problemMatchers: task.problemMatchers.slice(), + detail: task.detail } ); return result; diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 1fbe711b32b..0c7408693bd 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -261,6 +261,7 @@ export namespace TaskDTO { problemMatchers: value.problemMatchers, hasDefinedMatchers: (value as types.Task).hasDefinedMatchers, runOptions: (value).runOptions ? (value).runOptions : { reevaluateOnRerun: true }, + detail: (value).detail }; return result; } @@ -303,6 +304,9 @@ export namespace TaskDTO { if (value._id) { result._id = value._id; } + if (value.detail) { + result.detail = value.detail; + } return result; } } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index a5644289cf7..6a255a69d89 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1815,6 +1815,7 @@ export class Task implements vscode.Task2 { private _group: TaskGroup | undefined; private _presentationOptions: vscode.TaskPresentationOptions; private _runOptions: vscode.RunOptions; + private _detail: string | undefined; constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); @@ -2009,6 +2010,17 @@ export class Task implements vscode.Task2 { this._group = value; } + get detail(): string | undefined { + return this._detail; + } + + set detail(value: string | undefined) { + if (value === null) { + value = undefined; + } + this._detail = value; + } + get presentationOptions(): vscode.TaskPresentationOptions { return this._presentationOptions; } diff --git a/src/vs/workbench/api/common/shared/tasks.ts b/src/vs/workbench/api/common/shared/tasks.ts index e31f4e6b807..465a042d8b5 100644 --- a/src/vs/workbench/api/common/shared/tasks.ts +++ b/src/vs/workbench/api/common/shared/tasks.ts @@ -89,6 +89,7 @@ export interface TaskDTO { isBackground?: boolean; source: TaskSourceDTO; group?: string; + detail?: string; presentationOptions?: TaskPresentationOptionsDTO; problemMatchers: string[]; hasDefinedMatchers: boolean; diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 468c064ae40..9f5abe4b65a 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -81,6 +81,7 @@ import { find } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history'; +const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail'; export namespace ConfigureTaskAction { export const ID = 'workbench.action.tasks.configureTaskRunner'; @@ -1876,6 +1877,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return true; } + private showDetail(): boolean { + return this.configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); + } + private createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry): TaskQuickPickEntry[] { if (tasks === undefined || tasks === null || tasks.length === 0) { return []; @@ -1892,7 +1897,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer description = workspaceFolder.name; } } - return { label: task._label, description, task }; + + return { label: task._label, description, task, detail: this.showDetail() ? task.configurationProperties.detail : undefined }; }; function fillEntries(entries: QuickPickInput[], tasks: Task[], groupLabel: string): void { if (tasks.length) { diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index c9f8cd30550..01517dfd302 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -358,5 +358,10 @@ configurationRegistry.registerConfiguration({ type: 'number', default: 30, minimum: 0, maximum: 30 }, + 'task.quickOpen.detail': { + markdownDescription: nls.localize('task.quickOpen.detail', "Controls whether to show the task detail for task that have a detail in the Run Task quick pick."), + type: 'boolean', + default: true + } } }); diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index 58d396469d8..66c4f690076 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -89,6 +89,11 @@ const dependsOrder: IJSONSchema = { description: nls.localize('JsonSchema.tasks.dependsOrder', 'Determines the order of the dependsOn tasks for this task. Note that this property is not recursive.') }; +const detail: IJSONSchema = { + type: 'string', + description: nls.localize('JsonSchema.tasks.detail', 'An optional description of a task that shows in the Run Task quick pick as a detail.') +}; + const presentation: IJSONSchema = { type: 'object', default: { @@ -365,7 +370,8 @@ let taskConfiguration: IJSONSchema = { }, runOptions: Objects.deepClone(runOptions), dependsOn: Objects.deepClone(dependsOn), - dependsOrder: Objects.deepClone(dependsOrder) + dependsOrder: Objects.deepClone(dependsOrder), + detail: Objects.deepClone(detail), } }; @@ -425,6 +431,7 @@ taskDescriptionProperties.presentation = Objects.deepClone(presentation); taskDescriptionProperties.terminal = terminal; taskDescriptionProperties.group = Objects.deepClone(group); taskDescriptionProperties.runOptions = Objects.deepClone(runOptions); +taskDescriptionProperties.detail = detail; taskDescriptionProperties.taskName.deprecationMessage = nls.localize( 'JsonSchema.tasks.taskName.deprecated', 'The task\'s name property is deprecated. Use the label property instead.' diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index be9cb7c97fc..b60c54b7866 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -309,6 +309,11 @@ export interface ConfigurationProperties { */ group?: string | GroupKind; + /** + * A description of the task. + */ + detail?: string; + /** * The other tasks the task depend on */ @@ -1326,6 +1331,9 @@ namespace ConfigurationProperties { if (configProblemMatcher !== undefined) { result.problemMatchers = configProblemMatcher; } + if (external.detail) { + result.detail = external.detail; + } return isEmpty(result) ? undefined : result; } @@ -1587,6 +1595,7 @@ namespace CustomTask { assignProperty(resultConfigProps, configuredProps.configurationProperties, 'dependsOn'); assignProperty(resultConfigProps, configuredProps.configurationProperties, 'problemMatchers'); assignProperty(resultConfigProps, configuredProps.configurationProperties, 'promptOnClose'); + assignProperty(resultConfigProps, configuredProps.configurationProperties, 'detail'); result.command.presentation = CommandConfiguration.PresentationOptions.assignProperties( result.command.presentation!, configuredProps.configurationProperties.presentation)!; result.command.options = CommandOptions.assignProperties(result.command.options, configuredProps.configurationProperties.options); @@ -1598,6 +1607,7 @@ namespace CustomTask { fillProperty(resultConfigProps, contributedConfigProps, 'dependsOn'); fillProperty(resultConfigProps, contributedConfigProps, 'problemMatchers'); fillProperty(resultConfigProps, contributedConfigProps, 'promptOnClose'); + fillProperty(resultConfigProps, contributedConfigProps, 'detail'); result.command.presentation = CommandConfiguration.PresentationOptions.fillProperties( result.command.presentation!, contributedConfigProps.presentation)!; result.command.options = CommandOptions.fillProperties(result.command.options, contributedConfigProps.options); diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 0509e545b2d..6cde38187b1 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -504,6 +504,11 @@ export interface ConfigurationProperties { */ dependsOrder?: DependsOrder; + /** + * A description of the task. + */ + detail?: string; + /** * The problem watchers to use for this task */