From d4d168bfa66454cf08486edab19641ae62553011 Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega Date: Thu, 23 Jan 2025 17:54:19 -0800 Subject: [PATCH 1/4] Persisted storage for replace widget --- .../base/browser/ui/findinput/replaceInput.ts | 7 +- src/vs/editor/common/config/editorOptions.ts | 23 ++++- .../contrib/find/browser/findController.ts | 5 +- .../editor/contrib/find/browser/findWidget.ts | 8 +- .../find/browser/replaceWidgetHistory.ts | 99 +++++++++++++++++++ .../contrib/find/notebookFindReplaceWidget.ts | 2 +- .../contrib/search/browser/searchWidget.ts | 2 +- 7 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 src/vs/editor/contrib/find/browser/replaceWidgetHistory.ts diff --git a/src/vs/base/browser/ui/findinput/replaceInput.ts b/src/vs/base/browser/ui/findinput/replaceInput.ts index 22a81e211c929..11c3c04a8cc7c 100644 --- a/src/vs/base/browser/ui/findinput/replaceInput.ts +++ b/src/vs/base/browser/ui/findinput/replaceInput.ts @@ -17,6 +17,7 @@ import { KeyCode } from '../../../common/keyCodes.js'; import './findInput.css'; import * as nls from '../../../../nls.js'; import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js'; +import { IHistory } from '../../../common/history.js'; export interface IReplaceInputOptions { @@ -29,7 +30,7 @@ export interface IReplaceInputOptions { readonly flexibleMaxHeight?: number; readonly appendPreserveCaseLabel?: string; - readonly history?: string[]; + readonly history?: IHistory; readonly showHistoryHint?: () => boolean; readonly inputBoxStyles: IInputBoxStyles; readonly toggleStyles: IToggleStyles; @@ -94,7 +95,7 @@ export class ReplaceInput extends Widget { this.label = options.label || NLS_DEFAULT_LABEL; const appendPreserveCaseLabel = options.appendPreserveCaseLabel || ''; - const history = options.history || []; + const history = options.history || new Set([]); const flexibleHeight = !!options.flexibleHeight; const flexibleWidth = !!options.flexibleWidth; const flexibleMaxHeight = options.flexibleMaxHeight; @@ -108,7 +109,7 @@ export class ReplaceInput extends Widget { validationOptions: { validation: this.validation }, - history: new Set(history), + history, showHistoryHint: options.showHistoryHint, flexibleHeight, flexibleWidth, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 60057bc930e44..b01d6ecd30d6e 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -1670,7 +1670,12 @@ export interface IEditorFindOptions { * @internal * Controls how the find widget search history should be stored */ - history?: 'never' | 'workspace'; + findHistory?: 'never' | 'workspace'; + /** + * @internal + * Controls how the find widget search history should be stored + */ + replaceHistory?: 'never' | 'workspace'; } /** @@ -1688,7 +1693,8 @@ class EditorFind extends BaseEditorOption(input.history, this.defaultValue.history, ['never', 'workspace']), + findHistory: stringSet<'never' | 'workspace'>(input.findHistory, this.defaultValue.findHistory, ['never', 'workspace']), + replaceHistory: stringSet<'never' | 'workspace'>(input.replaceHistory, this.defaultValue.replaceHistory, ['never', 'workspace']), }; } } diff --git a/src/vs/editor/contrib/find/browser/findController.ts b/src/vs/editor/contrib/find/browser/findController.ts index 128d89dc571f3..6b6102ea5ac94 100644 --- a/src/vs/editor/contrib/find/browser/findController.ts +++ b/src/vs/editor/contrib/find/browser/findController.ts @@ -33,6 +33,7 @@ import { IThemeService, themeColorFromId } from '../../../../platform/theme/comm import { Selection } from '../../../common/core/selection.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; import { FindWidgetSearchHistory } from './findWidgetSearchHistory.js'; +import { ReplaceWidgetHistory } from './replaceWidgetHistory.js'; const SEARCH_STRING_MAX_LENGTH = 524288; @@ -444,6 +445,7 @@ export class FindController extends CommonFindController implements IFindControl private _widget: FindWidget | null; private _findOptionsWidget: FindOptionsWidget | null; private _findWidgetSearchHistory: FindWidgetSearchHistory; + private _replaceWidgetHistory: ReplaceWidgetHistory; constructor( editor: ICodeEditor, @@ -460,6 +462,7 @@ export class FindController extends CommonFindController implements IFindControl this._widget = null; this._findOptionsWidget = null; this._findWidgetSearchHistory = FindWidgetSearchHistory.getOrCreate(_storageService); + this._replaceWidgetHistory = ReplaceWidgetHistory.getOrCreate(_storageService); } protected override async _start(opts: IFindStartOptions, newState?: INewFindReplaceState): Promise { @@ -511,7 +514,7 @@ export class FindController extends CommonFindController implements IFindControl } private _createFindWidget() { - this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService, this._hoverService, this._findWidgetSearchHistory)); + this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService, this._hoverService, this._findWidgetSearchHistory, this._replaceWidgetHistory)); this._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService)); } diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index 96786676a39ca..a305114ac1e04 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -175,6 +175,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL notificationService: INotificationService, private readonly _hoverService: IHoverService, private readonly _findWidgetSearchHistory: IHistory | undefined, + private readonly _replaceWidgetHistory: IHistory | undefined, ) { super(); this._codeEditor = codeEditor; @@ -941,7 +942,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL const flexibleHeight = true; const flexibleWidth = true; // Find input - const findSearchHistoryConfig = this._codeEditor.getOption(EditorOption.find).history; + const findSearchHistoryConfig = this._codeEditor.getOption(EditorOption.find).findHistory; + const replaceHistoryConfig = this._codeEditor.getOption(EditorOption.find).replaceHistory; this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewProvider, { width: FIND_INPUT_AREA_WIDTH, label: NLS_FIND_INPUT_LABEL, @@ -1112,13 +1114,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL label: NLS_REPLACE_INPUT_LABEL, placeholder: NLS_REPLACE_INPUT_PLACEHOLDER, appendPreserveCaseLabel: this._keybindingLabelFor(FIND_IDS.TogglePreserveCaseCommand), - history: [], + history: replaceHistoryConfig === 'workspace' ? this._replaceWidgetHistory : new Set([]), flexibleHeight, flexibleWidth, flexibleMaxHeight: 118, showHistoryHint: () => showHistoryKeybindingHint(this._keybindingService), inputBoxStyles: defaultInputBoxStyles, - toggleStyles: defaultToggleStyles + toggleStyles: defaultToggleStyles, }, this._contextKeyService, true)); this._replaceInput.setPreserveCase(!!this._state.preserveCase); this._register(this._replaceInput.onKeyDown((e) => this._onReplaceInputKeyDown(e))); diff --git a/src/vs/editor/contrib/find/browser/replaceWidgetHistory.ts b/src/vs/editor/contrib/find/browser/replaceWidgetHistory.ts new file mode 100644 index 0000000000000..a570cc7b9e275 --- /dev/null +++ b/src/vs/editor/contrib/find/browser/replaceWidgetHistory.ts @@ -0,0 +1,99 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from '../../../../base/common/event.js'; +import { IHistory } from '../../../../base/common/history.js'; +import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; + +export class ReplaceWidgetHistory implements IHistory { + public static readonly FIND_HISTORY_KEY = 'workbench.replace.history'; + private inMemoryValues: Set = new Set(); + public onDidChange?: Event; + private _onDidChangeEmitter: Emitter; + + private static _instance: ReplaceWidgetHistory | null = null; + + static getOrCreate( + storageService: IStorageService, + ): ReplaceWidgetHistory { + if (!ReplaceWidgetHistory._instance) { + ReplaceWidgetHistory._instance = new ReplaceWidgetHistory(storageService); + } + return ReplaceWidgetHistory._instance; + } + + constructor( + @IStorageService private readonly storageService: IStorageService, + ) { + this._onDidChangeEmitter = new Emitter(); + this.onDidChange = this._onDidChangeEmitter.event; + this.load(); + } + + delete(t: string): boolean { + const result = this.inMemoryValues.delete(t); + this.save(); + return result; + } + + add(t: string): this { + this.inMemoryValues.add(t); + this.save(); + return this; + } + + has(t: string): boolean { + return this.inMemoryValues.has(t); + } + + clear(): void { + this.inMemoryValues.clear(); + this.save(); + } + + forEach(callbackfn: (value: string, value2: string, set: Set) => void, thisArg?: any): void { + // fetch latest from storage + this.load(); + return this.inMemoryValues.forEach(callbackfn); + } + replace?(t: string[]): void { + this.inMemoryValues = new Set(t); + this.save(); + } + + load() { + let result: [] | undefined; + const raw = this.storageService.get( + ReplaceWidgetHistory.FIND_HISTORY_KEY, + StorageScope.WORKSPACE + ); + + if (raw) { + try { + result = JSON.parse(raw); + } catch (e) { + // Invalid data + } + } + + this.inMemoryValues = new Set(result || []); + } + + // Run saves async + save(): Promise { + const elements: string[] = []; + this.inMemoryValues.forEach(e => elements.push(e)); + return new Promise(resolve => { + this.storageService.store( + ReplaceWidgetHistory.FIND_HISTORY_KEY, + JSON.stringify(elements), + StorageScope.WORKSPACE, + StorageTarget.USER, + ); + this._onDidChangeEmitter.fire(elements); + resolve(); + }); + } +} diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts index 8509900d4b07b..74a3bc881b5c9 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts @@ -566,7 +566,7 @@ export abstract class SimpleFindReplaceWidget extends Widget { this._replaceInput = this._register(new ContextScopedReplaceInput(null, undefined, { label: NLS_REPLACE_INPUT_LABEL, placeholder: NLS_REPLACE_INPUT_PLACEHOLDER, - history: [], + history: new Set([]), inputBoxStyles: defaultInputBoxStyles, toggleStyles: defaultToggleStyles }, contextKeyService, false)); diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 3b1bab8cf7186..77b589490ec4a 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -512,7 +512,7 @@ export class SearchWidget extends Widget { label: nls.localize('label.Replace', 'Replace: Type replace term and press Enter to preview'), placeholder: nls.localize('search.replace.placeHolder', "Replace"), appendPreserveCaseLabel: appendKeyBindingLabel('', this.keybindingService.lookupKeybinding(Constants.SearchCommandIds.TogglePreserveCaseId)), - history: options.replaceHistory, + history: new Set(options.replaceHistory), showHistoryHint: () => showHistoryKeybindingHint(this.keybindingService), flexibleHeight: true, flexibleMaxHeight: SearchWidget.INPUT_MAX_HEIGHT, From 6551f0c830ef12f6e54d13f7f23992cedd576b76 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 23 Jan 2025 18:47:56 -0800 Subject: [PATCH 2/4] Initialize shellType state after reconnect (#238588) --- src/vs/workbench/api/browser/mainThreadTerminalService.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 9482ade466111..90d5a2ec03fb5 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -93,6 +93,9 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape for (const instance of this._terminalService.instances) { this._onTerminalOpened(instance); instance.processReady.then(() => this._onTerminalProcessIdReady(instance)); + if (instance.shellType) { + this._proxy.$acceptTerminalShellType(instance.instanceId, instance.shellType); + } } const activeInstance = this._terminalService.activeInstance; if (activeInstance) { From 235263308ba950c69cd6f46fe75fe5272309bcce Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 23 Jan 2025 21:12:14 -0600 Subject: [PATCH 3/4] adjust terminal suggest font, line height when they change (#238611) --- .../suggest/browser/terminalSuggestAddon.ts | 5 ++++- .../suggest/browser/simpleSuggestWidget.ts | 11 ++++++++--- .../browser/simpleSuggestWidgetRenderer.ts | 17 +++++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts index 1fdfe2f4262c4..a175d8f35d4f4 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts @@ -401,7 +401,10 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest const fontInfo: ISimpleSuggestWidgetFontInfo = { fontFamily: font.fontFamily, fontSize: font.fontSize, - lineHeight: Math.ceil(1.5 * font.fontSize), + // In the editor's world, lineHeight is the pixels between the baselines of two lines of text + // In the terminal's world, lineHeight is the multiplier of the font size + // 1.5 is needed so that it's taller than a 16px icon + lineHeight: Math.ceil(c.lineHeight * font.fontSize * 1.5), fontWeight: c.fontWeight.toString(), letterSpacing: font.letterSpacing }; diff --git a/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts b/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts index bbb56eefaeb1c..6092257e73d43 100644 --- a/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts +++ b/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts @@ -23,6 +23,7 @@ import { IConfigurationService } from '../../../../platform/configuration/common import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { canExpandCompletionItem, SimpleSuggestDetailsOverlay, SimpleSuggestDetailsWidget } from './simpleSuggestWidgetDetails.js'; import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +import { TerminalSettingId } from '../../../../platform/terminal/common/terminal.js'; const $ = dom.$; @@ -179,7 +180,7 @@ export class SimpleSuggestWidget extends Disposable { const applyIconStyle = () => this.element.domNode.classList.toggle('no-icons', !_configurationService.getValue('editor.suggest.showIcons')); applyIconStyle(); - const renderer = new SimpleSuggestWidgetItemRenderer(_getFontInfo); + const renderer = new SimpleSuggestWidgetItemRenderer(_getFontInfo, this._configurationService); this._register(renderer); this._listElement = dom.append(this.element.domNode, $('.tree')); this._list = this._register(new List('SuggestWidget', this._listElement, { @@ -246,6 +247,10 @@ export class SimpleSuggestWidget extends Disposable { if (e.affectsConfiguration('editor.suggest.showIcons')) { applyIconStyle(); } + if (this._completionModel && e.affectsConfiguration(TerminalSettingId.FontSize) || e.affectsConfiguration(TerminalSettingId.LineHeight) || e.affectsConfiguration(TerminalSettingId.FontFamily)) { + this._layout(undefined); + this._list.splice(0, this._list.length, this._completionModel!.items); + } if (_options.statusBarMenuId && _options.showStatusBarSettingId && e.affectsConfiguration(_options.showStatusBarSettingId)) { const showStatusBar: boolean = _configurationService.getValue(_options.showStatusBarSettingId); if (showStatusBar && !this._status) { @@ -764,9 +769,9 @@ export class SimpleSuggestWidget extends Disposable { private _getLayoutInfo() { const fontInfo = this._getFontInfo(); - const itemHeight = clamp(Math.ceil(fontInfo.lineHeight), 8, 1000); + const itemHeight = clamp(fontInfo.lineHeight, 8, 1000); const statusBarHeight = !this._options.statusBarMenuId || !this._options.showStatusBarSettingId || !this._configurationService.getValue(this._options.showStatusBarSettingId) || this._state === State.Empty || this._state === State.Loading ? 0 : itemHeight; - const borderWidth = 1; //this._details.widget.borderWidth; + const borderWidth = this._details.widget.borderWidth; const borderHeight = 2 * borderWidth; return { diff --git a/src/vs/workbench/services/suggest/browser/simpleSuggestWidgetRenderer.ts b/src/vs/workbench/services/suggest/browser/simpleSuggestWidgetRenderer.ts index 83605e2156de9..71129442dda41 100644 --- a/src/vs/workbench/services/suggest/browser/simpleSuggestWidgetRenderer.ts +++ b/src/vs/workbench/services/suggest/browser/simpleSuggestWidgetRenderer.ts @@ -12,6 +12,8 @@ import { Emitter, Event } from '../../../../base/common/event.js'; import { createMatches } from '../../../../base/common/filters.js'; import { DisposableStore } from '../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; +import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; +import { TerminalSettingId } from '../../../../platform/terminal/common/terminal.js'; export function getAriaId(index: number): string { return `simple-suggest-aria-id-${index}`; @@ -55,13 +57,16 @@ export class SimpleSuggestWidgetItemRenderer implements IListRenderer(); readonly onDidToggleDetails: Event = this._onDidToggleDetails.event; + private readonly _disposables = new DisposableStore(); + readonly templateId = 'suggestion'; - constructor(private readonly _getFontInfo: () => ISimpleSuggestWidgetFontInfo) { + constructor(private readonly _getFontInfo: () => ISimpleSuggestWidgetFontInfo, @IConfigurationService private readonly _configurationService: IConfigurationService) { } dispose(): void { this._onDidToggleDetails.dispose(); + this._disposables.dispose(); } renderTemplate(container: HTMLElement): ISimpleSuggestionTemplateData { @@ -111,11 +116,11 @@ export class SimpleSuggestWidgetItemRenderer implements IListRenderer { - // if (e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.suggestFontSize) || e.hasChanged(EditorOption.suggestLineHeight)) { - // configureFont(); - // } - // })); + this._disposables.add(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(TerminalSettingId.FontSize) || e.affectsConfiguration(TerminalSettingId.FontFamily) || e.affectsConfiguration(TerminalSettingId.FontWeight) || e.affectsConfiguration(TerminalSettingId.LineHeight)) { + configureFont(); + } + })); return { root, left, right, icon, colorspan, iconLabel, iconContainer, parametersLabel, qualifierLabel, detailsLabel, disposables }; } From f5782f528629d4200a964cc652055a4da43a7eb1 Mon Sep 17 00:00:00 2001 From: sunnylost Date: Fri, 24 Jan 2025 11:12:35 +0800 Subject: [PATCH 4/4] fix(settings-editor): ensure the width of the key name does not shrink (#229919) --- .../contrib/preferences/browser/media/settingsWidgets.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css b/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css index 89ba7579904be..088783e156c66 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css @@ -72,6 +72,7 @@ display: inline-block; line-height: 24px; min-height: 24px; + flex: none; } /* Use monospace to display glob patterns in include/exclude widget */