Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search In Open Editors #107756

Merged
merged 11 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extensions/git/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
"category": "Git",
"icon": "$(compare-changes)"
},
{
"command": "git.openAllChanges",
"title": "%command.openAllChanges%",
"category": "Git"
},
{
"command": "git.openFile",
"title": "%command.openFile%",
Expand Down
1 change: 1 addition & 0 deletions extensions/git/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"command.close": "Close Repository",
"command.refresh": "Refresh",
"command.openChange": "Open Changes",
"command.openAllChanges": "Open All Changes",
"command.openFile": "Open File",
"command.openHEADFile": "Open File (HEAD)",
"command.stage": "Stage Changes",
Expand Down
14 changes: 14 additions & 0 deletions extensions/git/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,20 @@ export class CommandCenter {
await resource.open();
}

@command('git.openAllChanges', { repository: true })
async openChanges(repository: Repository): Promise<void> {
[
...repository.workingTreeGroup.resourceStates,
...repository.untrackedGroup.resourceStates,
].forEach(resource => {
commands.executeCommand(
'vscode.open',
resource.resourceUri,
{ preview: false, }
);
});
}

async cloneRepository(url?: string, parentPath?: string, options: { recursive?: boolean } = {}): Promise<void> {
if (!url || typeof url !== 'string') {
url = await pickRemoteSource(this.model, {
Expand Down
67 changes: 63 additions & 4 deletions src/vs/workbench/contrib/search/browser/patternInputWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedH
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import type { IThemable } from 'vs/base/common/styler';
import { Codicon } from 'vs/base/common/codicons';

import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ISearchConfiguration } from 'vs/workbench/services/search/common/search';
export interface IOptions {
placeholder?: string;
width?: number;
Expand Down Expand Up @@ -50,7 +51,8 @@ export class PatternInputWidget extends Widget implements IThemable {

constructor(parent: HTMLElement, private contextViewProvider: IContextViewProvider, options: IOptions = Object.create(null),
@IThemeService protected themeService: IThemeService,
@IContextKeyService private readonly contextKeyService: IContextKeyService
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService protected readonly configurationService: IConfigurationService
) {
super();
this.width = options.width || 100;
Expand Down Expand Up @@ -178,16 +180,73 @@ export class PatternInputWidget extends Widget implements IThemable {
}
}

export class IncludePatternInputWidget extends PatternInputWidget {

private _onChangeSearchInEditorsBoxEmitter = this._register(new Emitter<void>());
onChangeSearchInEditorsBox = this._onChangeSearchInEditorsBoxEmitter.event;

constructor(parent: HTMLElement, contextViewProvider: IContextViewProvider, options: IOptions = Object.create(null),
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService configurationService: IConfigurationService,
) {
super(parent, contextViewProvider, options, themeService, contextKeyService, configurationService);
}

private useSearchInEditorsBox!: Checkbox;

dispose(): void {
super.dispose();
this.useSearchInEditorsBox.dispose();
}

onlySearchInOpenEditors(): boolean {
return this.useSearchInEditorsBox.checked;
}

setOnlySearchInOpenEditors(value: boolean) {
this.useSearchInEditorsBox.checked = value;
}

protected getSubcontrolsWidth(): number {
if (this.configurationService.getValue<ISearchConfiguration>().search?.experimental?.searchInOpenEditors) {
return super.getSubcontrolsWidth() + this.useSearchInEditorsBox.width();
}
return super.getSubcontrolsWidth();
}

protected renderSubcontrols(controlsDiv: HTMLDivElement): void {
this.useSearchInEditorsBox = this._register(new Checkbox({
icon: Codicon.book,
title: nls.localize('onlySearchInOpenEditors', "Search only in Open Editors"),
isChecked: false,
}));
if (!this.configurationService.getValue<ISearchConfiguration>().search?.experimental?.searchInOpenEditors) {
return;
}
this._register(this.useSearchInEditorsBox.onChange(viaKeyboard => {
this._onChangeSearchInEditorsBoxEmitter.fire();
if (!viaKeyboard) {
this.inputBox.focus();
}
}));
this._register(attachCheckboxStyler(this.useSearchInEditorsBox, this.themeService));
controlsDiv.appendChild(this.useSearchInEditorsBox.domNode);
super.renderSubcontrols(controlsDiv);
}
}

export class ExcludePatternInputWidget extends PatternInputWidget {

private _onChangeIgnoreBoxEmitter = this._register(new Emitter<void>());
onChangeIgnoreBox = this._onChangeIgnoreBoxEmitter.event;

constructor(parent: HTMLElement, contextViewProvider: IContextViewProvider, options: IOptions = Object.create(null),
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService configurationService: IConfigurationService,
) {
super(parent, contextViewProvider, options, themeService, contextKeyService);
super(parent, contextViewProvider, options, themeService, contextKeyService, configurationService);
}

private useExcludesAndIgnoreFilesBox!: Checkbox;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,11 @@ configurationRegistry.registerConfiguration({
],
'description': nls.localize('search.sortOrder', "Controls sorting order of search results.")
},
'search.experimental.searchInOpenEditors': {
type: 'boolean',
default: false,
markdownDescription: nls.localize('search.experimental.searchInOpenEditors', "Experimental. When enabled, an option is provided to make workspace search only search files that have been opened. **Requires restart to take effect.**")
}
}
});

Expand Down
42 changes: 30 additions & 12 deletions src/vs/workbench/contrib/search/browser/searchView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/vie
import { IEditorPane } from 'vs/workbench/common/editor';
import { Memento, MementoObject } from 'vs/workbench/common/memento';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { ExcludePatternInputWidget, PatternInputWidget } from 'vs/workbench/contrib/search/browser/patternInputWidget';
import { ExcludePatternInputWidget, IncludePatternInputWidget } from 'vs/workbench/contrib/search/browser/patternInputWidget';
import { appendKeyBindingLabel, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions';
import { searchDetailsIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { FileMatchRenderer, FolderMatchRenderer, MatchRenderer, SearchAccessibilityProvider, SearchDelegate, SearchDND } from 'vs/workbench/contrib/search/browser/searchResultsView';
Expand Down Expand Up @@ -125,7 +125,7 @@ export class SearchView extends ViewPane {
private queryDetails!: HTMLElement;
private toggleQueryDetailsButton!: HTMLElement;
private inputPatternExcludes!: ExcludePatternInputWidget;
private inputPatternIncludes!: PatternInputWidget;
private inputPatternIncludes!: IncludePatternInputWidget;
private resultsElement!: HTMLElement;

private currentSelectedFileMatch: FileMatch | undefined;
Expand Down Expand Up @@ -309,14 +309,17 @@ export class SearchView extends ViewPane {
const filesToIncludeTitle = nls.localize('searchScope.includes', "files to include");
dom.append(folderIncludesList, $('h4', undefined, filesToIncludeTitle));

this.inputPatternIncludes = this._register(this.instantiationService.createInstance(PatternInputWidget, folderIncludesList, this.contextViewService, {
this.inputPatternIncludes = this._register(this.instantiationService.createInstance(IncludePatternInputWidget, folderIncludesList, this.contextViewService, {
ariaLabel: nls.localize('label.includes', 'Search Include Patterns'),
history: patternIncludesHistory,
}));

this.inputPatternIncludes.setValue(patternIncludes);

this._register(this.inputPatternIncludes.onSubmit(triggeredOnType => this.triggerQueryChange({ triggeredOnType, delay: this.searchConfig.searchOnTypeDebouncePeriod })));
this._register(this.inputPatternIncludes.onCancel(() => this.cancelSearch(false)));
this._register(this.inputPatternIncludes.onChangeSearchInEditorsBox(() => this.triggerQueryChange()));

this.trackInputBox(this.inputPatternIncludes.inputFocusTracker, this.inputPatternIncludesFocused);

// excludes list
Expand Down Expand Up @@ -385,7 +388,7 @@ export class SearchView extends ViewPane {
return this.searchWidget;
}

get searchIncludePattern(): PatternInputWidget {
get searchIncludePattern(): IncludePatternInputWidget {
return this.inputPatternIncludes;
}

Expand Down Expand Up @@ -1293,6 +1296,7 @@ export class SearchView extends ViewPane {
const excludePatternText = this.inputPatternExcludes.getValue().trim();
const includePatternText = this.inputPatternIncludes.getValue().trim();
const useExcludesAndIgnoreFiles = this.inputPatternExcludes.useExcludesAndIgnoreFiles();
const onlySearchInOpenEditors = this.inputPatternIncludes.onlySearchInOpenEditors();

if (contentPattern.length === 0) {
this.clearSearchResults(false);
Expand Down Expand Up @@ -1321,6 +1325,7 @@ export class SearchView extends ViewPane {
maxResults: SearchView.MAX_TEXT_RESULTS,
disregardIgnoreFiles: !useExcludesAndIgnoreFiles || undefined,
disregardExcludeSettings: !useExcludesAndIgnoreFiles || undefined,
onlyOpenEditors: onlySearchInOpenEditors,
excludePattern,
includePattern,
previewOptions: {
Expand Down Expand Up @@ -1443,14 +1448,26 @@ export class SearchView extends ViewPane {

if (!completed) {
message = SEARCH_CANCELLED_MESSAGE;
} else if (hasIncludes && hasExcludes) {
message = nls.localize('noResultsIncludesExcludes', "No results found in '{0}' excluding '{1}' - ", includePatternText, excludePatternText);
} else if (hasIncludes) {
message = nls.localize('noResultsIncludes', "No results found in '{0}' - ", includePatternText);
} else if (hasExcludes) {
message = nls.localize('noResultsExcludes', "No results found excluding '{0}' - ", excludePatternText);
} else if (this.inputPatternIncludes.onlySearchInOpenEditors()) {
if (hasIncludes && hasExcludes) {
message = nls.localize('noOpenEditorResultsIncludesExcludes', "No results found in open editors matching '{0}' excluding '{1}' - ", includePatternText, excludePatternText);
} else if (hasIncludes) {
message = nls.localize('noOpenEditorResultsIncludes', "No results found in open editors matching '{0}' - ", includePatternText);
} else if (hasExcludes) {
message = nls.localize('noOpenEditorResultsExcludes', "No results found in open editors excluding '{0}' - ", excludePatternText);
} else {
message = nls.localize('noOpenEditorResultsFound', "No results found in open editors. Review your settings for configured exclusions and check your gitignore files - ");
}
} else {
message = nls.localize('noResultsFound', "No results found. Review your settings for configured exclusions and check your gitignore files - ");
if (hasIncludes && hasExcludes) {
message = nls.localize('noResultsIncludesExcludes', "No results found in '{0}' excluding '{1}' - ", includePatternText, excludePatternText);
} else if (hasIncludes) {
message = nls.localize('noResultsIncludes', "No results found in '{0}' - ", includePatternText);
} else if (hasExcludes) {
message = nls.localize('noResultsExcludes', "No results found excluding '{0}' - ", excludePatternText);
} else {
message = nls.localize('noResultsFound', "No results found. Review your settings for configured exclusions and check your gitignore files - ");
}
}

// Indicate as status to ARIA
Expand All @@ -1472,6 +1489,7 @@ export class SearchView extends ViewPane {

this.inputPatternExcludes.setValue('');
this.inputPatternIncludes.setValue('');
this.inputPatternIncludes.setOnlySearchInOpenEditors(false);

this.triggerQueryChange({ preserveFocus: false });
}));
Expand Down Expand Up @@ -1599,7 +1617,7 @@ export class SearchView extends ViewPane {

this.messageDisposables.push(dom.addDisposableListener(openInEditorLink, dom.EventType.CLICK, (e: MouseEvent) => {
dom.EventHelper.stop(e, false);
this.instantiationService.invokeFunction(createEditorFromSearchResult, this.searchResult, this.searchIncludePattern.getValue(), this.searchExcludePattern.getValue());
this.instantiationService.invokeFunction(createEditorFromSearchResult, this.searchResult, this.searchIncludePattern.getValue(), this.searchExcludePattern.getValue(), this.searchIncludePattern.onlySearchInOpenEditors());
}));

this.reLayout();
Expand Down
Loading