提交 89906c07 编写于 作者: B Benjamin Pasero

quick access - apply configured excludes to symbols

上级 f44fbc59
......@@ -9,7 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { first } from 'vs/base/common/arrays';
import { startsWith } from 'vs/base/common/strings';
import { assertIsDefined } from 'vs/base/common/types';
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent } from 'vs/base/parts/quickinput/common/quickInput';
export interface IQuickAccessController {
......@@ -188,9 +188,11 @@ export interface IPickerQuickAccessItem extends IQuickPickItem {
trigger?(buttonIndex: number, keyMods: IKeyMods): TriggerAction | Promise<TriggerAction>;
}
export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem> implements IQuickAccessProvider {
export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem> extends Disposable implements IQuickAccessProvider {
constructor(private prefix: string) { }
constructor(private prefix: string) {
super();
}
provide(picker: IQuickPick<T>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
......
......@@ -113,8 +113,8 @@ export class ResourceGlobMatcher extends Disposable {
private readonly _onExpressionChange = this._register(new Emitter<void>());
readonly onExpressionChange = this._onExpressionChange.event;
private readonly mapRootToParsedExpression: Map<string | null, ParsedExpression> = new Map<string, ParsedExpression>();
private readonly mapRootToExpressionConfig: Map<string | null, IExpression> = new Map<string, IExpression>();
private readonly mapRootToParsedExpression = new Map<string | null, ParsedExpression>();
private readonly mapRootToExpressionConfig = new Map<string | null, IExpression>();
constructor(
private globFn: (root?: URI) => IExpression,
......
......@@ -13,7 +13,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IEditorInputFactory, EditorInput, IFileEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
import { AutoSaveConfiguration, HotExitConfiguration } from 'vs/platform/files/common/files';
import { AutoSaveConfiguration, HotExitConfiguration, FILES_EXCLUDE_CONFIG, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files';
import { VIEWLET_ID, SortOrder, FILE_EDITOR_INPUT_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
import { TextFileEditorTracker } from 'vs/workbench/contrib/files/browser/editors/textFileEditorTracker';
import { TextFileSaveErrorHandler } from 'vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler';
......@@ -202,9 +202,9 @@ configurationRegistry.registerConfiguration({
'title': nls.localize('filesConfigurationTitle', "Files"),
'type': 'object',
'properties': {
'files.exclude': {
[FILES_EXCLUDE_CONFIG]: {
'type': 'object',
'markdownDescription': nls.localize('exclude', "Configure glob patterns for excluding files and folders. For example, the files explorer decides which files and folders to show or hide based on this setting. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."),
'markdownDescription': nls.localize('exclude', "Configure glob patterns for excluding files and folders. For example, the files explorer decides which files and folders to show or hide based on this setting. Refer to the `#search.exclude#` setting to define search specific excludes. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."),
'default': { '**/.git': true, '**/.svn': true, '**/.hg': true, '**/CVS': true, '**/.DS_Store': true },
'scope': ConfigurationScope.RESOURCE,
'additionalProperties': {
......@@ -227,7 +227,7 @@ configurationRegistry.registerConfiguration({
]
}
},
'files.associations': {
[FILES_ASSOCIATIONS_CONFIG]: {
'type': 'object',
'markdownDescription': nls.localize('associations', "Configure file associations to languages (e.g. `\"*.extension\": \"html\"`). These have precedence over the default associations of the languages installed."),
},
......@@ -306,7 +306,7 @@ configurationRegistry.registerConfiguration({
'files.watcherExclude': {
'type': 'object',
'default': platform.isWindows /* https://github.com/Microsoft/vscode/issues/23954 */ ? { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/*/**': true, '**/.hg/store/**': true } : { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/**': true, '**/.hg/store/**': true },
'description': nls.localize('watcherExclude', "Configure glob patterns of file paths to exclude from file watching. Patterns must match on absolute paths (i.e. prefix with ** or the full path to match properly). Changing this setting requires a restart. When you experience Code consuming lots of cpu time on startup, you can exclude large folders to reduce the initial load."),
'description': nls.localize('watcherExclude', "Configure glob patterns of file paths to exclude from file watching. Patterns must match on absolute paths (i.e. prefix with ** or the full path to match properly). Changing this setting requires a restart. When you experience Code consuming lots of CPU time on startup, you can exclude large folders to reduce the initial load."),
'scope': ConfigurationScope.RESOURCE
},
'files.hotExit': hotExitConfiguration,
......
......@@ -47,7 +47,7 @@ import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search';
import { ISearchHistoryService, SearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService';
import { FileMatchOrMatch, ISearchWorkbenchService, RenderableMatch, SearchWorkbenchService, FileMatch, Match, FolderMatch } from 'vs/workbench/contrib/search/common/searchModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { VIEWLET_ID, VIEW_ID, SearchSortOrder } from 'vs/workbench/services/search/common/search';
import { VIEWLET_ID, VIEW_ID, SEARCH_EXCLUDE_CONFIG, SearchSortOrder } from 'vs/workbench/services/search/common/search';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ExplorerViewPaneContainer } from 'vs/workbench/contrib/files/browser/explorerViewlet';
......@@ -671,9 +671,9 @@ configurationRegistry.registerConfiguration({
title: nls.localize('searchConfigurationTitle', "Search"),
type: 'object',
properties: {
'search.exclude': {
[SEARCH_EXCLUDE_CONFIG]: {
type: 'object',
markdownDescription: nls.localize('exclude', "Configure glob patterns for excluding files and folders in searches. Inherits all glob patterns from the `#files.exclude#` setting. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."),
markdownDescription: nls.localize('exclude', "Configure glob patterns for excluding files and folders in fulltext searches and quick open. Inherits all glob patterns from the `#files.exclude#` setting. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."),
default: { '**/node_modules': true, '**/bower_components': true, '**/*.code-search': true },
additionalProperties: {
anyOf: [
......
......@@ -20,6 +20,9 @@ import { Range } from 'vs/editor/common/core/range';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
import { IKeyMods, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { createResourceExcludeMatcher } from 'vs/workbench/services/search/common/search';
import { ResourceMap } from 'vs/base/common/map';
interface ISymbolsQuickPickItem extends IPickerQuickAccessItem {
score: FuzzyScore;
......@@ -34,11 +37,14 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
private delayer = new ThrottledDelayer<ISymbolsQuickPickItem[]>(SymbolsQuickAccessProvider.TYPING_SEARCH_DELAY);
private readonly resourceExcludeMatcher = this._register(createResourceExcludeMatcher(this.instantiationService, this.configurationService));
constructor(
@ILabelService private readonly labelService: ILabelService,
@IOpenerService private readonly openerService: IOpenerService,
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super(SymbolsQuickAccessProvider.PREFIX);
}
......@@ -83,14 +89,21 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
// Convert to symbol picks and apply filtering
const openSideBySideDirection = this.configuration.openSideBySideDirection;
const symbolsExcludedByResource = new ResourceMap<boolean>();
for (const [provider, symbols] of workspaceSymbols) {
for (const symbol of symbols) {
// Score by symbol label
const symbolLabel = symbol.name;
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
const symbolScore = fuzzyScore(symbolFilter, symbolFilterLow, 0, symbolLabel, symbolLabel.toLowerCase(), 0, true);
if (!symbolScore) {
continue;
}
const symbolUri = symbol.location.uri;
let containerLabel: string | undefined = undefined;
if (symbol.location.uri) {
const containerPath = this.labelService.getUriLabel(symbol.location.uri, { relative: true });
if (symbolUri) {
const containerPath = this.labelService.getUriLabel(symbolUri, { relative: true });
if (symbol.containerName) {
containerLabel = `${symbol.containerName}${containerPath}`;
} else {
......@@ -98,14 +111,8 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}
}
// Score by symbol
const symbolScore = fuzzyScore(symbolFilter, symbolFilterLow, 0, symbolLabel, symbolLabel.toLowerCase(), 0, true);
let containerScore: FuzzyScore | undefined = undefined;
if (!symbolScore) {
continue;
}
// Score by container if specified
let containerScore: FuzzyScore | undefined = undefined;
if (containerFilter && containerFilterLow) {
if (containerLabel) {
containerScore = fuzzyScore(containerFilter, containerFilterLow, 0, containerLabel, containerLabel.toLowerCase(), 0, true);
......@@ -116,6 +123,20 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}
}
// Filter out symbols that match the global resource filter
if (symbolUri) {
let excludeSymbolByResource = symbolsExcludedByResource.get(symbolUri);
if (typeof excludeSymbolByResource === 'undefined') {
excludeSymbolByResource = this.resourceExcludeMatcher.matches(symbolUri);
symbolsExcludedByResource.set(symbolUri, excludeSymbolByResource);
}
if (excludeSymbolByResource) {
continue;
}
}
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
const deprecated = symbol.tags ? symbol.tags.indexOf(SymbolTag.Deprecated) >= 0 : false;
symbolPicks.push({
......
......@@ -9,21 +9,19 @@ import { ITextEditorOptions, IResourceEditorInput, TextEditorSelectionRevealType
import { IEditorInput, IEditorPane, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, IEditorIdentifier, GroupIdentifier, EditorsOrder } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { FileChangesEvent, IFileService, FileChangeType, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files';
import { FileChangesEvent, IFileService, FileChangeType } from 'vs/platform/files/common/files';
import { Selection } from 'vs/editor/common/core/selection';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { Registry } from 'vs/platform/registry/common/platform';
import { Event } from 'vs/base/common/event';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { getCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { getExcludes, ISearchConfiguration } from 'vs/workbench/services/search/common/search';
import { IExpression } from 'vs/base/common/glob';
import { createResourceExcludeMatcher } from 'vs/workbench/services/search/common/search';
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ResourceGlobMatcher } from 'vs/workbench/common/resources';
import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
......@@ -98,8 +96,8 @@ export class HistoryService extends Disposable implements IHistoryService {
private readonly activeEditorListeners = this._register(new DisposableStore());
private lastActiveEditor?: IEditorIdentifier;
private readonly editorHistoryListeners: Map<EditorInput, DisposableStore> = new Map();
private readonly editorStackListeners: Map<EditorInput, DisposableStore> = new Map();
private readonly editorHistoryListeners = new Map();
private readonly editorStackListeners = new Map();
constructor(
@IEditorService private readonly editorService: EditorServiceImpl,
......@@ -124,7 +122,7 @@ export class HistoryService extends Disposable implements IHistoryService {
this._register(this.editorService.onDidCloseEditor(event => this.onEditorClosed(event)));
this._register(this.storageService.onWillSaveState(() => this.saveState()));
this._register(this.fileService.onDidFilesChange(event => this.onDidFilesChange(event)));
this._register(this.resourceFilter.onExpressionChange(() => this.removeExcludedFromHistory()));
this._register(this.resourceExcludeMatcher.onExpressionChange(() => this.removeExcludedFromHistory()));
this._register(this.editorService.onDidMostRecentlyActiveEditorsChange(() => this.handleEditorEventInRecentEditorsStack()));
// if the service is created late enough that an editor is already opened
......@@ -718,17 +716,7 @@ export class HistoryService extends Disposable implements IHistoryService {
private history: Array<IEditorInput | IResourceEditorInput> | undefined = undefined;
private readonly resourceFilter = this._register(this.instantiationService.createInstance(
ResourceGlobMatcher,
(root?: URI) => this.getExcludes(root),
(event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) || event.affectsConfiguration('search.exclude')
));
private getExcludes(root?: URI): IExpression {
const scope = root ? { resource: root } : undefined;
return getExcludes(scope ? this.configurationService.getValue<ISearchConfiguration>(scope) : this.configurationService.getValue<ISearchConfiguration>())!;
}
private readonly resourceExcludeMatcher = this._register(createResourceExcludeMatcher(this.instantiationService, this.configurationService));
private handleEditorEventInHistory(editor?: IEditorPane): void {
......@@ -764,7 +752,7 @@ export class HistoryService extends Disposable implements IHistoryService {
const resourceEditorInput = input as IResourceEditorInput;
return !this.resourceFilter.matches(resourceEditorInput.resource);
return !this.resourceExcludeMatcher.matches(resourceEditorInput.resource);
}
private removeExcludedFromHistory(): void {
......
......@@ -11,16 +11,20 @@ import * as objects from 'vs/base/common/objects';
import * as extpath from 'vs/base/common/extpath';
import { fuzzyContains, getNLines } from 'vs/base/common/strings';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IFilesConfiguration } from 'vs/platform/files/common/files';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IFilesConfiguration, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { Event } from 'vs/base/common/event';
import { relative } from 'vs/base/common/path';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ResourceGlobMatcher } from 'vs/workbench/common/resources';
export const VIEWLET_ID = 'workbench.view.search';
export const PANEL_ID = 'workbench.panel.search';
export const VIEW_ID = 'workbench.view.search';
export const SEARCH_EXCLUDE_CONFIG = 'search.exclude';
export const ISearchService = createDecorator<ISearchService>('searchService');
/**
......@@ -372,6 +376,14 @@ export function getExcludes(configuration: ISearchConfiguration, includeSearchEx
return allExcludes;
}
export function createResourceExcludeMatcher(instantiationService: IInstantiationService, configurationService: IConfigurationService): ResourceGlobMatcher {
return instantiationService.createInstance(
ResourceGlobMatcher,
root => getExcludes(root ? configurationService.getValue<ISearchConfiguration>({ resource: root }) : configurationService.getValue<ISearchConfiguration>()) || Object.create(null),
event => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) || event.affectsConfiguration(SEARCH_EXCLUDE_CONFIG)
);
}
export function pathIncludedInQuery(queryProps: ICommonQueryProps<URI>, fsPath: string): boolean {
if (queryProps.excludePattern && glob.match(queryProps.excludePattern, fsPath)) {
return false;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册