Skip to content

Commit 797ab73

Browse files
committed
1 parent 86fa120 commit 797ab73

4 files changed

Lines changed: 64 additions & 70 deletions

File tree

src/vs/base/browser/ui/findinput/replaceInput.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface IReplaceInputOptions extends IReplaceInputStyles {
3232

3333
export interface IReplaceInputStyles extends IInputBoxStyles {
3434
inputActiveOptionBorder?: Color;
35+
inputActiveOptionBackground?: Color;
3536
}
3637

3738
const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");
@@ -44,7 +45,8 @@ export class PreserveCaseCheckbox extends Checkbox {
4445
actionClassName: 'codicon-preserve-case',
4546
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
4647
isChecked: opts.isChecked,
47-
inputActiveOptionBorder: opts.inputActiveOptionBorder
48+
inputActiveOptionBorder: opts.inputActiveOptionBorder,
49+
inputActiveOptionBackground: opts.inputActiveOptionBackground
4850
});
4951
}
5052
}
@@ -60,6 +62,7 @@ export class ReplaceInput extends Widget {
6062
private fixFocusOnOptionClickEnabled = true;
6163

6264
private inputActiveOptionBorder?: Color;
65+
private inputActiveOptionBackground?: Color;
6366
private inputBackground?: Color;
6467
private inputForeground?: Color;
6568
private inputBorder?: Color;
@@ -105,6 +108,7 @@ export class ReplaceInput extends Widget {
105108
this.label = options.label || NLS_DEFAULT_LABEL;
106109

107110
this.inputActiveOptionBorder = options.inputActiveOptionBorder;
111+
this.inputActiveOptionBackground = options.inputActiveOptionBackground;
108112
this.inputBackground = options.inputBackground;
109113
this.inputForeground = options.inputForeground;
110114
this.inputBorder = options.inputBorder;
@@ -181,6 +185,7 @@ export class ReplaceInput extends Widget {
181185

182186
public style(styles: IReplaceInputStyles): void {
183187
this.inputActiveOptionBorder = styles.inputActiveOptionBorder;
188+
this.inputActiveOptionBackground = styles.inputActiveOptionBackground;
184189
this.inputBackground = styles.inputBackground;
185190
this.inputForeground = styles.inputForeground;
186191
this.inputBorder = styles.inputBorder;
@@ -202,6 +207,7 @@ export class ReplaceInput extends Widget {
202207
if (this.domNode) {
203208
const checkBoxStyles: ICheckboxStyles = {
204209
inputActiveOptionBorder: this.inputActiveOptionBorder,
210+
inputActiveOptionBackground: this.inputActiveOptionBackground,
205211
};
206212
this.preserveCase.style(checkBoxStyles);
207213

@@ -281,7 +287,8 @@ export class ReplaceInput extends Widget {
281287
this.preserveCase = this._register(new PreserveCaseCheckbox({
282288
appendTitle: '',
283289
isChecked: false,
284-
inputActiveOptionBorder: this.inputActiveOptionBorder
290+
inputActiveOptionBorder: this.inputActiveOptionBorder,
291+
inputActiveOptionBackground: this.inputActiveOptionBackground,
285292
}));
286293
this._register(this.preserveCase.onChange(viaKeyboard => {
287294
this._onDidOptionChange.fire(viaKeyboard);

src/vs/platform/theme/common/styler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeSer
143143
} as ISelectBoxStyleOverrides, widget);
144144
}
145145

146-
export function attachFindInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable {
146+
export function attachFindReplaceInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable {
147147
return attachStyler(themeService, {
148148
inputBackground: (style && style.inputBackground) || inputBackground,
149149
inputForeground: (style && style.inputForeground) || inputForeground,

src/vs/workbench/contrib/search/browser/searchView.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export class SearchView extends ViewletPanel {
298298
this._register(this.viewModel.searchResult.onChange((event) => this.onSearchResultsChanged(event)));
299299

300300
this._register(this.searchWidget.searchInput.onInput(() => this.updateActions()));
301-
this._register(this.searchWidget.replaceInput.onDidChange(() => this.updateActions()));
301+
this._register(this.searchWidget.replaceInput.onInput(() => this.updateActions()));
302302

303303
this._register(this.onDidFocus(() => this.viewletFocused.set(true)));
304304
this._register(this.onDidBlur(() => this.viewletFocused.set(false)));
@@ -1048,10 +1048,10 @@ export class SearchView extends ViewletPanel {
10481048
this.searchWidget.searchInput.setValue(args.query);
10491049
}
10501050
if (typeof args.replace === 'string') {
1051-
this.searchWidget.replaceInput.value = args.replace;
1051+
this.searchWidget.replaceInput.setValue(args.replace);
10521052
} else {
1053-
if (this.searchWidget.replaceInput.value !== '') {
1054-
this.searchWidget.replaceInput.value = '';
1053+
if (this.searchWidget.replaceInput.getValue() !== '') {
1054+
this.searchWidget.replaceInput.setValue('');
10551055
}
10561056
}
10571057
if (typeof args.triggerSearch === 'boolean' && args.triggerSearch) {

src/vs/workbench/contrib/search/browser/searchWidget.ts

Lines changed: 50 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
88
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
99
import { Button, IButtonOptions } from 'vs/base/browser/ui/button/button';
1010
import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput';
11-
import { HistoryInputBox, IMessage } from 'vs/base/browser/ui/inputbox/inputBox';
11+
import { ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput';
12+
import { IMessage } from 'vs/base/browser/ui/inputbox/inputBox';
1213
import { Widget } from 'vs/base/browser/ui/widget';
1314
import { Action } from 'vs/base/common/actions';
1415
import { Delayer } from 'vs/base/common/async';
@@ -24,16 +25,15 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView
2425
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
2526
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
2627
import { ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search';
27-
import { attachFindInputBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
28+
import { attachFindReplaceInputBoxStyler } from 'vs/platform/theme/common/styler';
2829
import { IThemeService } from 'vs/platform/theme/common/themeService';
29-
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
30+
import { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/browser/contextScopedHistoryWidget';
3031
import { appendKeyBindingLabel, isSearchViewFocused } from 'vs/workbench/contrib/search/browser/searchActions';
3132
import * as Constants from 'vs/workbench/contrib/search/common/constants';
3233
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
3334
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
3435
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
3536
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
36-
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
3737
import { isMacintosh } from 'vs/base/common/platform';
3838

3939
export interface ISearchWidgetOptions {
@@ -79,6 +79,22 @@ class ReplaceAllAction extends Action {
7979

8080
const ctrlKeyMod = (isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd);
8181

82+
function stopPropagationForMultiLineUpwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {
83+
const isMultiline = !!value.match(/\n/);
84+
if (textarea && isMultiline && textarea.selectionStart > 0) {
85+
event.stopPropagation();
86+
return;
87+
}
88+
}
89+
90+
function stopPropagationForMultiLineDownwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {
91+
const isMultiline = !!value.match(/\n/);
92+
if (textarea && isMultiline && textarea.selectionEnd < textarea.value.length) {
93+
event.stopPropagation();
94+
return;
95+
}
96+
}
97+
8298
export class SearchWidget extends Widget {
8399

84100
private static readonly REPLACE_ALL_DISABLED_LABEL = nls.localize('search.action.replaceAll.disabled.label', "Replace All (Submit Search to Enable)");
@@ -94,15 +110,14 @@ export class SearchWidget extends Widget {
94110
private searchInputBoxFocused: IContextKey<boolean>;
95111

96112
private replaceContainer!: HTMLElement;
97-
replaceInput!: HistoryInputBox;
113+
replaceInput!: ReplaceInput;
114+
replaceInputFocusTracker!: dom.IFocusTracker;
115+
private replaceInputBoxFocused: IContextKey<boolean>;
98116
private toggleReplaceButton!: Button;
99117
private replaceAllAction!: ReplaceAllAction;
100118
private replaceActive: IContextKey<boolean>;
101119
private replaceActionBar!: ActionBar;
102-
replaceInputFocusTracker!: dom.IFocusTracker;
103-
private replaceInputBoxFocused: IContextKey<boolean>;
104120
private _replaceHistoryDelayer: Delayer<void>;
105-
private _preserveCase!: Checkbox;
106121

107122
private ignoreGlobalFindBufferOnNextFocus = false;
108123
private previousGlobalFindBufferValue: string | null = null;
@@ -180,12 +195,12 @@ export class SearchWidget extends Widget {
180195
setWidth(width: number) {
181196
this.searchInput.inputBox.layout();
182197
this.replaceInput.width = width - 28;
183-
this.replaceInput.layout();
198+
this.replaceInput.inputBox.layout();
184199
}
185200

186201
clear() {
187202
this.searchInput.clear();
188-
this.replaceInput.value = '';
203+
this.replaceInput.setValue('');
189204
this.setReplaceAllActionState(false);
190205
}
191206

@@ -198,7 +213,7 @@ export class SearchWidget extends Widget {
198213
}
199214

200215
getReplaceValue(): string {
201-
return this.replaceInput.value;
216+
return this.replaceInput.getValue();
202217
}
203218

204219
toggleReplace(show?: boolean): void {
@@ -212,7 +227,7 @@ export class SearchWidget extends Widget {
212227
}
213228

214229
getReplaceHistory(): string[] {
215-
return this.replaceInput.getHistory();
230+
return this.replaceInput.inputBox.getHistory();
216231
}
217232

218233
clearHistory(): void {
@@ -228,19 +243,19 @@ export class SearchWidget extends Widget {
228243
}
229244

230245
showNextReplaceTerm() {
231-
this.replaceInput.showNextValue();
246+
this.replaceInput.inputBox.showNextValue();
232247
}
233248

234249
showPreviousReplaceTerm() {
235-
this.replaceInput.showPreviousValue();
250+
this.replaceInput.inputBox.showPreviousValue();
236251
}
237252

238253
searchInputHasFocus(): boolean {
239254
return !!this.searchInputBoxFocused.get();
240255
}
241256

242257
replaceInputHasFocus(): boolean {
243-
return this.replaceInput.hasFocus();
258+
return this.replaceInput.inputBox.hasFocus();
244259
}
245260

246261
focusReplaceAllAction(): void {
@@ -301,7 +316,7 @@ export class SearchWidget extends Widget {
301316

302317
const searchInputContainer = dom.append(parent, dom.$('.search-container.input-box'));
303318
this.searchInput = this._register(new ContextScopedFindInput(searchInputContainer, this.contextViewService, inputOptions, this.contextKeyService, true));
304-
this._register(attachFindInputBoxStyler(this.searchInput, this.themeService));
319+
this._register(attachFindReplaceInputBoxStyler(this.searchInput, this.themeService));
305320
this.searchInput.onKeyDown((keyboardEvent: IKeyboardEvent) => this.onSearchInputKeyDown(keyboardEvent));
306321
this.searchInput.setValue(options.value || '');
307322
this.searchInput.setRegex(!!options.isRegex);
@@ -316,7 +331,7 @@ export class SearchWidget extends Widget {
316331
this._register(this.searchInput.inputBox.onDidHeightChange(() => this._onDidHeightChange.fire()));
317332

318333
this._register(this.onReplaceValueChanged(() => {
319-
this._replaceHistoryDelayer.trigger(() => this.replaceInput.addToHistory());
334+
this._replaceHistoryDelayer.trigger(() => this.replaceInput.inputBox.addToHistory());
320335
}));
321336

322337
this.searchInputFocusTracker = this._register(dom.trackFocus(this.searchInput.inputBox.inputElement));
@@ -344,38 +359,24 @@ export class SearchWidget extends Widget {
344359
this.replaceContainer = dom.append(parent, dom.$('.replace-container.disabled'));
345360
const replaceBox = dom.append(this.replaceContainer, dom.$('.replace-input'));
346361

347-
this.replaceInput = this._register(new ContextScopedHistoryInputBox(replaceBox, this.contextViewService, {
348-
ariaLabel: nls.localize('label.Replace', 'Replace: Type replace term and press Enter to preview or Escape to cancel'),
362+
this.replaceInput = this._register(new ContextScopedReplaceInput(replaceBox, this.contextViewService, {
363+
label: nls.localize('label.Replace', 'Replace: Type replace term and press Enter to preview or Escape to cancel'),
349364
placeholder: nls.localize('search.replace.placeHolder', "Replace"),
350-
history: options.replaceHistory || [],
365+
history: options.replaceHistory,
351366
flexibleHeight: true
352-
}, this.contextKeyService));
367+
}, this.contextKeyService, true));
353368

354-
this._preserveCase = this._register(new Checkbox({
355-
actionClassName: 'monaco-preserve-case',
356-
title: nls.localize('label.preserveCaseCheckbox', "Preserve Case"),
357-
isChecked: !!options.preserveCase,
358-
}));
359-
360-
this._register(this._preserveCase.onChange(viaKeyboard => {
369+
this._register(this.replaceInput.onDidOptionChange(viaKeyboard => {
361370
if (!viaKeyboard) {
362-
this.replaceInput.focus();
363-
this._onPreserveCaseChange.fire(this._preserveCase.checked);
371+
this._onPreserveCaseChange.fire(this.replaceInput.getPreserveCase());
364372
}
365373
}));
366374

367-
const controls = document.createElement('div');
368-
controls.className = 'controls';
369-
controls.style.display = 'block';
370-
controls.appendChild(this._preserveCase.domNode);
371-
replaceBox.appendChild(controls);
372-
this.replaceInput.paddingRight = this._preserveCase.width();
373-
374-
this._register(attachInputBoxStyler(this.replaceInput, this.themeService));
375-
this.onkeydown(this.replaceInput.inputElement, (keyboardEvent) => this.onReplaceInputKeyDown(keyboardEvent));
376-
this.replaceInput.value = options.replaceValue || '';
377-
this._register(this.replaceInput.onDidChange(() => this._onReplaceValueChanged.fire()));
378-
this._register(this.replaceInput.onDidHeightChange(() => this._onDidHeightChange.fire()));
375+
this._register(attachFindReplaceInputBoxStyler(this.replaceInput, this.themeService));
376+
this.replaceInput.onKeyDown((keyboardEvent) => this.onReplaceInputKeyDown(keyboardEvent));
377+
this.replaceInput.setValue(options.replaceValue || '');
378+
this._register(this.replaceInput.inputBox.onDidChange(() => this._onReplaceValueChanged.fire()));
379+
this._register(this.replaceInput.inputBox.onDidHeightChange(() => this._onDidHeightChange.fire()));
379380

380381
this.replaceAllAction = ReplaceAllAction.INSTANCE;
381382
this.replaceAllAction.searchWidget = this;
@@ -384,7 +385,7 @@ export class SearchWidget extends Widget {
384385
this.replaceActionBar.push([this.replaceAllAction], { icon: true, label: false });
385386
this.onkeydown(this.replaceActionBar.domNode, (keyboardEvent) => this.onReplaceActionbarKeyDown(keyboardEvent));
386387

387-
this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputElement));
388+
this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputBox.inputElement));
388389
this._register(this.replaceInputFocusTracker.onDidFocus(() => this.replaceInputBoxFocused.set(true)));
389390
this._register(this.replaceInputFocusTracker.onDidBlur(() => this.replaceInputBoxFocused.set(false)));
390391
}
@@ -417,7 +418,7 @@ export class SearchWidget extends Widget {
417418
if (currentState !== newState) {
418419
this.replaceActive.set(newState);
419420
this._onReplaceStateChange.fire(newState);
420-
this.replaceInput.layout();
421+
this.replaceInput.inputBox.layout();
421422
}
422423
}
423424

@@ -475,19 +476,11 @@ export class SearchWidget extends Widget {
475476
}
476477

477478
else if (keyboardEvent.equals(KeyCode.UpArrow)) {
478-
const ta = this.searchInput.domNode.querySelector('textarea');
479-
const isMultiline = !!this.searchInput.getValue().match(/\n/);
480-
if (ta && isMultiline && ta.selectionStart > 0) {
481-
keyboardEvent.stopPropagation();
482-
}
479+
stopPropagationForMultiLineUpwards(keyboardEvent, this.searchInput.getValue(), this.searchInput.domNode.querySelector('textarea'));
483480
}
484481

485482
else if (keyboardEvent.equals(KeyCode.DownArrow)) {
486-
const ta = this.searchInput.domNode.querySelector('textarea');
487-
const isMultiline = !!this.searchInput.getValue().match(/\n/);
488-
if (ta && isMultiline && ta.selectionEnd < ta.value.length) {
489-
keyboardEvent.stopPropagation();
490-
}
483+
stopPropagationForMultiLineDownwards(keyboardEvent, this.searchInput.getValue(), this.searchInput.domNode.querySelector('textarea'));
491484
}
492485
}
493486

@@ -513,7 +506,7 @@ export class SearchWidget extends Widget {
513506

514507
private onReplaceInputKeyDown(keyboardEvent: IKeyboardEvent) {
515508
if (keyboardEvent.equals(ctrlKeyMod | KeyCode.Enter)) {
516-
this.searchInput.inputBox.insertAtCursor('\n');
509+
this.replaceInput.inputBox.insertAtCursor('\n');
517510
keyboardEvent.preventDefault();
518511
}
519512

@@ -533,17 +526,11 @@ export class SearchWidget extends Widget {
533526
}
534527

535528
else if (keyboardEvent.equals(KeyCode.UpArrow)) {
536-
const ta = this.searchInput.domNode.querySelector('textarea');
537-
if (ta && ta.selectionStart > 0) {
538-
keyboardEvent.stopPropagation();
539-
}
529+
stopPropagationForMultiLineUpwards(keyboardEvent, this.replaceInput.getValue(), this.replaceInput.domNode.querySelector('textarea'));
540530
}
541531

542532
else if (keyboardEvent.equals(KeyCode.DownArrow)) {
543-
const ta = this.searchInput.domNode.querySelector('textarea');
544-
if (ta && ta.selectionEnd < ta.value.length) {
545-
keyboardEvent.stopPropagation();
546-
}
533+
stopPropagationForMultiLineDownwards(keyboardEvent, this.replaceInput.getValue(), this.replaceInput.domNode.querySelector('textarea'));
547534
}
548535
}
549536

0 commit comments

Comments
 (0)