mirror of
https://github.com/Microsoft/vscode
synced 2024-09-19 18:48:00 +00:00
#68927 Use resource glob matcher
This commit is contained in:
parent
aca0a5ed9a
commit
1fe15c5f0a
|
@ -10,6 +10,8 @@ import { equalsIgnoreCase } from 'vs/base/common/strings';
|
|||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
|
||||
export function getComparisonKey(resource: URI): string {
|
||||
return hasToIgnoreCase(resource) ? resource.toString().toLowerCase() : resource.toString();
|
||||
|
@ -295,3 +297,30 @@ export namespace DataUri {
|
|||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ResourceGlobMatcher {
|
||||
|
||||
private readonly globalExpression: ParsedExpression;
|
||||
private readonly expressionsByRoot: TernarySearchTree<{ root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
|
||||
|
||||
constructor(
|
||||
globalExpression: IExpression,
|
||||
rootExpressions: { root: URI, expression: IExpression }[]
|
||||
) {
|
||||
this.globalExpression = parse(globalExpression);
|
||||
for (const expression of rootExpressions) {
|
||||
this.expressionsByRoot.set(expression.root.toString(), { root: expression.root, expression: parse(expression.expression) });
|
||||
}
|
||||
}
|
||||
|
||||
matches(resource: URI): boolean {
|
||||
const rootExpression = this.expressionsByRoot.findSubstr(resource.toString());
|
||||
if (rootExpression) {
|
||||
if (!!rootExpression.expression(relativePath(rootExpression.root, resource))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return !!this.globalExpression(resource.path);
|
||||
}
|
||||
}
|
|
@ -5,8 +5,10 @@
|
|||
|
||||
import Messages from 'vs/workbench/contrib/markers/electron-browser/messages';
|
||||
import { IFilter, matchesPrefix, matchesFuzzy, matchesFuzzy2 } from 'vs/base/common/filters';
|
||||
import { ParsedExpression, IExpression, splitGlobAware, getEmptyExpression, parse } from 'vs/base/common/glob';
|
||||
import { IExpression, splitGlobAware, getEmptyExpression } from 'vs/base/common/glob';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ResourceGlobMatcher } from 'vs/base/common/resources';
|
||||
|
||||
export class FilterOptions {
|
||||
|
||||
|
@ -16,19 +18,17 @@ export class FilterOptions {
|
|||
readonly filterErrors: boolean = false;
|
||||
readonly filterWarnings: boolean = false;
|
||||
readonly filterInfos: boolean = false;
|
||||
readonly excludePattern: ParsedExpression | null = null;
|
||||
readonly includePattern: ParsedExpression | null = null;
|
||||
readonly textFilter: string = '';
|
||||
readonly excludesMatcher: ResourceGlobMatcher;
|
||||
readonly includesMatcher: ResourceGlobMatcher;
|
||||
|
||||
constructor(readonly filter: string = '', excludePatterns: IExpression = {}) {
|
||||
constructor(readonly filter: string = '', filesExclude: { root: URI, expression: IExpression }[] | IExpression = []) {
|
||||
filter = filter.trim();
|
||||
for (const key of Object.keys(excludePatterns)) {
|
||||
if (excludePatterns[key]) {
|
||||
this.setPattern(excludePatterns, key);
|
||||
}
|
||||
delete excludePatterns[key];
|
||||
}
|
||||
const includePatterns: IExpression = getEmptyExpression();
|
||||
|
||||
const filesExcludeByRoot = Array.isArray(filesExclude) ? filesExclude : [];
|
||||
const excludesExpression: IExpression = Array.isArray(filesExclude) ? getEmptyExpression() : filesExclude;
|
||||
|
||||
const includeExpression: IExpression = getEmptyExpression();
|
||||
if (filter) {
|
||||
const filters = splitGlobAware(filter, ',').map(s => s.trim()).filter(s => !!s.length);
|
||||
for (const f of filters) {
|
||||
|
@ -36,19 +36,16 @@ export class FilterOptions {
|
|||
this.filterWarnings = this.filterWarnings || this.matches(f, Messages.MARKERS_PANEL_FILTER_WARNINGS);
|
||||
this.filterInfos = this.filterInfos || this.matches(f, Messages.MARKERS_PANEL_FILTER_INFOS);
|
||||
if (strings.startsWith(f, '!')) {
|
||||
this.setPattern(excludePatterns, strings.ltrim(f, '!'));
|
||||
this.setPattern(excludesExpression, strings.ltrim(f, '!'));
|
||||
} else {
|
||||
this.setPattern(includePatterns, f);
|
||||
this.setPattern(includeExpression, f);
|
||||
this.textFilter += ` ${f}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(excludePatterns).length) {
|
||||
this.excludePattern = parse(excludePatterns);
|
||||
}
|
||||
if (Object.keys(includePatterns).length) {
|
||||
this.includePattern = parse(includePatterns);
|
||||
}
|
||||
|
||||
this.excludesMatcher = new ResourceGlobMatcher(excludesExpression, filesExcludeByRoot);
|
||||
this.includesMatcher = new ResourceGlobMatcher(includeExpression, []);
|
||||
this.textFilter = this.textFilter.trim();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,9 @@ import { ITreeElement, ITreeNode, ITreeContextMenuEvent } from 'vs/base/browser/
|
|||
import { Relay, Event, Emitter } from 'vs/base/common/event';
|
||||
import { WorkbenchObjectTree, TreeResourceNavigator2 } from 'vs/platform/list/browser/listService';
|
||||
import { FilterOptions } from 'vs/workbench/contrib/markers/electron-browser/markersFilterOptions';
|
||||
import { IExpression, getEmptyExpression } from 'vs/base/common/glob';
|
||||
import { mixin, deepClone } from 'vs/base/common/objects';
|
||||
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { joinWithSlashes } from 'vs/base/common/extpath';
|
||||
import { isAbsolute } from 'vs/base/common/path';
|
||||
import { IExpression } from 'vs/base/common/glob';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewModel, ResourceDragAndDrop } from 'vs/workbench/contrib/markers/electron-browser/markersTreeViewer';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
@ -248,8 +246,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
|||
|
||||
private updateFilter() {
|
||||
this.cachedFilterStats = undefined;
|
||||
const excludeExpression = this.getExcludeExpression(this.filterAction.useFilesExclude);
|
||||
this.filter.options = new FilterOptions(this.filterAction.filterText, excludeExpression);
|
||||
this.filter.options = new FilterOptions(this.filterAction.filterText, this.getFilesExcludeExpressions());
|
||||
this.tree.refilter();
|
||||
this._onDidFilter.fire();
|
||||
|
||||
|
@ -258,44 +255,21 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
|||
this.renderMessage();
|
||||
}
|
||||
|
||||
private getExcludeExpression(useFilesExclude: boolean): IExpression {
|
||||
if (!useFilesExclude) {
|
||||
return {};
|
||||
private getFilesExcludeExpressions(): { root: URI, expression: IExpression }[] | IExpression {
|
||||
if (!this.filterAction.useFilesExclude) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const workspaceFolders = this.workspaceContextService.getWorkspace().folders;
|
||||
if (workspaceFolders.length) {
|
||||
const result = getEmptyExpression();
|
||||
for (const workspaceFolder of workspaceFolders) {
|
||||
mixin(result, this.getExcludesForFolder(workspaceFolder));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return this.getFilesExclude();
|
||||
}
|
||||
}
|
||||
|
||||
private getExcludesForFolder(workspaceFolder: IWorkspaceFolder): IExpression {
|
||||
const expression = this.getFilesExclude(workspaceFolder.uri);
|
||||
return this.getAbsoluteExpression(expression, workspaceFolder.uri.fsPath);
|
||||
return workspaceFolders.length
|
||||
? workspaceFolders.map(workspaceFolder => ({ root: workspaceFolder.uri, expression: this.getFilesExclude(workspaceFolder.uri) }))
|
||||
: this.getFilesExclude();
|
||||
}
|
||||
|
||||
private getFilesExclude(resource?: URI): IExpression {
|
||||
return deepClone(this.configurationService.getValue('files.exclude', { resource })) || {};
|
||||
}
|
||||
|
||||
private getAbsoluteExpression(expr: IExpression, root: string): IExpression {
|
||||
return Object.keys(expr)
|
||||
.reduce((absExpr: IExpression, key: string) => {
|
||||
if (expr[key] && !isAbsolute(key)) {
|
||||
const absPattern = joinWithSlashes(root, key);
|
||||
absExpr[absPattern] = expr[key];
|
||||
}
|
||||
|
||||
return absExpr;
|
||||
}, Object.create(null));
|
||||
}
|
||||
|
||||
private createMessageBox(parent: HTMLElement): void {
|
||||
this.messageBoxContainer = dom.append(parent, dom.$('.message-box-container'));
|
||||
this.messageBoxContainer.setAttribute('aria-labelledby', 'markers-panel-arialabel');
|
||||
|
@ -320,7 +294,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
|||
this.instantiationService.createInstance(MarkerRenderer, this.markersViewModel),
|
||||
this.instantiationService.createInstance(RelatedInformationRenderer)
|
||||
];
|
||||
this.filter = new Filter();
|
||||
this.filter = new Filter(new FilterOptions());
|
||||
const accessibilityProvider = this.instantiationService.createInstance(MarkersTreeAccessibilityProvider);
|
||||
|
||||
const identityProvider = {
|
||||
|
|
|
@ -406,7 +406,7 @@ export class RelatedInformationRenderer implements ITreeRenderer<RelatedInformat
|
|||
|
||||
export class Filter implements ITreeFilter<TreeElement, FilterData> {
|
||||
|
||||
options = new FilterOptions();
|
||||
constructor(public options: FilterOptions) { }
|
||||
|
||||
filter(element: TreeElement, parentVisibility: TreeVisibility): TreeFilterResult<FilterData> {
|
||||
if (element instanceof ResourceMarkers) {
|
||||
|
@ -423,7 +423,7 @@ export class Filter implements ITreeFilter<TreeElement, FilterData> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (this.options.excludePattern && !!this.options.excludePattern(resourceMarkers.resource.fsPath)) {
|
||||
if (this.options.excludesMatcher.matches(resourceMarkers.resource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -433,7 +433,7 @@ export class Filter implements ITreeFilter<TreeElement, FilterData> {
|
|||
return { visibility: true, data: { type: FilterDataType.ResourceMarkers, uriMatches } };
|
||||
}
|
||||
|
||||
if (this.options.includePattern && this.options.includePattern(resourceMarkers.resource.fsPath)) {
|
||||
if (this.options.includesMatcher.matches(resourceMarkers.resource)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue