Skip to content

Commit

Permalink
Explorer should show hidden files and their path if they are opened
Browse files Browse the repository at this point in the history
fixes #92090
  • Loading branch information
isidorn committed Mar 9, 2020
1 parent 849aadb commit 1876b51
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 32 deletions.
38 changes: 16 additions & 22 deletions src/vs/workbench/contrib/files/browser/views/explorerView.ts
Expand Up @@ -354,6 +354,7 @@ export class ExplorerView extends ViewPane {
private createTree(container: HTMLElement): void {
this.filter = this.instantiationService.createInstance(FilesFilter);
this._register(this.filter);
this._register(this.filter.onDidChange(() => this.refresh(true)));
const explorerLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
this._register(explorerLabels);

Expand Down Expand Up @@ -458,18 +459,7 @@ export class ExplorerView extends ViewPane {
this.autoReveal = configuration?.explorer?.autoReveal;

// Push down config updates to components of viewer
let needsRefresh = false;
if (this.filter) {
needsRefresh = this.filter.updateConfiguration();
}

if (event && !needsRefresh) {
needsRefresh = event.affectsConfiguration('explorer.decorations.colors')
|| event.affectsConfiguration('explorer.decorations.badges');
}

// Refresh viewer as needed if this originates from a config event
if (event && needsRefresh) {
if (event && (event.affectsConfiguration('explorer.decorations.colors') || event.affectsConfiguration('explorer.decorations.badges'))) {
this.refresh(true);
}
}
Expand Down Expand Up @@ -672,19 +662,23 @@ export class ExplorerView extends ViewPane {
}

if (item && item.parent) {
if (reveal) {
if (item.isDisposed) {
return this.onSelectResource(resource, reveal, retry + 1);
}
try {
if (reveal) {
if (item.isDisposed) {
return this.onSelectResource(resource, reveal, retry + 1);
}

// Don't scroll to the item if it's already visible
if (this.tree.getRelativeTop(item) === null) {
this.tree.reveal(item, 0.5);
// Don't scroll to the item if it's already visible
if (this.tree.getRelativeTop(item) === null) {
this.tree.reveal(item, 0.5);
}
}
}

this.tree.setFocus([item]);
this.tree.setSelection([item]);
this.tree.setFocus([item]);
this.tree.setSelection([item]);
} catch (e) {
// Element might not be in the tree, silently fail
}
}
}

Expand Down
85 changes: 75 additions & 10 deletions src/vs/workbench/contrib/files/browser/views/explorerViewer.ts
Expand Up @@ -55,6 +55,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { isNumber } from 'vs/base/common/types';
import { domEvent } from 'vs/base/browser/event';
import { IEditableData } from 'vs/workbench/common/views';
import { IEditorInput } from 'vs/workbench/common/editor';

export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {

Expand Down Expand Up @@ -472,39 +473,96 @@ interface CachedParsedExpression {
parsed: glob.ParsedExpression;
}

/**
* Respectes 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> {
private hiddenExpressionPerRoot: Map<string, CachedParsedExpression>;
private workspaceFolderChangeListener: IDisposable;
private hiddenUris = new Set<URI>();
private editorsAffectingFilter = new Set<IEditorInput>();
private _onDidChange = new Emitter<void>();
private toDispose: IDisposable[] = [];

constructor(
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IExplorerService private readonly explorerService: IExplorerService
@IExplorerService private readonly explorerService: IExplorerService,
@IEditorService private readonly editorService: IEditorService,
) {
this.hiddenExpressionPerRoot = new Map<string, CachedParsedExpression>();
this.workspaceFolderChangeListener = this.contextService.onDidChangeWorkspaceFolders(() => this.updateConfiguration());
this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateConfiguration()));
this.toDispose.push(this.configurationService.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration('files.exclude')) {
this.updateConfiguration();
}
}));
this.toDispose.push(this.editorService.onDidVisibleEditorsChange(() => {
const editors = this.editorService.visibleEditors;
let shouldFire = false;
this.hiddenUris.forEach(u => {
editors.forEach(e => {
if (e.resource && isEqualOrParent(e.resource, u)) {
// A filtered resource suddenly became visible since user opened an editor
shouldFire = true;
}
});
});

this.editorsAffectingFilter.forEach(e => {
if (editors.indexOf(e) === -1) {
// Editor that was affecting filtering is no longer visible
shouldFire = true;
}
});
if (shouldFire) {
this.editorsAffectingFilter.clear();
this.hiddenUris.clear();
this._onDidChange.fire();
}
}));
this.updateConfiguration();
}

updateConfiguration(): boolean {
let needsRefresh = false;
get onDidChange(): Event<void> {
return this._onDidChange.event;
}

private updateConfiguration(): void {
let shouldFire = false;
this.contextService.getWorkspace().folders.forEach(folder => {
const configuration = this.configurationService.getValue<IFilesConfiguration>({ resource: folder.uri });
const excludesConfig: glob.IExpression = configuration?.files?.exclude || Object.create(null);

if (!needsRefresh) {
if (!shouldFire) {
const cached = this.hiddenExpressionPerRoot.get(folder.uri.toString());
needsRefresh = !cached || !equals(cached.original, excludesConfig);
shouldFire = !cached || !equals(cached.original, excludesConfig);
}

const excludesConfigCopy = deepClone(excludesConfig); // do not keep the config, as it gets mutated under our hoods

this.hiddenExpressionPerRoot.set(folder.uri.toString(), { original: excludesConfigCopy, parsed: glob.parse(excludesConfigCopy) });
});

return needsRefresh;
if (shouldFire) {
this.editorsAffectingFilter.clear();
this.hiddenUris.clear();
this._onDidChange.fire();
}
}

filter(stat: ExplorerItem, parentVisibility: TreeVisibility): TreeFilterResult<FuzzyScore> {
const isVisible = this.isVisible(stat, parentVisibility);
if (isVisible) {
this.hiddenUris.delete(stat.resource);
} else {
this.hiddenUris.add(stat.resource);
}

return isVisible;
}

private isVisible(stat: ExplorerItem, parentVisibility: TreeVisibility): boolean {
if (parentVisibility === TreeVisibility.Hidden) {
return false;
}
Expand All @@ -515,14 +573,21 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
// Hide those that match Hidden Patterns
const cached = this.hiddenExpressionPerRoot.get(stat.root.resource.toString());
if (cached && cached.parsed(path.relative(stat.root.resource.path, stat.resource.path), stat.name, name => !!(stat.parent && stat.parent.getChild(name)))) {
const editors = this.editorService.visibleEditors;
const editor = editors.filter(e => e.resource && isEqualOrParent(e.resource, stat.resource)).pop();
if (editor) {
this.editorsAffectingFilter.add(editor);
return true; // Show all opened files and their parents
}

return false; // hidden through pattern
}

return true;
}

public dispose(): void {
dispose(this.workspaceFolderChangeListener);
dispose(): void {
dispose(this.toDispose);
}
}

Expand Down

0 comments on commit 1876b51

Please sign in to comment.