src/vs/workbench/contrib/markers/browser/markersFilterOptions.ts/FilterOptions/constructor
class FilterOptions:	constructor(
		readonly filter: string,
		filesExclude: { root: URI, expression: IExpression }[] | IExpression,
		showWarnings: boolean,
		showErrors: boolean,
		showInfos: boolean,
		uriIdentityService: IUriIdentityService
	) {
		filter = filter.trim();
		this.showWarnings = showWarnings;
		this.showErrors = showErrors;
		this.showInfos = showInfos;

		const filesExcludeByRoot = Array.isArray(filesExclude) ? filesExclude : [];
		const excludesExpression: IExpression = Array.isArray(filesExclude) ? getEmptyExpression() : filesExclude;

		for (const { expression } of filesExcludeByRoot) {
			for (const pattern of Object.keys(expression)) {
				if (!pattern.endsWith('/**')) {
					// Append `/**` to pattern to match a parent folder #103631
					expression[`${strings.rtrim(pattern, '/')}/**`] = expression[pattern];
				}
			}
		}

		const negate = filter.startsWith('!');
		this.textFilter = { text: (negate ? strings.ltrim(filter, '!') : filter).trim(), negate };
		const includeExpression: IExpression = getEmptyExpression();

		if (filter) {
			const filters = splitGlobAware(filter, ',').map(s => s.trim()).filter(s => !!s.length);
			for (const f of filters) {
				if (f.startsWith('!')) {
					const filterText = strings.ltrim(f, '!');
					if (filterText) {
						this.setPattern(excludesExpression, filterText);
					}
				} else {
					this.setPattern(includeExpression, f);
				}
			}
		}

		this.excludesMatcher = new ResourceGlobMatcher(excludesExpression, filesExcludeByRoot, uriIdentityService);
		this.includesMatcher = new ResourceGlobMatcher(includeExpression, [], uriIdentityService);
	}