diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 8861615198..ad89bba4be 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -8940,281 +8940,6 @@ declare module 'vscode' { */ export const onDidChange: Event; } - - //#region Comments - - /** - * Collapsible state of a [comment thread](#CommentThread) - */ - export enum CommentThreadCollapsibleState { - /** - * Determines an item is collapsed - */ - Collapsed = 0, - - /** - * Determines an item is expanded - */ - Expanded = 1 - } - - /** - * A collection of [comments](#Comment) representing a conversation at a particular range in a document. - */ - export interface CommentThread { - /** - * A unique identifier of the comment thread. - */ - readonly id: string; - - /** - * The uri of the document the thread has been created on. - */ - readonly uri: Uri; - - /** - * The range the comment thread is located within the document. The thread icon will be shown - * at the first line of the range. - */ - readonly range: Range; - - /** - * The ordered comments of the thread. - */ - comments: Comment[]; - - /** - * Whether the thread should be collapsed or expanded when opening the document. - * Defaults to Collapsed. - */ - collapsibleState: CommentThreadCollapsibleState; - - /** - * The optional human-readable label describing the [Comment Thread](#CommentThread) - */ - label?: string; - - /** - * Optional accept input command - * - * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. - * This command will be invoked when users the user accepts the value in the comment editor. - * This command will disabled when the comment editor is empty. - */ - acceptInputCommand?: Command; - - - /** - * Dispose this comment thread. - * - * Once disposed, this comment thread will be removed from visible editors and Comment Panel when approriate. - */ - dispose(): void; - } - - /** - * Author information of a [comment](#Comment) - */ - - export interface CommentAuthorInformation { - /** - * The display name of the author of the comment - */ - name: string; - - /** - * The optional icon path for the author - */ - iconPath?: Uri; - } - - /** - * Author information of a [comment](#Comment) - */ - - export interface CommentAuthorInformation { - /** - * The display name of the author of the comment - */ - name: string; - - /** - * The optional icon path for the author - */ - iconPath?: Uri; - } - - /** - * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. - */ - export interface Comment { - /** - * The id of the comment - */ - id: string; - - /** - * The human-readable comment body - */ - body: MarkdownString; - - /** - * The author information of the comment - */ - author: CommentAuthorInformation; - - /** - * Optional label describing the [Comment](#Comment) - * Label will be rendered next to authorName if exists. - */ - label?: string; - - /** - * The command to be executed if the comment is selected in the Comments Panel - */ - selectCommand?: Command; - - /** - * The command to be executed when users try to save the edits to the comment - */ - editCommand?: Command; - } - - /** - * The comment input box in Comment Widget. - */ - export interface CommentInputBox { - /** - * Setter and getter for the contents of the comment input box - */ - value: string; - - /** - * The uri of the document comment input box has been created on - */ - resource: Uri; - - /** - * The range the comment input box is located within the document - */ - range: Range; - } - - /** - * Commenting range provider for a [comment controller](#CommentController). - */ - export interface CommentingRangeProvider { - /** - * Provide a list of ranges which allow new comment threads creation or null for a given document - */ - provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult; - } - - /** - * Comment thread template for new comment thread creation. - */ - export interface CommentThreadTemplate { - /** - * The human-readable label describing the [Comment Thread](#CommentThread) - */ - readonly label: string; - - /** - * Optional accept input command - * - * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. - * This command will be invoked when users the user accepts the value in the comment editor. - * This command will disabled when the comment editor is empty. - */ - readonly acceptInputCommand?: Command; - - /** - * Optional additonal commands. - * - * `additionalCommands` are the secondary actions rendered on Comment Widget. - */ - readonly additionalCommands?: Command[]; - - /** - * The command to be executed when users try to delete the comment thread. Currently, this is only called - * when the user collapses a comment thread that has no comments in it. - */ - readonly deleteCommand?: Command; - } - - /** - * A comment controller is able to provide [comments](#CommentThread) support to the editor and - * provide users various ways to interact with comments. - */ - export interface CommentController { - /** - * The id of this comment controller. - */ - readonly id: string; - - /** - * The human-readable label of this comment controller. - */ - readonly label: string; - - /** - * The active [comment input box](#CommentInputBox) or `undefined`. The active `inputBox` is the input box of - * the comment thread widget that currently has focus. It's `undefined` when the focus is not in any CommentInputBox. - */ - readonly inputBox: CommentInputBox | undefined; - - /** - * Optional comment thread template information. - * - * The comment controller will use this information to create the comment widget when users attempt to create new comment thread - * from the gutter or command palette. - * - * When users run `CommentThreadTemplate.acceptInputCommand` or `CommentThreadTemplate.additionalCommands`, extensions should create - * the approriate [CommentThread](#CommentThread). - * - * If not provided, users won't be able to create new comment threads in the editor. - */ - template?: CommentThreadTemplate; - - /** - * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. - * - * If not provided and `emptyCommentThreadFactory` exits, users can leave comments in any document opened in the editor. - */ - commentingRangeProvider?: CommentingRangeProvider; - - /** - * Create a [comment thread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) - * and Comments Panel once created. - * - * @param id An `id` for the comment thread. - * @param resource The uri of the document the thread has been created on. - * @param range The range the comment thread is located within the document. - * @param comments The ordered comments of the thread. - */ - createCommentThread(id: string, uri: Uri, range: Range, comments: Comment[]): CommentThread; - - /** - * Dispose this comment controller. - * - * Once disposed, all [comment threads](#CommentThread) created by this comment controller will also be removed from the editor - * and Comments Panel. - */ - dispose(): void; - } - - namespace comment { - /** - * Creates a new [comment controller](#CommentController) instance. - * - * @param id An `id` for the comment controller. - * @param label A human-readable string for the comment controller. - * @return An instance of [comment controller](#CommentController). - */ - export function createCommentController(id: string, label: string): CommentController; - } - - //#endregion } /** diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 08bb99320a..923f6de0e6 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -961,6 +961,277 @@ declare module 'vscode' { export function registerWorkspaceCommentProvider(provider: WorkspaceCommentProvider): Disposable; } + /** + * Collapsible state of a [comment thread](#CommentThread) + */ + export enum CommentThreadCollapsibleState { + /** + * Determines an item is collapsed + */ + Collapsed = 0, + + /** + * Determines an item is expanded + */ + Expanded = 1 + } + + /** + * A collection of [comments](#Comment) representing a conversation at a particular range in a document. + */ + export interface CommentThread { + /** + * A unique identifier of the comment thread. + */ + readonly id: string; + + /** + * The uri of the document the thread has been created on. + */ + readonly uri: Uri; + + /** + * The range the comment thread is located within the document. The thread icon will be shown + * at the first line of the range. + */ + readonly range: Range; + + /** + * The ordered comments of the thread. + */ + comments: Comment[]; + + /** + * Whether the thread should be collapsed or expanded when opening the document. + * Defaults to Collapsed. + */ + collapsibleState: CommentThreadCollapsibleState; + + /** + * The optional human-readable label describing the [Comment Thread](#CommentThread) + */ + label?: string; + + /** + * Optional accept input command + * + * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. + * This command will be invoked when users the user accepts the value in the comment editor. + * This command will disabled when the comment editor is empty. + */ + acceptInputCommand?: Command; + + + /** + * Dispose this comment thread. + * + * Once disposed, this comment thread will be removed from visible editors and Comment Panel when approriate. + */ + dispose(): void; + } + + /** + * Author information of a [comment](#Comment) + */ + + export interface CommentAuthorInformation { + /** + * The display name of the author of the comment + */ + name: string; + + /** + * The optional icon path for the author + */ + iconPath?: Uri; + } + + /** + * Author information of a [comment](#Comment) + */ + + export interface CommentAuthorInformation { + /** + * The display name of the author of the comment + */ + name: string; + + /** + * The optional icon path for the author + */ + iconPath?: Uri; + } + + /** + * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. + */ + export interface Comment { + /** + * The id of the comment + */ + id: string; + + /** + * The human-readable comment body + */ + body: MarkdownString; + + /** + * The author information of the comment + */ + author: CommentAuthorInformation; + + /** + * Optional label describing the [Comment](#Comment) + * Label will be rendered next to authorName if exists. + */ + label?: string; + + /** + * The command to be executed if the comment is selected in the Comments Panel + */ + selectCommand?: Command; + + /** + * The command to be executed when users try to save the edits to the comment + */ + editCommand?: Command; + } + + /** + * The comment input box in Comment Widget. + */ + export interface CommentInputBox { + /** + * Setter and getter for the contents of the comment input box + */ + value: string; + + /** + * The uri of the document comment input box has been created on + */ + resource: Uri; + + /** + * The range the comment input box is located within the document + */ + range: Range; + } + + /** + * Commenting range provider for a [comment controller](#CommentController). + */ + export interface CommentingRangeProvider { + /** + * Provide a list of ranges which allow new comment threads creation or null for a given document + */ + provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult; + } + + /** + * Comment thread template for new comment thread creation. + */ + export interface CommentThreadTemplate { + /** + * The human-readable label describing the [Comment Thread](#CommentThread) + */ + readonly label: string; + + /** + * Optional accept input command + * + * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. + * This command will be invoked when users the user accepts the value in the comment editor. + * This command will disabled when the comment editor is empty. + */ + readonly acceptInputCommand?: Command; + + /** + * Optional additonal commands. + * + * `additionalCommands` are the secondary actions rendered on Comment Widget. + */ + readonly additionalCommands?: Command[]; + + /** + * The command to be executed when users try to delete the comment thread. Currently, this is only called + * when the user collapses a comment thread that has no comments in it. + */ + readonly deleteCommand?: Command; + } + + /** + * A comment controller is able to provide [comments](#CommentThread) support to the editor and + * provide users various ways to interact with comments. + */ + export interface CommentController { + /** + * The id of this comment controller. + */ + readonly id: string; + + /** + * The human-readable label of this comment controller. + */ + readonly label: string; + + /** + * The active [comment input box](#CommentInputBox) or `undefined`. The active `inputBox` is the input box of + * the comment thread widget that currently has focus. It's `undefined` when the focus is not in any CommentInputBox. + */ + readonly inputBox: CommentInputBox | undefined; + + /** + * Optional comment thread template information. + * + * The comment controller will use this information to create the comment widget when users attempt to create new comment thread + * from the gutter or command palette. + * + * When users run `CommentThreadTemplate.acceptInputCommand` or `CommentThreadTemplate.additionalCommands`, extensions should create + * the approriate [CommentThread](#CommentThread). + * + * If not provided, users won't be able to create new comment threads in the editor. + */ + template?: CommentThreadTemplate; + + /** + * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. + * + * If not provided and `emptyCommentThreadFactory` exits, users can leave comments in any document opened in the editor. + */ + commentingRangeProvider?: CommentingRangeProvider; + + /** + * Create a [comment thread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) + * and Comments Panel once created. + * + * @param id An `id` for the comment thread. + * @param resource The uri of the document the thread has been created on. + * @param range The range the comment thread is located within the document. + * @param comments The ordered comments of the thread. + */ + createCommentThread(id: string, uri: Uri, range: Range, comments: Comment[]): CommentThread; + + /** + * Dispose this comment controller. + * + * Once disposed, all [comment threads](#CommentThread) created by this comment controller will also be removed from the editor + * and Comments Panel. + */ + dispose(): void; + } + + namespace comment { + /** + * Creates a new [comment controller](#CommentController) instance. + * + * @param id An `id` for the comment controller. + * @param label A human-readable string for the comment controller. + * @return An instance of [comment controller](#CommentController). + */ + export function createCommentController(id: string, label: string): CommentController; + } + //#endregion //#region Terminal diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index daaf482536..069778aed8 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -369,7 +369,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha sortText: data.e, filterText: data.f, preselect: data.g, - insertText: data.h || data.a, + insertText: typeof data.h === 'undefined' ? data.a : data.h, insertTextRules: data.i, range: data.j || defaultRange, commitCharacters: data.k, diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index bc457c3c64..e1ecf1ad89 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -11,7 +11,7 @@ import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowO import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ExplorerFocusCondition, FileOnDiskContentProvider, VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files'; +import { ExplorerFocusCondition, FileOnDiskContentProvider, VIEWLET_ID, IExplorerService, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; @@ -359,7 +359,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const name = basename(uri); const editorLabel = nls.localize('modifiedLabel', "{0} (on disk) ↔ {1}", name, name); - editorService.openEditor({ leftResource: uri.with({ scheme: COMPARE_WITH_SAVED_SCHEMA }), rightResource: uri, label: editorLabel }).then(() => { + editorService.openEditor({ leftResource: resourceToFileOnDisk(COMPARE_WITH_SAVED_SCHEMA, uri), rightResource: uri, label: editorLabel }).then(() => { // Dispose once no more diff editor is opened with the scheme if (registerEditorListener) { diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 53b277e4db..f2586ca831 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -511,8 +511,10 @@ export class ExplorerView extends ViewletPanel { return; } - // Expand all stats in the parent chain - let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => isEqualOrParent(resource, i.resource))[0]; + // Expand all stats in the parent chain. + let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => isEqualOrParent(resource, i.resource)) + // Take the root that is the closest to the stat #72299 + .sort((first, second) => second.resource.path.length - first.resource.path.length)[0]; while (item && item.resource.toString() !== resource.toString()) { await this.tree.expand(item); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts index 7fb658fe88..b3b9aae00e 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts @@ -150,6 +150,11 @@ export const tocData: ITOCEntry = { label: localize('terminal', "Terminal"), settings: ['terminal.*'] }, + { + id: 'features/tasks', + label: localize('tasks', "Tasks"), + settings: ['tasks.*'] + }, { id: 'features/problems', label: localize('problems', "Problems"), diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index b14d2a24af..36aba9f059 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -100,16 +100,16 @@ const presentation: IJSONSchema = { default: false, description: nls.localize('JsonSchema.tasks.presentation.focus', 'Controls whether the panel takes focus. Default is false. If set to true the panel is revealed as well.') }, - revealProblem: { + revealProblems: { type: 'string', enum: ['always', 'onProblem', 'never'], enumDescriptions: [ - nls.localize('JsonSchema.tasks.presentation.revealProblem.always', 'Always reveals the problems panel when this task is executed.'), - nls.localize('JsonSchema.tasks.presentation.revealProblem.onProblem', 'Only reveals the problems panel if a problem is found.'), - nls.localize('JsonSchema.tasks.presentation.revealProblem.never', 'Never reveals the problems panel when this task is executed.'), + nls.localize('JsonSchema.tasks.presentation.revealProblems.always', 'Always reveals the problems panel when this task is executed.'), + nls.localize('JsonSchema.tasks.presentation.revealProblems.onProblem', 'Only reveals the problems panel if a problem is found.'), + nls.localize('JsonSchema.tasks.presentation.revealProblems.never', 'Never reveals the problems panel when this task is executed.'), ], default: 'never', - description: nls.localize('JsonSchema.tasks.presentation.revealProblem', 'Controls whether the problems panel is revealed when running this task or not. Takes precedence over option \"reveal\". Default is \"never\".') + description: nls.localize('JsonSchema.tasks.presentation.revealProblems', 'Controls whether the problems panel is revealed when running this task or not. Takes precedence over option \"reveal\". Default is \"never\".') }, reveal: { type: 'string', @@ -120,7 +120,7 @@ const presentation: IJSONSchema = { nls.localize('JsonSchema.tasks.presentation.reveal.never', 'Never reveals the terminal when this task is executed.'), ], default: 'always', - description: nls.localize('JsonSchema.tasks.presentation.reveals', 'Controls whether the panel running the task is revealed or not. May be overridden by option \"revealProblem\". Default is \"always\".') + description: nls.localize('JsonSchema.tasks.presentation.reveal', 'Controls whether the terminal running the task is revealed or not. May be overridden by option \"revealProblems\". Default is \"always\".') }, panel: { type: 'string', diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index 7f4d551c2b..2ccc9984f8 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -95,7 +95,7 @@ export interface PresentationOptionsConfig { * Controls whether the problems panel is revealed when running this task or not. * Defaults to `RevealKind.Never`. */ - revealProblem?: string; + revealProblems?: string; /** * Controls whether the executed command is printed to the output window or terminal as well. @@ -802,7 +802,7 @@ namespace CommandOptions { namespace CommandConfiguration { export namespace PresentationOptions { - const properties: MetaData[] = [{ property: 'echo' }, { property: 'reveal' }, { property: 'revealProblem' }, { property: 'focus' }, { property: 'panel' }, { property: 'showReuseMessage' }, { property: 'clear' }, { property: 'group' }]; + const properties: MetaData[] = [{ property: 'echo' }, { property: 'reveal' }, { property: 'revealProblems' }, { property: 'focus' }, { property: 'panel' }, { property: 'showReuseMessage' }, { property: 'clear' }, { property: 'group' }]; interface PresentationOptionsShape extends LegacyCommandProperties { presentation?: PresentationOptionsConfig; @@ -811,7 +811,7 @@ namespace CommandConfiguration { export function from(this: void, config: PresentationOptionsShape, context: ParseContext): Tasks.PresentationOptions | undefined { let echo: boolean; let reveal: Tasks.RevealKind; - let revealProblem: Tasks.RevealProblemKind; + let revealProblems: Tasks.RevealProblemKind; let focus: boolean; let panel: Tasks.PanelKind; let showReuseMessage: boolean; @@ -834,8 +834,8 @@ namespace CommandConfiguration { if (Types.isString(presentation.reveal)) { reveal = Tasks.RevealKind.fromString(presentation.reveal); } - if (Types.isString(presentation.revealProblem)) { - revealProblem = Tasks.RevealProblemKind.fromString(presentation.revealProblem); + if (Types.isString(presentation.revealProblems)) { + revealProblems = Tasks.RevealProblemKind.fromString(presentation.revealProblems); } if (Types.isBoolean(presentation.focus)) { focus = presentation.focus; @@ -857,7 +857,7 @@ namespace CommandConfiguration { if (!hasProps) { return undefined; } - return { echo: echo!, reveal: reveal!, revealProblem: revealProblem!, focus: focus!, panel: panel!, showReuseMessage: showReuseMessage!, clear: clear!, group }; + return { echo: echo!, reveal: reveal!, revealProblems: revealProblems!, focus: focus!, panel: panel!, showReuseMessage: showReuseMessage!, clear: clear!, group }; } export function assignProperties(target: Tasks.PresentationOptions, source: Tasks.PresentationOptions | undefined): Tasks.PresentationOptions | undefined { @@ -870,7 +870,7 @@ namespace CommandConfiguration { export function fillDefaults(value: Tasks.PresentationOptions, context: ParseContext): Tasks.PresentationOptions | undefined { let defaultEcho = context.engine === Tasks.ExecutionEngine.Terminal ? true : false; - return _fillDefaults(value, { echo: defaultEcho, reveal: Tasks.RevealKind.Always, revealProblem: Tasks.RevealProblemKind.Never, focus: false, panel: Tasks.PanelKind.Shared, showReuseMessage: true, clear: false }, properties, context); + return _fillDefaults(value, { echo: defaultEcho, reveal: Tasks.RevealKind.Always, revealProblems: Tasks.RevealProblemKind.Never, focus: false, panel: Tasks.PanelKind.Shared, showReuseMessage: true, clear: false }, properties, context); } export function freeze(value: Tasks.PresentationOptions): Readonly | undefined { diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index d73b497da1..8eb48222aa 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -228,7 +228,7 @@ export interface PresentationOptions { * Controls whether the problems pane is revealed when running this task or not. * Defaults to `RevealProblemKind.Never`. */ - revealProblem: RevealProblemKind; + revealProblems: RevealProblemKind; /** * Controls whether the command associated with the task is echoed @@ -266,7 +266,7 @@ export interface PresentationOptions { export namespace PresentationOptions { export const defaults: PresentationOptions = { - echo: true, reveal: RevealKind.Always, revealProblem: RevealProblemKind.Never, focus: false, panel: PanelKind.Shared, showReuseMessage: true, clear: false + echo: true, reveal: RevealKind.Always, revealProblems: RevealProblemKind.Never, focus: false, panel: PanelKind.Shared, showReuseMessage: true, clear: false }; } diff --git a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts index 8a4afe6625..94b017b473 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts @@ -1360,6 +1360,7 @@ class TaskService extends Disposable implements ITaskService { this.modelService, this.configurationResolverService, this.telemetryService, this.contextService, this._environmentService, TaskService.OutputChannelId, + this.configurationService, (workspaceFolder: IWorkspaceFolder) => { if (!workspaceFolder) { return undefined; @@ -2741,6 +2742,7 @@ let schema: IJSONSchema = { import schemaVersion1 from '../common/jsonSchema_v1'; import schemaVersion2, { updateProblemMatchers } from '../common/jsonSchema_v2'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; schema.definitions = { ...schemaVersion1.definitions, ...schemaVersion2.definitions, @@ -2754,3 +2756,19 @@ ProblemMatcherRegistry.onMatcherChanged(() => { updateProblemMatchers(); jsonRegistry.notifySchemaChanged(schemaId); }); + +const configurationRegistry = Registry.as(Extensions.Configuration); +configurationRegistry.registerConfiguration({ + id: 'Tasks', + order: 100, + title: nls.localize('tasksConfigurationTitle', "Tasks"), + type: 'object', + properties: { + 'tasks.terminal.windowsAllowConpty': { + markdownDescription: nls.localize('tasks.terminal.windowsAllowConpty', "Works in conjunction with the `#terminal.integrated.windowsEnableConpty#` setting. Both must be enabled for tasks to use conpty. Defaults to `false`."), + type: 'boolean', + default: false + } + } +}); + diff --git a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts index 5e9885322c..6386e7fcf8 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts @@ -44,6 +44,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { Schemas } from 'vs/base/common/network'; import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; interface TerminalData { terminal: ITerminalInstance; @@ -171,7 +172,8 @@ export class TerminalTaskSystem implements ITaskSystem { private contextService: IWorkspaceContextService, private environmentService: IWorkbenchEnvironmentService, private outputChannelId: string, - taskSystemInfoResolver: TaskSystemInfoResovler + private readonly configurationService: IConfigurationService, + taskSystemInfoResolver: TaskSystemInfoResovler, ) { this.activeTasks = Object.create(null); @@ -523,8 +525,8 @@ export class TerminalTaskSystem implements ITaskSystem { if ((watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && (watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error)) { let reveal = task.command.presentation!.reveal; - let revealProblem = task.command.presentation!.revealProblem; - if (revealProblem === RevealProblemKind.OnProblem) { + let revealProblems = task.command.presentation!.revealProblems; + if (revealProblems === RevealProblemKind.OnProblem) { this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true); } else if (reveal === RevealKind.Silent) { this.terminalService.setActiveInstance(terminal!); @@ -653,8 +655,8 @@ export class TerminalTaskSystem implements ITaskSystem { } } let reveal = task.command.presentation!.reveal; - let revealProblem = task.command.presentation!.revealProblem; - let revealProblemPanel = terminal && (revealProblem === RevealProblemKind.OnProblem) && (startStopProblemMatcher.numberOfMatches > 0); + let revealProblems = task.command.presentation!.revealProblems; + let revealProblemPanel = terminal && (revealProblems === RevealProblemKind.OnProblem) && (startStopProblemMatcher.numberOfMatches > 0); if (revealProblemPanel) { this.panelService.openPanel(Constants.MARKERS_PANEL_ID); } else if (terminal && (reveal === RevealKind.Silent) && ((exitCode !== 0) || (startStopProblemMatcher.numberOfMatches > 0) && startStopProblemMatcher.maxMarkerSeverity && @@ -688,7 +690,7 @@ export class TerminalTaskSystem implements ITaskSystem { if (!terminal) { return Promise.reject(new Error(`Failed to create terminal for task ${task._label}`)); } - let showProblemPanel = task.command.presentation && (task.command.presentation.revealProblem === RevealProblemKind.Always); + let showProblemPanel = task.command.presentation && (task.command.presentation.revealProblems === RevealProblemKind.Always); if (showProblemPanel) { this.panelService.openPanel(Constants.MARKERS_PANEL_ID); } else if (task.command.presentation && (task.command.presentation.reveal === RevealKind.Always)) { @@ -877,6 +879,9 @@ export class TerminalTaskSystem implements ITaskSystem { if (options.env) { shellLaunchConfig.env = options.env; } + + // Conpty doesn't do linefeeds in an expected way. Force winpty unless the user has requested otherwise. + shellLaunchConfig.forceWinpty = !this.configurationService.getValue('tasks.terminal.windowsAllowConpty'); return shellLaunchConfig; } diff --git a/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts b/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts index 0d1df8797f..e45fac586c 100644 --- a/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts +++ b/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts @@ -83,7 +83,7 @@ class PresentationBuilder { public result: Tasks.PresentationOptions; constructor(public parent: CommandConfigurationBuilder) { - this.result = { echo: false, reveal: Tasks.RevealKind.Always, revealProblem: Tasks.RevealProblemKind.Never, focus: false, panel: Tasks.PanelKind.Shared, showReuseMessage: true, clear: false }; + this.result = { echo: false, reveal: Tasks.RevealKind.Always, revealProblems: Tasks.RevealProblemKind.Never, focus: false, panel: Tasks.PanelKind.Shared, showReuseMessage: true, clear: false }; } public echo(value: boolean): PresentationBuilder { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 61d21effd2..ae75a15120 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -182,7 +182,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables); this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env); - return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty); + const useConpty = (shellLaunchConfig.forceWinpty !== true) && this._configHelper.config.windowsEnableConpty; + return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, useConpty); } public setDimensions(cols: number, rows: number): void { diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 122f9e99a6..b21f664d5a 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -192,6 +192,12 @@ export interface IShellLaunchConfig { * provided as nothing will be inherited from the process or any configuration. */ strictEnv?: boolean; + + /** + * Moving forward, conpty will be the default. However, there are cases where conpty is not ready + * to be the default. This property will force winpty to be used, even when conpty would normally be used. + */ + forceWinpty?: boolean; } export interface ITerminalService { diff --git a/src/vs/workbench/services/files/node/diskFileSystemProvider.ts b/src/vs/workbench/services/files/node/diskFileSystemProvider.ts index 3ef02edd13..081bbea90d 100644 --- a/src/vs/workbench/services/files/node/diskFileSystemProvider.ts +++ b/src/vs/workbench/services/files/node/diskFileSystemProvider.ts @@ -80,16 +80,14 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro const children = await readdir(this.toFilePath(resource)); const result: [string, FileType][] = []; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - + await Promise.all(children.map(async child => { try { const stat = await this.stat(joinPath(resource, child)); result.push([child, stat.type]); } catch (error) { this.logService.trace(error); // ignore errors for individual entries that can arise from permission denied } - } + })); return result; } catch (error) {