Skip to content

Commit ff4f0c4

Browse files
authored
Merge branch 'main' into #163967-css-aliases
2 parents af6c927 + c1ec0ed commit ff4f0c4

10 files changed

Lines changed: 75 additions & 27 deletions

File tree

src/vs/platform/menubar/electron-main/menubar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export class Menubar {
128128
this.fallbackMenuHandlers['workbench.action.openWorkspace'] = (menuItem, win, event) => this.nativeHostMainService.pickWorkspaceAndOpen(undefined, { forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } });
129129

130130
// Recent Menu Items
131-
this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.workspacesHistoryMainService.clearRecentlyOpened();
131+
this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.workspacesHistoryMainService.clearRecentlyOpened({ confirm: true /* ask for confirmation */ });
132132

133133
// Help Menu Items
134134
const youTubeUrl = this.productService.youTubeUrl;

src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,10 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
377377
// Conpty could have the wrong cursor position at this point.
378378
if (!this._cursorOnNextLine() || !prompt) {
379379
this._windowsPromptPollingInProcess = true;
380-
// Poll for 200ms until the cursor position is correct.
380+
// Poll for 1000ms until the cursor position is correct.
381381
let i = 0;
382-
for (; i < 20; i++) {
383-
await timeout(10);
382+
for (; i < 50; i++) {
383+
await timeout(20);
384384
prompt = this._getWindowsPrompt();
385385
if (this._store.isDisposed || !this._windowsPromptPollingInProcess || this._cursorOnNextLine() && prompt) {
386386
if (!this._windowsPromptPollingInProcess) {
@@ -390,7 +390,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
390390
}
391391
}
392392
this._windowsPromptPollingInProcess = false;
393-
if (i === 20) {
393+
if (i >= 50) {
394394
this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._getWindowsPrompt());
395395
} else if (prompt) {
396396
// use the regex to set the position as it's possible input has occurred
@@ -428,9 +428,11 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
428428
private _cursorOnNextLine(): boolean {
429429
const lastCommand = this.commands.at(-1);
430430

431+
// There is only a single command, so this check is unnecessary
431432
if (!lastCommand) {
432-
return false;
433+
return true;
433434
}
435+
434436
const cursorYAbsolute = this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY;
435437
// If the cursor position is within the last command, we should poll.
436438
const lastCommandYAbsolute = (lastCommand.endMarker ? lastCommand.endMarker.line : lastCommand.marker?.line) ?? -1;
@@ -442,8 +444,26 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
442444
if (!line) {
443445
return;
444446
}
445-
// TODO: fine tune prompt regex to accomodate for unique configurtions.
446-
return line.translateToString(true)?.match(/^(?<prompt>(\(.+\)\s)?(?:PS.+>\s)|(?:[A-Z]:\\.*>))/)?.groups?.prompt;
447+
// TODO: fine tune prompt regex to accomodate for unique configurations.
448+
const lineText = line.translateToString(true);
449+
if (!lineText) {
450+
return;
451+
}
452+
453+
// PowerShell
454+
const pwshMatch = lineText.match(/(?<prompt>(\(.+\)\s)?(?:PS.+>\s?))/);
455+
if (pwshMatch) {
456+
let prompt = pwshMatch?.groups?.prompt;
457+
if (lineText === prompt && prompt.endsWith('>')) {
458+
// Conpty may not 'render' the space at the end of the prompt
459+
prompt += ' ';
460+
}
461+
return prompt;
462+
}
463+
464+
// Command Prompt
465+
const cmdMatch = lineText.match(/^(?<prompt>(\(.+\)\s)?(?:[A-Z]:\\.*>))/);
466+
return cmdMatch?.groups?.prompt;
447467
}
448468

449469
handleGenericCommand(options?: IHandleCommandOptions): void {

src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { IRecent, IRecentFile, IRecentFolder, IRecentlyOpened, IRecentWorkspace,
2424
import { IWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspace/common/workspace';
2525
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
2626
import { ResourceMap } from 'vs/base/common/map';
27+
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
2728

2829
export const IWorkspacesHistoryMainService = createDecorator<IWorkspacesHistoryMainService>('workspacesHistoryMainService');
2930

@@ -36,7 +37,7 @@ export interface IWorkspacesHistoryMainService {
3637
addRecentlyOpened(recents: IRecent[]): Promise<void>;
3738
getRecentlyOpened(): Promise<IRecentlyOpened>;
3839
removeRecentlyOpened(paths: URI[]): Promise<void>;
39-
clearRecentlyOpened(): Promise<void>;
40+
clearRecentlyOpened(options?: { confirm?: boolean }): Promise<void>;
4041
}
4142

4243
export class WorkspacesHistoryMainService extends Disposable implements IWorkspacesHistoryMainService {
@@ -54,7 +55,8 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
5455
@ILogService private readonly logService: ILogService,
5556
@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService,
5657
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
57-
@IApplicationStorageMainService private readonly applicationStorageMainService: IApplicationStorageMainService
58+
@IApplicationStorageMainService private readonly applicationStorageMainService: IApplicationStorageMainService,
59+
@IDialogMainService private readonly dialogMainService: IDialogMainService
5860
) {
5961
super();
6062

@@ -157,7 +159,24 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
157159
}
158160
}
159161

160-
async clearRecentlyOpened(): Promise<void> {
162+
async clearRecentlyOpened(options?: { confirm?: boolean }): Promise<void> {
163+
if (options?.confirm) {
164+
const { response } = await this.dialogMainService.showMessageBox({
165+
type: 'warning',
166+
buttons: [
167+
localize({ key: 'clearButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Clear"),
168+
localize({ key: 'cancel', comment: ['&& denotes a mnemonic'] }, "&&Cancel")
169+
],
170+
message: localize('confirmClearRecentsMessage', "Do you want to clear all recently opened files and workspaces?"),
171+
detail: localize('confirmClearDetail', "This action is irreversible!"),
172+
cancelId: 1
173+
});
174+
175+
if (response !== 0) {
176+
return;
177+
}
178+
}
179+
161180
await this.saveRecentlyOpened({ workspaces: [], files: [] });
162181
app.clearRecentDocuments();
163182

src/vs/workbench/browser/parts/editor/editor.contribution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, {
601601
group: 'z_clear',
602602
command: {
603603
id: ClearRecentFilesAction.ID,
604-
title: localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened")
604+
title: localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened...")
605605
},
606606
order: 1
607607
});

src/vs/workbench/browser/parts/editor/editorActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1600,7 +1600,7 @@ export class ClearRecentFilesAction extends Action2 {
16001600
constructor() {
16011601
super({
16021602
id: ClearRecentFilesAction.ID,
1603-
title: { value: localize('clearRecentFiles', "Clear Recently Opened"), original: 'Clear Recently Opened' },
1603+
title: { value: localize('clearRecentFiles', "Clear Recently Opened..."), original: 'Clear Recently Opened...' },
16041604
f1: true,
16051605
category: Categories.File
16061606
});

src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class InputEditorDecorations extends Disposable {
8989

9090
private registerViewModelListeners(): void {
9191
this.viewModelDisposables.value = this.widget.viewModel?.onDidChange(e => {
92-
if (e?.kind === 'changePlaceholder') {
92+
if (e?.kind === 'changePlaceholder' || e?.kind === 'initialize') {
9393
this.updateInputEditorDecorations();
9494
}
9595
});
@@ -127,7 +127,6 @@ class InputEditorDecorations extends Disposable {
127127

128128
private async updateInputEditorDecorations() {
129129
const inputValue = this.widget.inputEditor.getValue();
130-
const slashCommands = await this.widget.getSlashCommands(); // TODO this async call can lead to a flicker of the placeholder text when switching editor tabs
131130

132131
const viewModel = this.widget.viewModel;
133132
if (!viewModel) {
@@ -136,10 +135,7 @@ class InputEditorDecorations extends Disposable {
136135

137136
if (!inputValue) {
138137
const viewModelPlaceholder = this.widget.viewModel?.inputPlaceholder;
139-
const defaultPlaceholder = slashCommands?.length ?
140-
localize('interactive.input.placeholderWithCommands', "Ask a question or type '@' or '/'") :
141-
localize('interactive.input.placeholderNoCommands', "Ask a question");
142-
const placeholder = viewModelPlaceholder ?? defaultPlaceholder;
138+
const placeholder = viewModelPlaceholder ?? '';
143139
const decoration: IDecorationOptions[] = [
144140
{
145141
range: {

src/vs/workbench/contrib/chat/browser/media/chat.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
}
110110

111111
.interactive-item-container .header .avatar .codicon {
112-
color: var(--vscode-chat-avatarForeground);
112+
color: var(--vscode-chat-avatarForeground) !important;
113113
font-size: 14px;
114114
}
115115

src/vs/workbench/contrib/chat/common/chatViewModel.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function isWelcomeVM(item: unknown): item is IChatWelcomeMessageViewModel
2626
return !!item && typeof item === 'object' && 'content' in item;
2727
}
2828

29-
export type IChatViewModelChangeEvent = IChatAddRequestEvent | IChangePlaceholderEvent | null;
29+
export type IChatViewModelChangeEvent = IChatAddRequestEvent | IChangePlaceholderEvent | IChatSessionInitEvent | null;
3030

3131
export interface IChatAddRequestEvent {
3232
kind: 'addRequest';
@@ -36,6 +36,10 @@ export interface IChangePlaceholderEvent {
3636
kind: 'changePlaceholder';
3737
}
3838

39+
export interface IChatSessionInitEvent {
40+
kind: 'initialize';
41+
}
42+
3943
export interface IChatViewModel {
4044
readonly initState: ChatModelInitState;
4145
readonly providerId: string;
@@ -184,7 +188,10 @@ export class ChatViewModel extends Disposable implements IChatViewModel {
184188
}
185189
}
186190

187-
this._onDidChange.fire(e.kind === 'addRequest' ? { kind: 'addRequest' } : null);
191+
const modelEventToVmEvent: IChatViewModelChangeEvent = e.kind === 'addRequest' ? { kind: 'addRequest' } :
192+
e.kind === 'initialize' ? { kind: 'initialize' } :
193+
null;
194+
this._onDidChange.fire(modelEventToVmEvent);
188195
}));
189196
}
190197

src/vs/workbench/contrib/search/browser/quickTextSearch/textSearchQuickAccess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/
2929
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder';
3030
import { IPatternInfo, ITextQuery, VIEW_ID } from 'vs/workbench/services/search/common/search';
3131

32-
export const TEXT_SEARCH_QUICK_ACCESS_PREFIX = '% ';
32+
export const TEXT_SEARCH_QUICK_ACCESS_PREFIX = '%';
3333

3434
const DEFAULT_TEXT_QUERY_BUILDER_OPTIONS: ITextQueryBuilderOptions = {
3535
_reason: 'quickAccessSearch',

src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
77
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
88
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
9-
import { ITerminalLogService } from 'vs/platform/terminal/common/terminal';
9+
import { ITerminalLogService, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
1010
import type { Terminal, ITerminalAddon } from 'xterm';
1111
import { debounce } from 'vs/base/common/decorators';
1212
import { addDisposableListener } from 'vs/base/browser/dom';
13+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1314

1415
export interface ITextAreaData {
1516
content: string;
@@ -24,19 +25,20 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon {
2425

2526
activate(terminal: Terminal): void {
2627
this._terminal = terminal;
27-
if (this._accessibilityService.isScreenReaderOptimized()) {
28+
if (this._shouldBeActive()) {
2829
this._registerSyncListeners();
2930
}
3031
}
3132

3233
constructor(
3334
private readonly _capabilities: ITerminalCapabilityStore,
3435
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
36+
@IConfigurationService private readonly _configurationService: IConfigurationService,
3537
@ITerminalLogService private readonly _logService: ITerminalLogService
3638
) {
3739
super();
3840
this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => {
39-
if (this._accessibilityService.isScreenReaderOptimized()) {
41+
if (this._shouldBeActive()) {
4042
this._syncTextArea();
4143
this._registerSyncListeners();
4244
} else {
@@ -46,14 +48,18 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon {
4648
}
4749

4850
private _registerSyncListeners(): void {
49-
if (this._accessibilityService.isScreenReaderOptimized() && this._terminal?.textarea) {
51+
if (this._shouldBeActive() && this._terminal?.textarea) {
5052
this._listeners.value = new DisposableStore();
5153
this._listeners.value.add(this._terminal.onCursorMove(() => this._syncTextArea()));
5254
this._listeners.value.add(this._terminal.onData(() => this._syncTextArea()));
5355
this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._syncTextArea()));
5456
}
5557
}
5658

59+
private _shouldBeActive(): boolean {
60+
return this._accessibilityService.isScreenReaderOptimized() || this._configurationService.getValue(TerminalSettingId.DevMode);
61+
}
62+
5763
@debounce(50)
5864
private _syncTextArea(): void {
5965
this._logService.debug('TextAreaSyncAddon#syncTextArea');

0 commit comments

Comments
 (0)