mirror of
https://github.com/Microsoft/vscode
synced 2024-10-02 17:32:41 +00:00
Add explorer.autorevealExclude setting (#136905)
* Add explorer.autorevealExclude setting * Update setting name, only check sibling once * linting * Correct boolean order and add catch for force reveal * Check for force instead of converting * Do not make revealexcludes inherit from file.excludes * Linting
This commit is contained in:
parent
bdf8dd00e4
commit
fbaacfb921
|
@ -26,8 +26,8 @@ export class SettingsDocument {
|
|||
return this.provideFilesAssociationsCompletionItems(location, position);
|
||||
}
|
||||
|
||||
// files.exclude, search.exclude
|
||||
if (location.path[0] === 'files.exclude' || location.path[0] === 'search.exclude') {
|
||||
// files.exclude, search.exclude, explorer.autoRevealExclude
|
||||
if (location.path[0] === 'files.exclude' || location.path[0] === 'search.exclude' || location.path[0] === 'explorer.autoRevealExclude') {
|
||||
return this.provideExcludeCompletionItems(location, position);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,10 @@ export class ResourceGlobMatcher extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
matches(resource: URI): boolean {
|
||||
matches(
|
||||
resource: URI,
|
||||
hasSibling?: (name: string) => boolean
|
||||
): boolean {
|
||||
const folder = this.contextService.getWorkspaceFolder(resource);
|
||||
|
||||
let expressionForRoot: ParsedExpression | undefined;
|
||||
|
@ -108,6 +111,6 @@ export class ResourceGlobMatcher extends Disposable {
|
|||
resourcePathToMatch = resource.fsPath; // TODO@isidor: support non-file URIs
|
||||
}
|
||||
|
||||
return !!expressionForRoot && typeof resourcePathToMatch === 'string' && !!expressionForRoot(resourcePathToMatch);
|
||||
return !!expressionForRoot && typeof resourcePathToMatch === 'string' && !!expressionForRoot(resourcePathToMatch, undefined, hasSibling);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import { IProgressService, ProgressLocation, IProgressNotificationOptions, IProg
|
|||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IExpression } from 'vs/base/common/glob';
|
||||
import { ResourceGlobMatcher } from 'vs/workbench/common/resources';
|
||||
|
||||
export const UNDO_REDO_SOURCE = new UndoRedoSource();
|
||||
|
||||
|
@ -39,6 +41,7 @@ export class ExplorerService implements IExplorerService {
|
|||
private model: ExplorerModel;
|
||||
private onFileChangesScheduler: RunOnceScheduler;
|
||||
private fileChangeEvents: FileChangesEvent[] = [];
|
||||
private revealExcludeMatcher: ResourceGlobMatcher;
|
||||
|
||||
constructor(
|
||||
@IFileService private fileService: IFileService,
|
||||
|
@ -130,6 +133,11 @@ export class ExplorerService implements IExplorerService {
|
|||
this.refresh(false);
|
||||
}
|
||||
}));
|
||||
this.revealExcludeMatcher = new ResourceGlobMatcher(
|
||||
(uri) => getRevealExcludes(configurationService.getValue<IFilesConfiguration>({ resource: uri })),
|
||||
(event) => event.affectsConfiguration('explorer.autoRevealExclude'),
|
||||
contextService, configurationService);
|
||||
this.disposables.add(this.revealExcludeMatcher);
|
||||
}
|
||||
|
||||
get roots(): ExplorerItem[] {
|
||||
|
@ -254,8 +262,14 @@ export class ExplorerService implements IExplorerService {
|
|||
return;
|
||||
}
|
||||
|
||||
// If file or parent matches exclude patterns, do not reveal unless reveal argument is 'force'
|
||||
const ignoreRevealExcludes = reveal === 'force';
|
||||
|
||||
const fileStat = this.findClosest(resource);
|
||||
if (fileStat) {
|
||||
if (!this.shouldAutoRevealItem(fileStat, ignoreRevealExcludes)) {
|
||||
return;
|
||||
}
|
||||
await this.view.selectResource(fileStat.resource, reveal);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
@ -277,7 +291,10 @@ export class ExplorerService implements IExplorerService {
|
|||
const item = root.find(resource);
|
||||
await this.view.refresh(true, root);
|
||||
|
||||
// Select and Reveal
|
||||
// Once item is resolved, check again if folder should be expanded
|
||||
if (item && !this.shouldAutoRevealItem(item, ignoreRevealExcludes)) {
|
||||
return;
|
||||
}
|
||||
await this.view.selectResource(item ? item.resource : undefined, reveal);
|
||||
} catch (error) {
|
||||
root.isError = true;
|
||||
|
@ -395,6 +412,28 @@ export class ExplorerService implements IExplorerService {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if an item matches a explorer.autoRevealExclude pattern
|
||||
private shouldAutoRevealItem(item: ExplorerItem | undefined, ignore: boolean): boolean {
|
||||
if (item === undefined || ignore) {
|
||||
return true;
|
||||
}
|
||||
if (this.revealExcludeMatcher.matches(item.resource, name => !!(item.parent && item.parent.getChild(name)))) {
|
||||
return false;
|
||||
}
|
||||
const root = item.root;
|
||||
let currentItem = item.parent;
|
||||
while (currentItem !== root) {
|
||||
if (currentItem === undefined) {
|
||||
return true;
|
||||
}
|
||||
if (this.revealExcludeMatcher.matches(currentItem.resource)) {
|
||||
return false;
|
||||
}
|
||||
currentItem = currentItem.parent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): Promise<void> {
|
||||
let shouldRefresh = false;
|
||||
|
||||
|
@ -440,3 +479,13 @@ function doesFileEventAffect(item: ExplorerItem, view: IExplorerView, events: Fi
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getRevealExcludes(configuration: IFilesConfiguration): IExpression {
|
||||
const revealExcludes = configuration && configuration.explorer && configuration.explorer.autoRevealExclude;
|
||||
|
||||
if (!revealExcludes) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return revealExcludes;
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ CommandsRegistry.registerCommand({
|
|||
const explorerView = viewlet.getExplorerView();
|
||||
if (explorerView) {
|
||||
explorerView.setExpanded(true);
|
||||
await explorerService.select(uri, true);
|
||||
await explorerService.select(uri, 'force');
|
||||
explorerView.focus();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -371,6 +371,30 @@ configurationRegistry.registerConfiguration({
|
|||
],
|
||||
'description': nls.localize('autoReveal', "Controls whether the explorer should automatically reveal and select files when opening them.")
|
||||
},
|
||||
'explorer.autoRevealExclude': {
|
||||
'type': 'object',
|
||||
'markdownDescription': nls.localize('autoRevealExclude', "Configure glob patterns for excluding files and folders from being revealed and selected in the explorer when they are opened. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."),
|
||||
'default': { '**/node_modules': true, '**/bower_components': true },
|
||||
'additionalProperties': {
|
||||
'anyOf': [
|
||||
{
|
||||
'type': 'boolean',
|
||||
'description': nls.localize('explorer.autoRevealExclude.boolean', "The glob pattern to match file paths against. Set to true or false to enable or disable the pattern."),
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
when: {
|
||||
type: 'string', // expression ({ "**/*.js": { "when": "$(basename).js" } })
|
||||
pattern: '\\w*\\$\\(basename\\)\\w*',
|
||||
default: '$(basename).ext',
|
||||
description: nls.localize('explorer.autoRevealExclude.when', 'Additional check on the siblings of a matching file. Use $(basename) as variable for the matching file name.')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
'explorer.enableDragAndDrop': {
|
||||
'type': 'boolean',
|
||||
'description': nls.localize('enableDragAndDrop', "Controls whether the explorer should allow to move files and folders via drag and drop. This setting only effects drag and drop from inside the explorer."),
|
||||
|
|
|
@ -181,7 +181,7 @@ export class ExplorerView extends ViewPane implements IExplorerView {
|
|||
private horizontalScrolling: boolean | undefined;
|
||||
|
||||
private dragHandler!: DelayedDragHandler;
|
||||
private autoReveal: boolean | 'focusNoScroll' = false;
|
||||
private autoReveal: boolean | 'force' | 'focusNoScroll' = false;
|
||||
private decorationsProvider: ExplorerDecorationsProvider | undefined;
|
||||
|
||||
constructor(
|
||||
|
@ -725,7 +725,7 @@ export class ExplorerView extends ViewPane implements IExplorerView {
|
|||
}
|
||||
|
||||
public async selectResource(resource: URI | undefined, reveal = this.autoReveal, retry = 0): Promise<void> {
|
||||
// do no retry more than once to prevent inifinite loops in cases of inconsistent model
|
||||
// do no retry more than once to prevent infinite loops in cases of inconsistent model
|
||||
if (retry === 2) {
|
||||
return;
|
||||
}
|
||||
|
@ -766,7 +766,7 @@ export class ExplorerView extends ViewPane implements IExplorerView {
|
|||
await this.tree.expand(item.nestedParent);
|
||||
}
|
||||
|
||||
if (reveal === true && this.tree.getRelativeTop(item) === null) {
|
||||
if ((reveal === true || reveal === 'force') && this.tree.getRelativeTop(item) === null) {
|
||||
// Don't scroll to the item if it's already visible, or if set not to.
|
||||
this.tree.reveal(item, 0.5);
|
||||
}
|
||||
|
|
|
@ -604,7 +604,7 @@ interface CachedParsedExpression {
|
|||
}
|
||||
|
||||
/**
|
||||
* Respectes files.exclude setting in filtering out content from the explorer.
|
||||
* Respects files.exclude setting in filtering out content from the explorer.
|
||||
* Makes sure that visible editors are always shown in the explorer even if they are filtered out by settings.
|
||||
*/
|
||||
export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
|
||||
|
|
|
@ -21,6 +21,7 @@ import { once } from 'vs/base/common/functional';
|
|||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExpression } from 'vs/base/common/glob';
|
||||
|
||||
/**
|
||||
* Explorer viewlet id.
|
||||
|
@ -88,6 +89,7 @@ export interface IFilesConfiguration extends PlatformIFilesConfiguration, IWorkb
|
|||
sortOrder: 'editorOrder' | 'alphabetical' | 'fullPath';
|
||||
};
|
||||
autoReveal: boolean | 'focusNoScroll';
|
||||
autoRevealExclude: IExpression;
|
||||
enableDragAndDrop: boolean;
|
||||
confirmDelete: boolean;
|
||||
enableUndo: boolean;
|
||||
|
|
|
@ -739,6 +739,7 @@ export function isExcludeSetting(setting: ISetting): boolean {
|
|||
return setting.key === 'files.exclude' ||
|
||||
setting.key === 'search.exclude' ||
|
||||
setting.key === 'workbench.localHistory.exclude' ||
|
||||
setting.key === 'explorer.autoRevealExclude' ||
|
||||
setting.key === 'files.watcherExclude';
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue