diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index e2e3c4a95a2dd..241c1d1453b37 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -31,7 +31,7 @@ import {IEditorGroupService} from 'vs/workbench/services/group/common/groupServi import {getOutOfWorkspaceEditorResources} from 'vs/workbench/common/editor'; import {FileChangeType, FileChangesEvent, EventType as FileEventType} from 'vs/platform/files/common/files'; import {Viewlet} from 'vs/workbench/browser/viewlet'; -import {Match, FileMatch, SearchModel, FileMatchOrMatch} from 'vs/workbench/parts/search/common/searchModel'; +import {Match, FileMatch, SearchModel, FileMatchOrMatch, IChangeEvent} from 'vs/workbench/parts/search/common/searchModel'; import {getExcludes, QueryBuilder} from 'vs/workbench/parts/search/common/searchQuery'; import {VIEWLET_ID} from 'vs/workbench/parts/search/common/constants'; import {MessageType, InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -309,12 +309,29 @@ export class SearchViewlet extends Viewlet { } private registerListeners(): void { - this.toUnbind.push(this.viewModel.searchResult.onChange((element) => { - this.tree.refresh(element); + this.toUnbind.push(this.viewModel.searchResult.onChange((event) => { + this.refreshTree(event); this.searchWidget.setReplaceAllActionState(!this.viewModel.searchResult.isEmpty()); })); } + private refreshTree(event: IChangeEvent): void { + if (event.added || event.removed) { + this.tree.refresh(this.viewModel.searchResult); + if (event.added) { + event.elements.forEach(element => { + this.autoExpandFileMatch(element, true); + }); + } + } else { + if (event.elements.length === 1) { + this.tree.refresh(event.elements[0]); + } else { + this.tree.refresh(event.elements); + } + } + } + private refreshInputs(): void { this.viewModel.searchResult.matches().forEach((fileMatch) => { this.replaceService.refreshInput(fileMatch, this.viewModel.replaceText); @@ -668,6 +685,15 @@ export class SearchViewlet extends Viewlet { } } + private autoExpandFileMatch(fileMatch: FileMatch, alwaysExpandIfOneResult: boolean): void { + let length = fileMatch.matches().length; + if (length < 10 || (alwaysExpandIfOneResult && this.viewModel.searchResult.count() === 1 && length < 50)) { + this.tree.expand(fileMatch).done(null, errors.onUnexpectedError); + } else { + this.tree.collapse(fileMatch).done(null, errors.onUnexpectedError); + } + } + private onQueryTriggered(query: ISearchQuery, excludePattern: string, includePattern: string): void { // Progress total is 100% let progressTotal = 100; @@ -688,15 +714,8 @@ export class SearchViewlet extends Viewlet { if (handledMatches[match.id()]) { return; // if we once handled a result, do not do it again to keep results stable (the user might have expanded/collapsed meanwhile) } - handledMatches[match.id()] = true; - - let length = match.matches().length; - if (length < 10 || (alwaysExpandIfOneResult && matches.length === 1 && length < 50)) { - this.tree.expand(match).done(null, errors.onUnexpectedError); - } else { - this.tree.collapse(match).done(null, errors.onUnexpectedError); - } + this.autoExpandFileMatch(match, alwaysExpandIfOneResult); }); }; diff --git a/src/vs/workbench/parts/search/common/searchModel.ts b/src/vs/workbench/parts/search/common/searchModel.ts index 8dc7c9d28a811..503d9232d7eb7 100644 --- a/src/vs/workbench/parts/search/common/searchModel.ts +++ b/src/vs/workbench/parts/search/common/searchModel.ts @@ -236,10 +236,16 @@ export class FileMatch extends Disposable { } } +export interface IChangeEvent { + elements: FileMatch[]; + added?: boolean; + removed?: boolean; +} + export class SearchResult extends Disposable { - private _onChange= this._register(new Emitter()); - public onChange: Event = this._onChange.event; + private _onChange= this._register(new Emitter()); + public onChange: Event = this._onChange.event; private _fileMatches: SimpleMap; private _unDisposedFileMatches: SimpleMap; @@ -263,27 +269,30 @@ export class SearchResult extends Disposable { } public add(raw: Search.IFileMatch[], silent:boolean= false): void { + let changed: FileMatch[] = []; raw.forEach((rawFileMatch) => { if (!this._fileMatches.has(rawFileMatch.resource)){ let fileMatch= this.instantiationService.createInstance(FileMatch, this._query, this, rawFileMatch); this.doAdd(fileMatch); + changed.push(fileMatch); let disposable= fileMatch.onChange(() => this.onFileChange(fileMatch)); fileMatch.onDispose(() => disposable.dispose()); } }); if (!silent) { - this._onChange.fire(this); + this._onChange.fire({elements: changed, added: true}); } } public clear(): void { + let changed: FileMatch[]= this.matches(); this.disposeMatches(); - this._onChange.fire(this); + this._onChange.fire({elements: changed, removed: true}); } public remove(match: FileMatch): void { this.doRemove(match); - this._onChange.fire(this); + this._onChange.fire({elements: [match], removed: true}); } public replace(match: FileMatch, replaceText: string): TPromise { @@ -336,17 +345,19 @@ export class SearchResult extends Disposable { } private onFileChange(fileMatch: FileMatch): void { - let refreshFile: boolean= true; + let added: boolean= false; + let removed: boolean= false; if (!this._fileMatches.has(fileMatch.resource())) { this.doAdd(fileMatch); - refreshFile= false; + added= true; } if (fileMatch.count() === 0) { this.doRemove(fileMatch, false); - refreshFile= false; + added= false; + removed= true; } if (!this._replacingAll) { - this._onChange.fire(refreshFile ? fileMatch : this); + this._onChange.fire({elements: [fileMatch], added: added, removed: removed}); } }