Adopt Custom Hover for search/find/replace views/widgets (#206077)

* Adopt Custom Hover for search/find/replace views

* tree search filters
This commit is contained in:
Benjamin Christopher Simmonds 2024-02-23 14:36:18 +01:00 committed by GitHub
parent 0bd70d48ad
commit c18d58d962
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 89 additions and 18 deletions

View file

@ -10,6 +10,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { renderMarkdown, renderStringAsPlaintext } from 'vs/base/browser/markdownRenderer';
import { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { Action, IAction, IActionRunner } from 'vs/base/common/actions';
@ -29,6 +30,7 @@ export interface IButtonOptions extends Partial<IButtonStyles> {
readonly supportIcons?: boolean;
readonly supportShortLabel?: boolean;
readonly secondary?: boolean;
readonly hoverDelegate?: IHoverDelegate;
}
export interface IButtonStyles {
@ -115,6 +117,10 @@ export class Button extends Disposable implements IButton {
this._element.classList.add('monaco-text-button-with-short-label');
}
if (typeof options.title === 'string') {
this.setTitle(options.title);
}
if (typeof options.ariaLabel === 'string') {
this._element.setAttribute('aria-label', options.ariaLabel);
}
@ -249,16 +255,13 @@ export class Button extends Disposable implements IButton {
} else if (this.options.title) {
title = renderStringAsPlaintext(value);
}
if (!this._hover) {
this._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this._element, title));
} else {
this._hover.update(title);
}
this.setTitle(title);
if (typeof this.options.ariaLabel === 'string') {
this._element.setAttribute('aria-label', this.options.ariaLabel);
} else if (this.options.ariaLabel) {
this._element.setAttribute('aria-label', this._element.title);
this._element.setAttribute('aria-label', title);
}
this._label = value;
@ -299,6 +302,14 @@ export class Button extends Disposable implements IButton {
return !this._element.classList.contains('disabled');
}
private setTitle(title: string) {
if (!this._hover) {
this._hover = this._register(setupCustomHover(this.options.hoverDelegate ?? getDefaultHoverDelegate('mouse'), this._element, title));
} else {
this._hover.update(title);
}
}
focus(): void {
this._element.focus();
}

View file

@ -16,6 +16,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import 'vs/css!./findInput';
import * as nls from 'vs/nls';
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
export interface IFindInputOptions {
@ -113,10 +114,13 @@ export class FindInput extends Widget {
inputBoxStyles: options.inputBoxStyles,
}));
const hoverDelegate = this._register(getDefaultHoverDelegate('element', true));
if (this.showCommonFindToggles) {
this.regex = this._register(new RegexToggle({
appendTitle: appendRegexLabel,
isChecked: false,
hoverDelegate,
...options.toggleStyles
}));
this._register(this.regex.onChange(viaKeyboard => {
@ -133,6 +137,7 @@ export class FindInput extends Widget {
this.wholeWords = this._register(new WholeWordsToggle({
appendTitle: appendWholeWordsLabel,
isChecked: false,
hoverDelegate,
...options.toggleStyles
}));
this._register(this.wholeWords.onChange(viaKeyboard => {
@ -146,6 +151,7 @@ export class FindInput extends Widget {
this.caseSensitive = this._register(new CaseSensitiveToggle({
appendTitle: appendCaseSensitiveLabel,
isChecked: false,
hoverDelegate,
...options.toggleStyles
}));
this._register(this.caseSensitive.onChange(viaKeyboard => {

View file

@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { Toggle } from 'vs/base/browser/ui/toggle/toggle';
import { Codicon } from 'vs/base/common/codicons';
import * as nls from 'vs/nls';
@ -13,6 +15,7 @@ export interface IFindInputToggleOpts {
readonly inputActiveOptionBorder: string | undefined;
readonly inputActiveOptionForeground: string | undefined;
readonly inputActiveOptionBackground: string | undefined;
readonly hoverDelegate?: IHoverDelegate;
}
const NLS_CASE_SENSITIVE_TOGGLE_LABEL = nls.localize('caseDescription', "Match Case");
@ -25,6 +28,7 @@ export class CaseSensitiveToggle extends Toggle {
icon: Codicon.caseSensitive,
title: NLS_CASE_SENSITIVE_TOGGLE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
@ -38,6 +42,7 @@ export class WholeWordsToggle extends Toggle {
icon: Codicon.wholeWord,
title: NLS_WHOLE_WORD_TOGGLE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
@ -51,6 +56,7 @@ export class RegexToggle extends Toggle {
icon: Codicon.regex,
title: NLS_REGEX_TOGGLE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground

View file

@ -16,6 +16,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import 'vs/css!./findInput';
import * as nls from 'vs/nls';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
export interface IReplaceInputOptions {
@ -44,9 +45,10 @@ class PreserveCaseToggle extends Toggle {
icon: Codicon.preserveCase,
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
inputActiveOptionBackground: opts.inputActiveOptionBackground,
});
}
}

View file

@ -15,6 +15,7 @@ import 'vs/css!./toggle';
import { isActiveElement, $, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
export interface IToggleOpts extends IToggleStyles {
readonly actionClassName?: string;
@ -22,6 +23,7 @@ export interface IToggleOpts extends IToggleStyles {
readonly title: string;
readonly isChecked: boolean;
readonly notFocusable?: boolean;
readonly hoverDelegate?: IHoverDelegate;
}
export interface IToggleStyles {
@ -130,7 +132,7 @@ export class Toggle extends Widget {
}
this.domNode = document.createElement('div');
this._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.domNode, this._opts.title));
this._hover = this._register(setupCustomHover(opts.hoverDelegate ?? getDefaultHoverDelegate('mouse'), this.domNode, this._opts.title));
this.domNode.classList.add(...classes);
if (!this._opts.notFocusable) {
this.domNode.tabIndex = 0;

View file

@ -33,6 +33,8 @@ import { ISpliceable } from 'vs/base/common/sequence';
import { isNumber } from 'vs/base/common/types';
import 'vs/css!./media/tree';
import { localize } from 'vs/nls';
import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
class TreeElementsDragAndDropData<T, TFilterData, TContext> extends ElementsDragAndDropData<T, TContext> {
@ -679,6 +681,7 @@ export interface ITreeFindToggleOpts {
readonly inputActiveOptionBorder: string | undefined;
readonly inputActiveOptionForeground: string | undefined;
readonly inputActiveOptionBackground: string | undefined;
readonly hoverDelegate?: IHoverDelegate;
}
export class ModeToggle extends Toggle {
@ -687,6 +690,7 @@ export class ModeToggle extends Toggle {
icon: Codicon.listFilter,
title: localize('filter', "Filter"),
isChecked: opts.isChecked ?? false,
hoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
@ -700,6 +704,7 @@ export class FuzzyToggle extends Toggle {
icon: Codicon.searchFuzzy,
title: localize('fuzzySearch', "Fuzzy Match"),
isChecked: opts.isChecked ?? false,
hoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
@ -802,8 +807,9 @@ class FindWidget<T, TFilterData> extends Disposable {
this.elements.root.style.boxShadow = `0 0 8px 2px ${styles.listFilterWidgetShadow}`;
}
this.modeToggle = this._register(new ModeToggle({ ...styles.toggleStyles, isChecked: mode === TreeFindMode.Filter }));
this.matchTypeToggle = this._register(new FuzzyToggle({ ...styles.toggleStyles, isChecked: matchType === TreeFindMatchType.Fuzzy }));
const toggleHoverDelegate = this._register(getDefaultHoverDelegate('element', true));
this.modeToggle = this._register(new ModeToggle({ ...styles.toggleStyles, isChecked: mode === TreeFindMode.Filter, hoverDelegate: toggleHoverDelegate }));
this.matchTypeToggle = this._register(new FuzzyToggle({ ...styles.toggleStyles, isChecked: matchType === TreeFindMatchType.Fuzzy, hoverDelegate: toggleHoverDelegate }));
this.onDidChangeMode = Event.map(this.modeToggle.onChange, () => this.modeToggle.checked ? TreeFindMode.Filter : TreeFindMode.Highlight, this._store);
this.onDidChangeMatchType = Event.map(this.matchTypeToggle.onChange, () => this.matchTypeToggle.checked ? TreeFindMatchType.Fuzzy : TreeFindMatchType.Contiguous, this._store);

View file

@ -13,6 +13,7 @@ import { FIND_IDS } from 'vs/editor/contrib/find/browser/findModel';
import { FindReplaceState } from 'vs/editor/contrib/find/browser/findState';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { asCssVariable, inputActiveOptionBackground, inputActiveOptionBorder, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
export class FindOptionsWidget extends Widget implements IOverlayWidget {
@ -52,9 +53,12 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
inputActiveOptionBackground: asCssVariable(inputActiveOptionBackground),
};
const hoverDelegate = this._register(getDefaultHoverDelegate('element', true));
this.caseSensitive = this._register(new CaseSensitiveToggle({
appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand),
isChecked: this._state.matchCase,
hoverDelegate,
...toggleStyles
}));
this._domNode.appendChild(this.caseSensitive.domNode);
@ -67,6 +71,7 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
this.wholeWords = this._register(new WholeWordsToggle({
appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand),
isChecked: this._state.wholeWord,
hoverDelegate,
...toggleStyles
}));
this._domNode.appendChild(this.wholeWords.domNode);
@ -79,6 +84,7 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
this.regex = this._register(new RegexToggle({
appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand),
isChecked: this._state.isRegex,
hoverDelegate,
...toggleStyles
}));
this._domNode.appendChild(this.regex.domNode);

View file

@ -43,6 +43,9 @@ import { isHighContrast } from 'vs/platform/theme/common/theme';
import { assertIsDefined } from 'vs/base/common/types';
import { defaultInputBoxStyles, defaultToggleStyles } from 'vs/platform/theme/browser/defaultStyles';
import { Selection } from 'vs/editor/common/core/selection';
import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
const findSelectionIcon = registerIcon('find-selection', Codicon.selection, nls.localize('findSelectionIcon', 'Icon for \'Find in Selection\' in the editor find widget.'));
const findCollapsedIcon = registerIcon('find-collapsed', Codicon.chevronRight, nls.localize('findCollapsedIcon', 'Icon to indicate that the editor find widget is collapsed.'));
@ -1010,10 +1013,14 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
this._matchesCount.className = 'matchesCount';
this._updateMatchesCount();
// Create a scoped hover delegate for all find related buttons
const hoverDelegate = getDefaultHoverDelegate('element', true);
// Previous button
this._prevBtn = this._register(new SimpleButton({
label: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction),
icon: findPreviousMatchIcon,
hoverDelegate,
onTrigger: () => {
assertIsDefined(this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction)).run().then(undefined, onUnexpectedError);
}
@ -1023,6 +1030,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
this._nextBtn = this._register(new SimpleButton({
label: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction),
icon: findNextMatchIcon,
hoverDelegate,
onTrigger: () => {
assertIsDefined(this._codeEditor.getAction(FIND_IDS.NextMatchFindAction)).run().then(undefined, onUnexpectedError);
}
@ -1077,6 +1085,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
this._closeBtn = this._register(new SimpleButton({
label: NLS_CLOSE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.CloseFindWidgetCommand),
icon: widgetClose,
hoverDelegate,
onTrigger: () => {
this._state.change({ isRevealed: false, searchScope: null }, false);
},
@ -1138,10 +1147,14 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
}
}));
// Create scoped hover delegate for replace actions
const replaceHoverDelegate = this._register(getDefaultHoverDelegate('element', true));
// Replace one button
this._replaceBtn = this._register(new SimpleButton({
label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction),
icon: findReplaceIcon,
hoverDelegate: replaceHoverDelegate,
onTrigger: () => {
this._controller.replace();
},
@ -1157,6 +1170,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
this._replaceAllBtn = this._register(new SimpleButton({
label: NLS_REPLACE_ALL_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceAllAction),
icon: findReplaceAllIcon,
hoverDelegate: replaceHoverDelegate,
onTrigger: () => {
this._controller.replaceAll();
}
@ -1299,6 +1313,7 @@ export interface ISimpleButtonOpts {
readonly label: string;
readonly className?: string;
readonly icon?: ThemeIcon;
readonly hoverDelegate?: IHoverDelegate;
readonly onTrigger: () => void;
readonly onKeyDown?: (e: IKeyboardEvent) => void;
}
@ -1321,11 +1336,11 @@ export class SimpleButton extends Widget {
}
this._domNode = document.createElement('div');
this._domNode.title = this._opts.label;
this._domNode.tabIndex = 0;
this._domNode.className = className;
this._domNode.setAttribute('role', 'button');
this._domNode.setAttribute('aria-label', this._opts.label);
this._register(setupCustomHover(opts.hoverDelegate ?? getDefaultHoverDelegate('element'), this._domNode, this._opts.label));
this.onclick(this._domNode, (e) => {
this._opts.onTrigger();

View file

@ -19,6 +19,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { defaultToggleStyles } from 'vs/platform/theme/browser/defaultStyles';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
export interface IOptions {
placeholder?: string;
@ -219,6 +220,7 @@ export class IncludePatternInputWidget extends PatternInputWidget {
icon: Codicon.book,
title: nls.localize('onlySearchInOpenEditors', "Search only in Open Editors"),
isChecked: false,
hoverDelegate: getDefaultHoverDelegate('element'),
...defaultToggleStyles
}));
this._register(this.useSearchInEditorsBox.onChange(viaKeyboard => {
@ -271,6 +273,7 @@ export class ExcludePatternInputWidget extends PatternInputWidget {
actionClassName: 'useExcludesAndIgnoreFiles',
title: nls.localize('useExcludesAndIgnoreFilesDescription', "Use Exclude Settings and Ignore Files"),
isChecked: true,
hoverDelegate: getDefaultHoverDelegate('element'),
...defaultToggleStyles
}));
this._register(this.useExcludesAndIgnoreFilesBox.onChange(viaKeyboard => {

View file

@ -30,6 +30,8 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { defaultCountBadgeStyles } from 'vs/platform/theme/browser/defaultStyles';
import { SearchContext } from 'vs/workbench/contrib/search/common/constants';
import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
interface IFolderMatchTemplate {
label: IResourceLabel;
@ -360,7 +362,9 @@ export class MatchRenderer extends Disposable implements ICompressibleTreeRender
templateData.match.classList.toggle('replace', replace);
templateData.replace.textContent = replace ? match.replaceString : '';
templateData.after.textContent = preview.after;
templateData.parent.title = (preview.fullBefore + (replace ? match.replaceString : preview.inside) + preview.after).trim().substr(0, 999);
const title = (preview.fullBefore + (replace ? match.replaceString : preview.inside) + preview.after).trim().substr(0, 999);
templateData.disposables.add(setupCustomHover(getDefaultHoverDelegate('mouse'), templateData.parent, title));
SearchContext.IsEditableItemKey.bindTo(templateData.contextKeyService).set(!(match instanceof MatchInNotebook && match.isReadonly()));
@ -372,7 +376,7 @@ export class MatchRenderer extends Disposable implements ICompressibleTreeRender
templateData.lineNumber.classList.toggle('show', (numLines > 0) || showLineNumbers);
templateData.lineNumber.textContent = lineNumberStr + extraLinesStr;
templateData.lineNumber.setAttribute('title', this.getMatchTitle(match, showLineNumbers));
templateData.disposables.add(setupCustomHover(getDefaultHoverDelegate('mouse'), templateData.lineNumber, this.getMatchTitle(match, showLineNumbers)));
templateData.actions.context = <ISearchActionContext>{ viewer: this.searchView.getControl(), element: match };

View file

@ -81,6 +81,8 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ILogService } from 'vs/platform/log/common/log';
import { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';
import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
const $ = dom.$;
@ -405,7 +407,8 @@ export class SearchView extends ViewPane {
// Toggle query details button
this.toggleQueryDetailsButton = dom.append(this.queryDetails,
$('.more' + ThemeIcon.asCSSSelector(searchDetailsIcon), { tabindex: 0, role: 'button', title: nls.localize('moreSearch', "Toggle Search Details") }));
$('.more' + ThemeIcon.asCSSSelector(searchDetailsIcon), { tabindex: 0, role: 'button' }));
this._register(setupCustomHover(getDefaultHoverDelegate('element'), this.toggleQueryDetailsButton, nls.localize('moreSearch', "Toggle Search Details")));
this._register(dom.addDisposableListener(this.toggleQueryDetailsButton, dom.EventType.CLICK, e => {
dom.EventHelper.stop(e);
@ -2133,7 +2136,8 @@ class SearchLinkButton extends Disposable {
constructor(label: string, handler: (e: dom.EventLike) => unknown, tooltip?: string) {
super();
this.element = $('a.pointer', { tabindex: 0, title: tooltip }, label);
this.element = $('a.pointer', { tabindex: 0 }, label);
this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.element, tooltip));
this.addEventHandlers(handler);
}

View file

@ -42,6 +42,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { GroupModelChangeKind } from 'vs/workbench/common/editor';
import { SearchFindInput } from 'vs/workbench/contrib/search/browser/searchFindInput';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
/** Specified in searchview.css */
const SingleLineInputHeight = 26;
@ -370,7 +371,9 @@ export class SearchWidget extends Widget {
buttonSecondaryBackground: undefined,
buttonSecondaryForeground: undefined,
buttonSecondaryHoverBackground: undefined,
buttonSeparator: undefined
buttonSeparator: undefined,
title: nls.localize('search.replace.toggle.button.title', "Toggle Replace"),
hoverDelegate: getDefaultHoverDelegate('element'),
};
this.toggleReplaceButton = this._register(new Button(parent, opts));
this.toggleReplaceButton.element.setAttribute('aria-expanded', 'false');
@ -378,7 +381,6 @@ export class SearchWidget extends Widget {
this.toggleReplaceButton.icon = searchHideReplaceIcon;
// TODO@joao need to dispose this listener eventually
this.toggleReplaceButton.onDidClick(() => this.onToggleReplaceButton());
this.toggleReplaceButton.element.title = nls.localize('search.replace.toggle.button.title', "Toggle Replace");
}
private renderSearchInput(parent: HTMLElement, options: ISearchWidgetOptions): void {
@ -441,6 +443,7 @@ export class SearchWidget extends Widget {
isChecked: false,
title: appendKeyBindingLabel(nls.localize('showContext', "Toggle Context Lines"), this.keybindingService.lookupKeybinding(ToggleSearchEditorContextLinesCommandId)),
icon: searchShowContextIcon,
hoverDelegate: getDefaultHoverDelegate('element'),
...defaultToggleStyles
});
this._register(this.showContextToggle.onChange(() => this.onContextLinesChanged()));

View file

@ -62,6 +62,8 @@ import { UnusualLineTerminatorsDetector } from 'vs/editor/contrib/unusualLineTer
import { defaultToggleStyles, getInputBoxStyle } from 'vs/platform/theme/browser/defaultStyles';
import { ILogService } from 'vs/platform/log/common/log';
import { SearchContext } from 'vs/workbench/contrib/search/common/constants';
import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
const RESULT_LINE_REGEX = /^(\s+)(\d+)(: | )(\s*)(.*)$/;
const FILE_LINE_REGEX = /^(\S.*):$/;
@ -161,7 +163,8 @@ export class SearchEditor extends AbstractTextCodeEditor<SearchEditorViewState>
this.includesExcludesContainer = DOM.append(container, DOM.$('.includes-excludes'));
// Toggle query details button
this.toggleQueryDetailsButton = DOM.append(this.includesExcludesContainer, DOM.$('.expand' + ThemeIcon.asCSSSelector(searchDetailsIcon), { tabindex: 0, role: 'button', title: localize('moreSearch', "Toggle Search Details") }));
this.toggleQueryDetailsButton = DOM.append(this.includesExcludesContainer, DOM.$('.expand' + ThemeIcon.asCSSSelector(searchDetailsIcon), { tabindex: 0, role: 'button' }));
this._register(setupCustomHover(getDefaultHoverDelegate('element'), this.toggleQueryDetailsButton, localize('moreSearch', "Toggle Search Details")));
this._register(DOM.addDisposableListener(this.toggleQueryDetailsButton, DOM.EventType.CLICK, e => {
DOM.EventHelper.stop(e);
this.toggleIncludesExcludes();