Merge from vscode 6e530127a1bb8ffbd1bfb77dc680c321dc0d71f5 (#6844)

This commit is contained in:
Anthony Dresser
2019-08-20 21:07:47 -07:00
committed by GitHub
parent 1f00249646
commit ecb80f14f0
221 changed files with 3140 additions and 1552 deletions

View File

@@ -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;
}

View File

@@ -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);
}
};

View File

@@ -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;

View File

@@ -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 || '';