Skip to content

Commit bdb2822

Browse files
committed
Search - Can't remove or "replace all" the "other files" row
Fix microsoft#80158, make names more clear, clean up
1 parent 5983f1e commit bdb2822

6 files changed

Lines changed: 45 additions & 44 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ MenuRegistry.appendMenuItem(MenuId.SearchContext, {
274274
KeybindingsRegistry.registerCommandAndKeybindingRule({
275275
id: Constants.CopyPathCommandId,
276276
weight: KeybindingWeight.WorkbenchContrib,
277-
when: Constants.FileMatchOrFolderMatchFocusKey,
277+
when: Constants.FileMatchOrFolderMatchWithResourceFocusKey,
278278
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C,
279279
win: {
280280
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_C
@@ -287,7 +287,7 @@ MenuRegistry.appendMenuItem(MenuId.SearchContext, {
287287
id: Constants.CopyPathCommandId,
288288
title: nls.localize('copyPathLabel', "Copy Path")
289289
},
290-
when: Constants.FileMatchOrFolderMatchFocusKey,
290+
when: Constants.FileMatchOrFolderMatchWithResourceFocusKey,
291291
group: 'search_2',
292292
order: 2
293293
});

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { getSelectionKeyboardEvent, WorkbenchObjectTree } from 'vs/platform/list
2020
import { SearchView } from 'vs/workbench/contrib/search/browser/searchView';
2121
import * as Constants from 'vs/workbench/contrib/search/common/constants';
2222
import { IReplaceService } from 'vs/workbench/contrib/search/common/replace';
23-
import { BaseFolderMatch, FileMatch, FileMatchOrMatch, FolderMatch, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel';
23+
import { FolderMatch, FileMatch, FileMatchOrMatch, FolderMatchWithResource, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel';
2424
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
2525
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
2626
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
@@ -312,7 +312,7 @@ export class CollapseDeepestExpandedLevelAction extends Action {
312312
const navigator = viewer.navigate();
313313
let node = navigator.first();
314314
let collapseFileMatchLevel = false;
315-
if (node instanceof BaseFolderMatch) {
315+
if (node instanceof FolderMatch) {
316316
while (node = navigator.next()) {
317317
if (node instanceof Match) {
318318
collapseFileMatchLevel = true;
@@ -448,8 +448,8 @@ export abstract class AbstractSearchAndReplaceAction extends Action {
448448

449449
getNextElementAfterRemoved(viewer: WorkbenchObjectTree<RenderableMatch>, element: RenderableMatch): RenderableMatch {
450450
const navigator: INavigator<any> = viewer.navigate(element);
451-
if (element instanceof BaseFolderMatch) {
452-
while (!!navigator.next() && !(navigator.current() instanceof BaseFolderMatch)) { }
451+
if (element instanceof FolderMatch) {
452+
while (!!navigator.next() && !(navigator.current() instanceof FolderMatch)) { }
453453
} else if (element instanceof FileMatch) {
454454
while (!!navigator.next() && !(navigator.current() instanceof FileMatch)) { }
455455
} else {
@@ -476,7 +476,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action {
476476

477477
// If the previous element is a File or Folder, expand it and go to its last child.
478478
// Spell out the two cases, would be too easy to create an infinite loop, like by adding another level...
479-
if (element instanceof Match && previousElement && previousElement instanceof BaseFolderMatch) {
479+
if (element instanceof Match && previousElement && previousElement instanceof FolderMatch) {
480480
navigator.next();
481481
viewer.expand(previousElement);
482482
previousElement = navigator.previous();
@@ -664,7 +664,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction {
664664
}
665665
}
666666

667-
export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatch) => {
667+
export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatchWithResource) => {
668668
const clipboardService = accessor.get(IClipboardService);
669669
const labelService = accessor.get(ILabelService);
670670

@@ -712,7 +712,7 @@ function fileMatchToString(fileMatch: FileMatch, maxMatches: number, labelServic
712712
};
713713
}
714714

715-
function folderMatchToString(folderMatch: FolderMatch | BaseFolderMatch, maxMatches: number, labelService: ILabelService): { text: string, count: number } {
715+
function folderMatchToString(folderMatch: FolderMatchWithResource | FolderMatch, maxMatches: number, labelService: ILabelService): { text: string, count: number } {
716716
const fileResults: string[] = [];
717717
let numMatches = 0;
718718

@@ -740,7 +740,7 @@ export const copyMatchCommand: ICommandHandler = async (accessor, match: Rendera
740740
text = matchToString(match);
741741
} else if (match instanceof FileMatch) {
742742
text = fileMatchToString(match, maxClipboardMatches, labelService).text;
743-
} else if (match instanceof BaseFolderMatch) {
743+
} else if (match instanceof FolderMatch) {
744744
text = folderMatchToString(match, maxClipboardMatches, labelService).text;
745745
}
746746

@@ -749,7 +749,7 @@ export const copyMatchCommand: ICommandHandler = async (accessor, match: Rendera
749749
}
750750
};
751751

752-
function allFolderMatchesToString(folderMatches: Array<FolderMatch | BaseFolderMatch>, maxMatches: number, labelService: ILabelService): string {
752+
function allFolderMatchesToString(folderMatches: Array<FolderMatchWithResource | FolderMatch>, maxMatches: number, labelService: ILabelService): string {
753753
const folderResults: string[] = [];
754754
let numMatches = 0;
755755
folderMatches = folderMatches.sort(searchMatchComparer);

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
2525
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
2626
import { RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction } from 'vs/workbench/contrib/search/browser/searchActions';
2727
import { SearchView } from 'vs/workbench/contrib/search/browser/searchView';
28-
import { FileMatch, FolderMatch, Match, RenderableMatch, SearchModel, BaseFolderMatch } from 'vs/workbench/contrib/search/common/searchModel';
28+
import { FileMatch, Match, RenderableMatch, SearchModel, FolderMatch } from 'vs/workbench/contrib/search/common/searchModel';
2929
import { IDragAndDropData } from 'vs/base/browser/dnd';
3030
import { fillResourceDataTransfers } from 'vs/workbench/browser/dnd';
3131
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
@@ -63,7 +63,7 @@ export class SearchDelegate implements IListVirtualDelegate<RenderableMatch> {
6363
}
6464

6565
getTemplateId(element: RenderableMatch): string {
66-
if (element instanceof BaseFolderMatch) {
66+
if (element instanceof FolderMatch) {
6767
return FolderMatchRenderer.TEMPLATE_ID;
6868
} else if (element instanceof FileMatch) {
6969
return FileMatchRenderer.TEMPLATE_ID;
@@ -114,7 +114,7 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer<Fol
114114

115115
renderElement(node: ITreeNode<FolderMatch, any>, index: number, templateData: IFolderMatchTemplate): void {
116116
const folderMatch = node.element;
117-
if (folderMatch.hasResource()) {
117+
if (folderMatch.resource) {
118118
const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource);
119119
if (workspaceFolder && resources.isEqual(workspaceFolder.uri, folderMatch.resource)) {
120120
templateData.label.setFile(folderMatch.resource, { fileKind: FileKind.ROOT_FOLDER, hidePath: true });
@@ -309,8 +309,8 @@ export class SearchAccessibilityProvider implements IAccessibilityProvider<Rende
309309
}
310310

311311
getAriaLabel(element: RenderableMatch): string | null {
312-
if (element instanceof BaseFolderMatch) {
313-
return element.hasResource() ?
312+
if (element instanceof FolderMatch) {
313+
return element.resource ?
314314
nls.localize('folderMatchAriaLabel', "{0} matches in folder root {1}, Search result", element.count(), element.name()) :
315315
nls.localize('otherFilesAriaLabel', "{0} matches outside of the workspace, Search result", element.count());
316316
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import * as Constants from 'vs/workbench/contrib/search/common/constants';
5050
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
5151
import { IReplaceService } from 'vs/workbench/contrib/search/common/replace';
5252
import { getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search';
53-
import { FileMatch, FileMatchOrMatch, FolderMatch, IChangeEvent, ISearchWorkbenchService, Match, RenderableMatch, searchMatchComparer, SearchModel, SearchResult, BaseFolderMatch } from 'vs/workbench/contrib/search/common/searchModel';
53+
import { FileMatch, FileMatchOrMatch, IChangeEvent, ISearchWorkbenchService, Match, RenderableMatch, searchMatchComparer, SearchModel, SearchResult, FolderMatch, FolderMatchWithResource } from 'vs/workbench/contrib/search/common/searchModel';
5454
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
5555
import { IPreferencesService, ISettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
5656
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
@@ -93,6 +93,7 @@ export class SearchView extends ViewletPanel {
9393
private firstMatchFocused: IContextKey<boolean>;
9494
private fileMatchOrMatchFocused: IContextKey<boolean>;
9595
private fileMatchOrFolderMatchFocus: IContextKey<boolean>;
96+
private fileMatchOrFolderMatchWithResourceFocus: IContextKey<boolean>;
9697
private fileMatchFocused: IContextKey<boolean>;
9798
private folderMatchFocused: IContextKey<boolean>;
9899
private matchFocused: IContextKey<boolean>;
@@ -163,6 +164,7 @@ export class SearchView extends ViewletPanel {
163164
this.firstMatchFocused = Constants.FirstMatchFocusKey.bindTo(contextKeyService);
164165
this.fileMatchOrMatchFocused = Constants.FileMatchOrMatchFocusKey.bindTo(contextKeyService);
165166
this.fileMatchOrFolderMatchFocus = Constants.FileMatchOrFolderMatchFocusKey.bindTo(contextKeyService);
167+
this.fileMatchOrFolderMatchWithResourceFocus = Constants.FileMatchOrFolderMatchWithResourceFocusKey.bindTo(contextKeyService);
166168
this.fileMatchFocused = Constants.FileFocusKey.bindTo(contextKeyService);
167169
this.folderMatchFocused = Constants.FolderFocusKey.bindTo(contextKeyService);
168170
this.matchFocused = Constants.MatchFocusKey.bindTo(this.contextKeyService);
@@ -473,7 +475,7 @@ export class SearchView extends ViewletPanel {
473475
});
474476
}
475477

476-
private createFolderIterator(folderMatch: BaseFolderMatch, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator<ITreeElement<RenderableMatch>> {
478+
private createFolderIterator(folderMatch: FolderMatch, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator<ITreeElement<RenderableMatch>> {
477479
const filesIt = Iterator.fromArray(
478480
folderMatch.matches()
479481
.sort(searchMatchComparer));
@@ -498,9 +500,9 @@ export class SearchView extends ViewletPanel {
498500
return Iterator.map(matchesIt, r => (<ITreeElement<RenderableMatch>>{ element: r }));
499501
}
500502

501-
private createIterator(match: BaseFolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator<ITreeElement<RenderableMatch>> {
503+
private createIterator(match: FolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator<ITreeElement<RenderableMatch>> {
502504
return match instanceof SearchResult ? this.createResultIterator(collapseResults) :
503-
match instanceof BaseFolderMatch ? this.createFolderIterator(match, collapseResults) :
505+
match instanceof FolderMatch ? this.createFolderIterator(match, collapseResults) :
504506
this.createFileIterator(match);
505507
}
506508

@@ -671,6 +673,7 @@ export class SearchView extends ViewletPanel {
671673
this.folderMatchFocused.set(focus instanceof FolderMatch);
672674
this.matchFocused.set(focus instanceof Match);
673675
this.fileMatchOrFolderMatchFocus.set(focus instanceof FileMatch || focus instanceof FolderMatch);
676+
this.fileMatchOrFolderMatchWithResourceFocus.set(focus instanceof FileMatch || focus instanceof FolderMatchWithResource);
674677
}
675678
}));
676679

@@ -681,6 +684,7 @@ export class SearchView extends ViewletPanel {
681684
this.folderMatchFocused.reset();
682685
this.matchFocused.reset();
683686
this.fileMatchOrFolderMatchFocus.reset();
687+
this.fileMatchOrFolderMatchWithResourceFocus.reset();
684688
}));
685689
}
686690

src/vs/workbench/contrib/search/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const HasSearchResults = new RawContextKey<boolean>('hasSearchResult', fa
4141
export const FirstMatchFocusKey = new RawContextKey<boolean>('firstMatchFocus', false);
4242
export const FileMatchOrMatchFocusKey = new RawContextKey<boolean>('fileMatchOrMatchFocus', false); // This is actually, Match or File or Folder
4343
export const FileMatchOrFolderMatchFocusKey = new RawContextKey<boolean>('fileMatchOrFolderMatchFocus', false);
44+
export const FileMatchOrFolderMatchWithResourceFocusKey = new RawContextKey<boolean>('fileMatchOrFolderMatchWithResourceFocus', false); // Excludes "Other files"
4445
export const FileFocusKey = new RawContextKey<boolean>('fileMatchFocus', false);
4546
export const FolderFocusKey = new RawContextKey<boolean>('folderMatchFocus', false);
4647
export const MatchFocusKey = new RawContextKey<boolean>('matchFocus', false);

src/vs/workbench/contrib/search/common/searchModel.ts

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export class FileMatch extends Disposable implements IFileMatch {
197197
private _updateScheduler: RunOnceScheduler;
198198
private _modelDecorations: string[] = [];
199199

200-
constructor(private _query: IPatternInfo, private _previewOptions: ITextSearchPreviewOptions, private _maxResults: number, private _parent: BaseFolderMatch, private rawMatch: IFileMatch,
200+
constructor(private _query: IPatternInfo, private _previewOptions: ITextSearchPreviewOptions, private _maxResults: number, private _parent: FolderMatch, private rawMatch: IFileMatch,
201201
@IModelService private readonly modelService: IModelService, @IReplaceService private readonly replaceService: IReplaceService
202202
) {
203203
super();
@@ -322,7 +322,7 @@ export class FileMatch extends Disposable implements IFileMatch {
322322
return this.resource.toString();
323323
}
324324

325-
parent(): BaseFolderMatch {
325+
parent(): FolderMatch {
326326
return this._parent;
327327
}
328328

@@ -405,7 +405,7 @@ export interface IChangeEvent {
405405
removed?: boolean;
406406
}
407407

408-
export class BaseFolderMatch extends Disposable {
408+
export class FolderMatch extends Disposable {
409409

410410
private _onChange = this._register(new Emitter<IChangeEvent>());
411411
readonly onChange: Event<IChangeEvent> = this._onChange.event;
@@ -458,10 +458,6 @@ export class BaseFolderMatch extends Disposable {
458458
return this._parent;
459459
}
460460

461-
hasResource(): boolean {
462-
return !!this._resource;
463-
}
464-
465461
bindModel(model: ITextModel): void {
466462
const fileMatch = this._fileMatches.get(model.uri);
467463
if (fileMatch) {
@@ -598,7 +594,7 @@ export class BaseFolderMatch extends Disposable {
598594
* BaseFolderMatch => optional resource ("other files" node)
599595
* FolderMatch => required resource (normal folder node)
600596
*/
601-
export class FolderMatch extends BaseFolderMatch {
597+
export class FolderMatchWithResource extends FolderMatch {
602598
constructor(_resource: URI, _id: string, _index: number, _query: ITextQuery, _parent: SearchResult, _searchModel: SearchModel,
603599
@IReplaceService replaceService: IReplaceService,
604600
@IInstantiationService instantiationService: IInstantiationService
@@ -616,7 +612,7 @@ export class FolderMatch extends BaseFolderMatch {
616612
* and their sort order is undefined.
617613
*/
618614
export function searchMatchComparer(elementA: RenderableMatch, elementB: RenderableMatch): number {
619-
if (elementA instanceof BaseFolderMatch && elementB instanceof BaseFolderMatch) {
615+
if (elementA instanceof FolderMatch && elementB instanceof FolderMatch) {
620616
return elementA.index() - elementB.index();
621617
}
622618

@@ -636,9 +632,9 @@ export class SearchResult extends Disposable {
636632
private _onChange = this._register(new Emitter<IChangeEvent>());
637633
readonly onChange: Event<IChangeEvent> = this._onChange.event;
638634

639-
private _folderMatches: FolderMatch[] = [];
640-
private _otherFilesMatch: BaseFolderMatch;
641-
private _folderMatchesMap: TernarySearchTree<FolderMatch> = TernarySearchTree.forPaths<FolderMatch>();
635+
private _folderMatches: FolderMatchWithResource[] = [];
636+
private _otherFilesMatch: FolderMatch;
637+
private _folderMatchesMap: TernarySearchTree<FolderMatchWithResource> = TernarySearchTree.forPaths<FolderMatchWithResource>();
642638
private _showHighlights: boolean;
643639
private _query: ITextQuery;
644640

@@ -666,7 +662,7 @@ export class SearchResult extends Disposable {
666662
this.clear();
667663
this._folderMatches = (query.folderQueries || [])
668664
.map(fq => fq.folder)
669-
.map((resource, index) => this.createFolderMatch(resource, resource.toString(), index, query));
665+
.map((resource, index) => this.createFolderMatchWithResource(resource, resource.toString(), index, query));
670666

671667
this._folderMatches.forEach(fm => this._folderMatchesMap.set(fm.resource.toString(), fm));
672668
this._otherFilesMatch = this.createOtherFilesFolderMatch('otherFiles', this._folderMatches.length + 1, query);
@@ -681,15 +677,15 @@ export class SearchResult extends Disposable {
681677
}
682678
}
683679

684-
private createFolderMatch(resource: URI, id: string, index: number, query: ITextQuery): FolderMatch {
685-
return <FolderMatch>this._createBaseFolderMatch(FolderMatch, resource, id, index, query);
680+
private createFolderMatchWithResource(resource: URI, id: string, index: number, query: ITextQuery): FolderMatchWithResource {
681+
return <FolderMatchWithResource>this._createBaseFolderMatch(FolderMatchWithResource, resource, id, index, query);
686682
}
687683

688-
private createOtherFilesFolderMatch(id: string, index: number, query: ITextQuery): BaseFolderMatch {
689-
return this._createBaseFolderMatch(BaseFolderMatch, null, id, index, query);
684+
private createOtherFilesFolderMatch(id: string, index: number, query: ITextQuery): FolderMatch {
685+
return this._createBaseFolderMatch(FolderMatch, null, id, index, query);
690686
}
691687

692-
private _createBaseFolderMatch(folderMatchClass: typeof BaseFolderMatch | typeof FolderMatch, resource: URI | null, id: string, index: number, query: ITextQuery): BaseFolderMatch {
688+
private _createBaseFolderMatch(folderMatchClass: typeof FolderMatch | typeof FolderMatchWithResource, resource: URI | null, id: string, index: number, query: ITextQuery): FolderMatch {
693689
const folderMatch = this.instantiationService.createInstance(folderMatchClass, resource, id, index, query, this, this._searchModel);
694690
const disposable = folderMatch.onChange((event) => this._onChange.fire(event));
695691
folderMatch.onDispose(() => disposable.dispose());
@@ -734,9 +730,9 @@ export class SearchResult extends Disposable {
734730
}
735731
});
736732

737-
matches = matches.filter(m => m instanceof FileMatch);
733+
const fileMatches: FileMatch[] = matches.filter(m => m instanceof FileMatch) as FileMatch[];
738734

739-
const { byFolder, other } = this.groupFilesByFolder(matches);
735+
const { byFolder, other } = this.groupFilesByFolder(fileMatches);
740736
byFolder.forEach(matches => {
741737
if (!matches.length) {
742738
return;
@@ -774,7 +770,7 @@ export class SearchResult extends Disposable {
774770
});
775771
}
776772

777-
folderMatches(): BaseFolderMatch[] {
773+
folderMatches(): FolderMatch[] {
778774
return this._otherFilesMatch ?
779775
[
780776
...this._folderMatches,
@@ -837,7 +833,7 @@ export class SearchResult extends Disposable {
837833
return this._rangeHighlightDecorations;
838834
}
839835

840-
private getFolderMatch(resource: URI): BaseFolderMatch {
836+
private getFolderMatch(resource: URI): FolderMatch {
841837
const folderMatch = this._folderMatchesMap.findSubstr(resource.toString());
842838
return folderMatch ? folderMatch : this._otherFilesMatch;
843839
}
@@ -877,7 +873,7 @@ export class SearchResult extends Disposable {
877873
private disposeMatches(): void {
878874
this.folderMatches().forEach(folderMatch => folderMatch.dispose());
879875
this._folderMatches = [];
880-
this._folderMatchesMap = TernarySearchTree.forPaths<FolderMatch>();
876+
this._folderMatchesMap = TernarySearchTree.forPaths<FolderMatchWithResource>();
881877
this._rangeHighlightDecorations.removeHighlightRange();
882878
}
883879

@@ -1063,7 +1059,7 @@ export class SearchModel extends Disposable {
10631059

10641060
export type FileMatchOrMatch = FileMatch | Match;
10651061

1066-
export type RenderableMatch = BaseFolderMatch | FolderMatch | FileMatch | Match;
1062+
export type RenderableMatch = FolderMatch | FolderMatchWithResource | FileMatch | Match;
10671063

10681064
export class SearchWorkbenchService implements ISearchWorkbenchService {
10691065

0 commit comments

Comments
 (0)