mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-31 09:10:30 -04:00
Merge from vscode 6e530127a1bb8ffbd1bfb77dc680c321dc0d71f5 (#6844)
This commit is contained in:
@@ -60,6 +60,20 @@
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.search-view .search-widget .replace-input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
vertical-align: middle;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
.search-view .search-widget .replace-input > .controls {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.search-view .search-widget .replace-container.disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,11 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { INavigator } from 'vs/base/common/iterator';
|
||||
import { createKeybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
import { isWindows, OS } from 'vs/base/common/platform';
|
||||
import { repeat } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -667,14 +664,11 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction {
|
||||
}
|
||||
}
|
||||
|
||||
function uriToClipboardString(resource: URI): string {
|
||||
return resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(resource.fsPath)) : resource.toString();
|
||||
}
|
||||
|
||||
export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatch) => {
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
const labelService = accessor.get(ILabelService);
|
||||
|
||||
const text = uriToClipboardString(fileMatch.resource);
|
||||
const text = labelService.getUriLabel(fileMatch.resource, { noPrefix: true });
|
||||
await clipboardService.writeText(text);
|
||||
};
|
||||
|
||||
@@ -706,25 +700,26 @@ function matchToString(match: Match, indent = 0): string {
|
||||
}
|
||||
|
||||
const lineDelimiter = isWindows ? '\r\n' : '\n';
|
||||
function fileMatchToString(fileMatch: FileMatch, maxMatches: number): { text: string, count: number } {
|
||||
function fileMatchToString(fileMatch: FileMatch, maxMatches: number, labelService: ILabelService): { text: string, count: number } {
|
||||
const matchTextRows = fileMatch.matches()
|
||||
.sort(searchMatchComparer)
|
||||
.slice(0, maxMatches)
|
||||
.map(match => matchToString(match, 2));
|
||||
const uriString = labelService.getUriLabel(fileMatch.resource, { noPrefix: true });
|
||||
return {
|
||||
text: `${uriToClipboardString(fileMatch.resource)}${lineDelimiter}${matchTextRows.join(lineDelimiter)}`,
|
||||
text: `${uriString}${lineDelimiter}${matchTextRows.join(lineDelimiter)}`,
|
||||
count: matchTextRows.length
|
||||
};
|
||||
}
|
||||
|
||||
function folderMatchToString(folderMatch: FolderMatch | BaseFolderMatch, maxMatches: number): { text: string, count: number } {
|
||||
function folderMatchToString(folderMatch: FolderMatch | BaseFolderMatch, maxMatches: number, labelService: ILabelService): { text: string, count: number } {
|
||||
const fileResults: string[] = [];
|
||||
let numMatches = 0;
|
||||
|
||||
const matches = folderMatch.matches().sort(searchMatchComparer);
|
||||
|
||||
for (let i = 0; i < folderMatch.fileCount() && numMatches < maxMatches; i++) {
|
||||
const fileResult = fileMatchToString(matches[i], maxMatches - numMatches);
|
||||
const fileResult = fileMatchToString(matches[i], maxMatches - numMatches, labelService);
|
||||
numMatches += fileResult.count;
|
||||
fileResults.push(fileResult.text);
|
||||
}
|
||||
@@ -738,14 +733,15 @@ function folderMatchToString(folderMatch: FolderMatch | BaseFolderMatch, maxMatc
|
||||
const maxClipboardMatches = 1e4;
|
||||
export const copyMatchCommand: ICommandHandler = async (accessor, match: RenderableMatch) => {
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
const labelService = accessor.get(ILabelService);
|
||||
|
||||
let text: string | undefined;
|
||||
if (match instanceof Match) {
|
||||
text = matchToString(match);
|
||||
} else if (match instanceof FileMatch) {
|
||||
text = fileMatchToString(match, maxClipboardMatches).text;
|
||||
text = fileMatchToString(match, maxClipboardMatches, labelService).text;
|
||||
} else if (match instanceof BaseFolderMatch) {
|
||||
text = folderMatchToString(match, maxClipboardMatches).text;
|
||||
text = folderMatchToString(match, maxClipboardMatches, labelService).text;
|
||||
}
|
||||
|
||||
if (text) {
|
||||
@@ -753,12 +749,12 @@ export const copyMatchCommand: ICommandHandler = async (accessor, match: Rendera
|
||||
}
|
||||
};
|
||||
|
||||
function allFolderMatchesToString(folderMatches: Array<FolderMatch | BaseFolderMatch>, maxMatches: number): string {
|
||||
function allFolderMatchesToString(folderMatches: Array<FolderMatch | BaseFolderMatch>, maxMatches: number, labelService: ILabelService): string {
|
||||
const folderResults: string[] = [];
|
||||
let numMatches = 0;
|
||||
folderMatches = folderMatches.sort(searchMatchComparer);
|
||||
for (let i = 0; i < folderMatches.length && numMatches < maxMatches; i++) {
|
||||
const folderResult = folderMatchToString(folderMatches[i], maxMatches - numMatches);
|
||||
const folderResult = folderMatchToString(folderMatches[i], maxMatches - numMatches, labelService);
|
||||
if (folderResult.count) {
|
||||
numMatches += folderResult.count;
|
||||
folderResults.push(folderResult.text);
|
||||
@@ -772,12 +768,13 @@ export const copyAllCommand: ICommandHandler = async (accessor) => {
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
const panelService = accessor.get(IPanelService);
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
const labelService = accessor.get(ILabelService);
|
||||
|
||||
const searchView = getSearchView(viewletService, panelService);
|
||||
if (searchView) {
|
||||
const root = searchView.searchResult;
|
||||
|
||||
const text = allFolderMatchesToString(root.folderMatches(), maxClipboardMatches);
|
||||
const text = allFolderMatchesToString(root.folderMatches(), maxClipboardMatches, labelService);
|
||||
await clipboardService.writeText(text);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,6 +61,7 @@ import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/v
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { Memento, MementoObject } from 'vs/workbench/common/memento';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -153,6 +154,7 @@ export class SearchView extends ViewletPanel {
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IOpenerService private readonly openerService: IOpenerService
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), id: VIEW_ID, ariaHeaderLabel: nls.localize('searchView', "Search") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
|
||||
@@ -364,6 +366,7 @@ export class SearchView extends ViewletPanel {
|
||||
const searchHistory = history.search || this.viewletState['query.searchHistory'] || [];
|
||||
const replaceHistory = history.replace || this.viewletState['query.replaceHistory'] || [];
|
||||
const showReplace = typeof this.viewletState['view.showReplace'] === 'boolean' ? this.viewletState['view.showReplace'] : true;
|
||||
const preserveCase = this.viewletState['query.preserveCase'] === true;
|
||||
|
||||
this.searchWidget = this._register(this.instantiationService.createInstance(SearchWidget, container, <ISearchWidgetOptions>{
|
||||
value: contentPattern,
|
||||
@@ -372,7 +375,8 @@ export class SearchView extends ViewletPanel {
|
||||
isCaseSensitive: isCaseSensitive,
|
||||
isWholeWords: isWholeWords,
|
||||
searchHistory: searchHistory,
|
||||
replaceHistory: replaceHistory
|
||||
replaceHistory: replaceHistory,
|
||||
preserveCase: preserveCase
|
||||
}));
|
||||
|
||||
if (showReplace) {
|
||||
@@ -390,6 +394,12 @@ export class SearchView extends ViewletPanel {
|
||||
this.viewModel.replaceActive = state;
|
||||
this.refreshTree();
|
||||
}));
|
||||
|
||||
this._register(this.searchWidget.onPreserveCaseChange((state) => {
|
||||
this.viewModel.preserveCase = state;
|
||||
this.refreshTree();
|
||||
}));
|
||||
|
||||
this._register(this.searchWidget.onReplaceValueChanged((value) => {
|
||||
this.viewModel.replaceString = this.searchWidget.getReplaceValue();
|
||||
this.delayedRefresh.trigger(() => this.refreshTree());
|
||||
@@ -1465,7 +1475,7 @@ export class SearchView extends ViewletPanel {
|
||||
private onLearnMore = (e: MouseEvent): void => {
|
||||
dom.EventHelper.stop(e, false);
|
||||
|
||||
window.open('https://go.microsoft.com/fwlink/?linkid=853977');
|
||||
this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=853977'));
|
||||
}
|
||||
|
||||
private updateSearchResultCount(disregardExcludesAndIgnores?: boolean): void {
|
||||
@@ -1641,6 +1651,7 @@ export class SearchView extends ViewletPanel {
|
||||
const patternExcludes = this.inputPatternExcludes.getValue().trim();
|
||||
const patternIncludes = this.inputPatternIncludes.getValue().trim();
|
||||
const useExcludesAndIgnoreFiles = this.inputPatternExcludes.useExcludesAndIgnoreFiles();
|
||||
const preserveCase = this.viewModel.preserveCase;
|
||||
|
||||
this.viewletState['query.contentPattern'] = contentPattern;
|
||||
this.viewletState['query.regex'] = isRegex;
|
||||
@@ -1649,6 +1660,7 @@ export class SearchView extends ViewletPanel {
|
||||
this.viewletState['query.folderExclusions'] = patternExcludes;
|
||||
this.viewletState['query.folderIncludes'] = patternIncludes;
|
||||
this.viewletState['query.useExcludesAndIgnoreFiles'] = useExcludesAndIgnoreFiles;
|
||||
this.viewletState['query.preserveCase'] = preserveCase;
|
||||
|
||||
const isReplaceShown = this.searchAndReplaceWidget.isReplaceShown();
|
||||
this.viewletState['view.showReplace'] = isReplaceShown;
|
||||
|
||||
@@ -33,6 +33,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
|
||||
export interface ISearchWidgetOptions {
|
||||
value?: string;
|
||||
@@ -42,6 +43,7 @@ export interface ISearchWidgetOptions {
|
||||
isWholeWords?: boolean;
|
||||
searchHistory?: string[];
|
||||
replaceHistory?: string[];
|
||||
preserveCase?: boolean;
|
||||
}
|
||||
|
||||
class ReplaceAllAction extends Action {
|
||||
@@ -97,6 +99,7 @@ export class SearchWidget extends Widget {
|
||||
replaceInputFocusTracker: dom.IFocusTracker;
|
||||
private replaceInputBoxFocused: IContextKey<boolean>;
|
||||
private _replaceHistoryDelayer: Delayer<void>;
|
||||
private _preserveCase: Checkbox;
|
||||
|
||||
private ignoreGlobalFindBufferOnNextFocus = false;
|
||||
private previousGlobalFindBufferValue: string;
|
||||
@@ -113,6 +116,9 @@ export class SearchWidget extends Widget {
|
||||
private _onReplaceStateChange = this._register(new Emitter<boolean>());
|
||||
readonly onReplaceStateChange: Event<boolean> = this._onReplaceStateChange.event;
|
||||
|
||||
private _onPreserveCaseChange = this._register(new Emitter<boolean>());
|
||||
readonly onPreserveCaseChange: Event<boolean> = this._onPreserveCaseChange.event;
|
||||
|
||||
private _onReplaceValueChanged = this._register(new Emitter<void>());
|
||||
readonly onReplaceValueChanged: Event<void> = this._onReplaceValueChanged.event;
|
||||
|
||||
@@ -333,13 +339,34 @@ export class SearchWidget extends Widget {
|
||||
|
||||
private renderReplaceInput(parent: HTMLElement, options: ISearchWidgetOptions): void {
|
||||
this.replaceContainer = dom.append(parent, dom.$('.replace-container.disabled'));
|
||||
const replaceBox = dom.append(this.replaceContainer, dom.$('.input-box'));
|
||||
const replaceBox = dom.append(this.replaceContainer, dom.$('.replace-input'));
|
||||
|
||||
this.replaceInput = this._register(new ContextScopedHistoryInputBox(replaceBox, this.contextViewService, {
|
||||
ariaLabel: nls.localize('label.Replace', 'Replace: Type replace term and press Enter to preview or Escape to cancel'),
|
||||
placeholder: nls.localize('search.replace.placeHolder', "Replace"),
|
||||
history: options.replaceHistory || [],
|
||||
flexibleHeight: true
|
||||
}, this.contextKeyService));
|
||||
|
||||
this._preserveCase = this._register(new Checkbox({
|
||||
actionClassName: 'monaco-preserve-case',
|
||||
title: nls.localize('label.preserveCaseCheckbox', "Preserve Case"),
|
||||
isChecked: !!options.preserveCase,
|
||||
}));
|
||||
|
||||
this._register(this._preserveCase.onChange(viaKeyboard => {
|
||||
if (!viaKeyboard) {
|
||||
this.replaceInput.focus();
|
||||
this._onPreserveCaseChange.fire(this._preserveCase.checked);
|
||||
}
|
||||
}));
|
||||
|
||||
let controls = document.createElement('div');
|
||||
controls.className = 'controls';
|
||||
controls.style.display = 'block';
|
||||
controls.appendChild(this._preserveCase.domNode);
|
||||
replaceBox.appendChild(controls);
|
||||
|
||||
this._register(attachInputBoxStyler(this.replaceInput, this.themeService));
|
||||
this.onkeydown(this.replaceInput.inputElement, (keyboardEvent) => this.onReplaceInputKeyDown(keyboardEvent));
|
||||
this.replaceInput.value = options.replaceValue || '';
|
||||
|
||||
Reference in New Issue
Block a user