This commit is contained in:
Jackson Kearl
2020-02-21 14:24:09 -08:00
parent 50e742c42e
commit b77192b4a7
5 changed files with 44 additions and 30 deletions
@@ -34,7 +34,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { TreeResourceNavigator, WorkbenchObjectTree, getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IProgressService, IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ITextQuery, VIEW_ID, SearchSortOrder } from 'vs/workbench/services/search/common/search';
import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ITextQuery, VIEW_ID, SearchSortOrder, SearchCompletionExitCode } from 'vs/workbench/services/search/common/search';
import { ISearchHistoryService, ISearchHistoryValues } from 'vs/workbench/contrib/search/common/searchHistoryService';
import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, listActiveSelectionForeground, foreground } from 'vs/platform/theme/common/colorRegistry';
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
@@ -1348,7 +1348,7 @@ export class SearchView extends ViewPane {
this.inputPatternIncludes.onSearchSubmit();
});
this.viewModel.cancelSearch();
this.viewModel.cancelSearch(true);
this.currentSearchQ = this.currentSearchQ
.then(() => this.doSearch(query, excludePatternText, includePatternText, triggeredOnType))
@@ -1393,6 +1393,10 @@ export class SearchView extends ViewPane {
this.updateActions();
const hasResults = !this.viewModel.searchResult.isEmpty();
if (completed?.exit === SearchCompletionExitCode.NewSearchStarted) {
return;
}
if (completed && completed.limitHit) {
this.searchWidget.searchInput.showMessage({
content: nls.localize('searchMaxResultsWarning', "The result set only contains a subset of all matches. Please be more specific in your search to narrow down the results."),
@@ -154,7 +154,6 @@ export class SearchWidget extends Widget {
private readonly _onDidToggleContext = new Emitter<void>();
readonly onDidToggleContext: Event<void> = this._onDidToggleContext.event;
private temporarilySkipSearchOnChange = false;
private showContextCheckbox!: Checkbox;
private contextLinesInput!: InputBox;
@@ -488,12 +487,10 @@ export class SearchWidget extends Widget {
this.setReplaceAllActionState(false);
if (this.searchConfiguration.searchOnType) {
if (!this.temporarilySkipSearchOnChange) {
this._onSearchCancel.fire({ focus: false });
if (this.searchInput.getRegex()) {
try {
const regex = new RegExp(this.searchInput.getValue(), 'ug');
const matchienessHeuristic = `
if (this.searchInput.getRegex()) {
try {
const regex = new RegExp(this.searchInput.getValue(), 'ug');
const matchienessHeuristic = `
~!@#$%^&*()_+
\`1234567890-=
qwertyuiop[]\\
@@ -503,18 +500,17 @@ export class SearchWidget extends Widget {
zxcvbnm,./
ZXCVBNM<>? `.match(regex)?.length ?? 0;
const delayMultiplier =
matchienessHeuristic < 50 ? 1 :
matchienessHeuristic < 100 ? 5 : // expressions like `.` or `\w`
10; // only things matching empty string
const delayMultiplier =
matchienessHeuristic < 50 ? 1 :
matchienessHeuristic < 100 ? 5 : // expressions like `.` or `\w`
10; // only things matching empty string
this.submitSearch(true, this.searchConfiguration.searchOnTypeDebouncePeriod * delayMultiplier);
} catch {
// pass
}
} else {
this.submitSearch(true, this.searchConfiguration.searchOnTypeDebouncePeriod);
this.submitSearch(true, this.searchConfiguration.searchOnTypeDebouncePeriod * delayMultiplier);
} catch {
// pass
}
} else {
this.submitSearch(true, this.searchConfiguration.searchOnTypeDebouncePeriod);
}
}
}
@@ -20,7 +20,7 @@ import { IModelService } from 'vs/editor/common/services/modelService';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';
import { ReplacePattern } from 'vs/workbench/services/search/common/replace';
import { IFileMatch, IPatternInfo, ISearchComplete, ISearchProgressItem, ISearchConfigurationProperties, ISearchService, ITextQuery, ITextSearchPreviewOptions, ITextSearchMatch, ITextSearchStats, resultIsMatch, ISearchRange, OneLineRange, ITextSearchContext, ITextSearchResult, SearchSortOrder } from 'vs/workbench/services/search/common/search';
import { IFileMatch, IPatternInfo, ISearchComplete, ISearchProgressItem, ISearchConfigurationProperties, ISearchService, ITextQuery, ITextSearchPreviewOptions, ITextSearchMatch, ITextSearchStats, resultIsMatch, ISearchRange, OneLineRange, ITextSearchContext, ITextSearchResult, SearchSortOrder, SearchCompletionExitCode } from 'vs/workbench/services/search/common/search';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { overviewRulerFindMatchForeground, minimapFindMatch } from 'vs/platform/theme/common/colorRegistry';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
@@ -968,6 +968,7 @@ export class SearchModel extends Disposable {
readonly onReplaceTermChanged: Event<void> = this._onReplaceTermChanged.event;
private currentCancelTokenSource: CancellationTokenSource | null = null;
private searchCancelledForNewSearch: boolean = false;
constructor(
@ISearchService private readonly searchService: ISearchService,
@@ -1016,7 +1017,7 @@ export class SearchModel extends Disposable {
}
search(query: ITextQuery, onProgress?: (result: ISearchProgressItem) => void): Promise<ISearchComplete> {
this.cancelSearch();
this.cancelSearch(true);
this._searchQuery = query;
@@ -1114,7 +1115,12 @@ export class SearchModel extends Disposable {
private onSearchError(e: any, duration: number): void {
if (errors.isPromiseCanceledError(e)) {
this.onSearchCompleted(null, duration);
this.onSearchCompleted(
this.searchCancelledForNewSearch
? { exit: SearchCompletionExitCode.NewSearchStarted, results: [] }
: null,
duration);
this.searchCancelledForNewSearch = false;
}
}
@@ -1133,8 +1139,9 @@ export class SearchModel extends Disposable {
return this.configurationService.getValue<ISearchConfigurationProperties>('search');
}
cancelSearch(): boolean {
cancelSearch(cancelledForNewSearch = false): boolean {
if (this.currentCancelTokenSource) {
this.searchCancelledForNewSearch = cancelledForNewSearch;
this.currentCancelTokenSource.cancel();
return true;
}
@@ -77,6 +77,7 @@ export class SearchEditor extends BaseTextEditor {
private searchHistoryDelayer: Delayer<void>;
private messageDisposables: IDisposable[] = [];
private container: HTMLElement;
private searchModel: SearchModel;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@@ -107,6 +108,8 @@ export class SearchEditor extends BaseTextEditor {
this.inputFocusContextKey = InputBoxFocusedKey.bindTo(scopedContextKeyService);
this.searchOperation = this._register(new LongRunningOperation(progressService));
this.searchHistoryDelayer = new Delayer<void>(2000);
this.searchModel = this._register(this.instantiationService.createInstance(SearchModel));
}
createEditor(parent: HTMLElement) {
@@ -326,6 +329,8 @@ export class SearchEditor extends BaseTextEditor {
}
private async doRunSearch() {
this.searchModel.cancelSearch(true);
const startInput = this.getInput();
this.searchHistoryDelayer.trigger(() => {
@@ -372,30 +377,26 @@ export class SearchEditor extends BaseTextEditor {
catch (err) {
return;
}
const searchModel = this.instantiationService.createInstance(SearchModel);
this.searchOperation.start(500);
await searchModel.search(query).finally(() => this.searchOperation.stop());
await this.searchModel.search(query).finally(() => this.searchOperation.stop());
const input = this.getInput();
if (!input ||
input !== startInput ||
JSON.stringify(config) !== JSON.stringify(this.readConfigFromWidget())) {
searchModel.dispose();
return;
}
const controller = ReferencesController.get(this.searchResultEditor);
controller.closeWidget(false);
const labelFormatter = (uri: URI): string => this.labelService.getUriLabel(uri, { relative: true });
const results = serializeSearchResultForEditor(searchModel.searchResult, config.includes, config.excludes, config.contextLines, labelFormatter, false);
const results = serializeSearchResultForEditor(this.searchModel.searchResult, config.includes, config.excludes, config.contextLines, labelFormatter, false);
const { header, body } = await input.getModels();
this.modelService.updateModel(body, results.text);
header.setValue(serializeSearchConfiguration(config));
input.setDirty(input.resource.scheme !== 'search-editor');
input.setMatchRanges(results.matchRanges);
searchModel.dispose();
}
layout(dimension: DOM.Dimension) {
@@ -198,6 +198,12 @@ export interface ISearchCompleteStats {
export interface ISearchComplete extends ISearchCompleteStats {
results: IFileMatch[];
exit?: SearchCompletionExitCode
}
export const enum SearchCompletionExitCode {
Normal,
NewSearchStarted
}
export interface ITextSearchStats {