diff --git a/src/commands/git/search.ts b/src/commands/git/search.ts index dc83ae7..6773188 100644 --- a/src/commands/git/search.ts +++ b/src/commands/git/search.ts @@ -5,8 +5,8 @@ import { getContext } from '../../context'; import type { GitCommit } from '../../git/models/commit'; import type { GitLog } from '../../git/models/log'; import type { Repository } from '../../git/models/repository'; -import type { SearchOperators } from '../../git/search'; -import { searchOperators, SearchPattern } from '../../git/search'; +import type { SearchOperators, SearchPattern } from '../../git/search'; +import { getKeyForSearchPattern, parseSearchOperations, searchOperators } from '../../git/search'; import type { QuickPickItemOfT } from '../../quickpicks/items/common'; import { ActionQuickPickItem } from '../../quickpicks/items/common'; import { pluralize } from '../../system/string'; @@ -166,7 +166,7 @@ export class SearchGitCommand extends QuickCommand { matchCase: state.matchCase, matchRegex: state.matchRegex, }; - const searchKey = SearchPattern.toKey(search); + const searchKey = getKeyForSearchPattern(search); if (context.resultsPromise == null || context.resultsKey !== searchKey) { context.resultsPromise = state.repo.searchForCommits(search); @@ -351,7 +351,7 @@ export class SearchGitCommand extends QuickCommand { // Simulate an extra step if we have a value state.counter = value ? 3 : 2; - const operations = SearchPattern.parseSearchOperations(value); + const operations = parseSearchOperations(value); quickpick.title = appendReposToTitle( operations.size === 0 || operations.size > 1 diff --git a/src/commands/showCommitsInView.ts b/src/commands/showCommitsInView.ts index 59f219a..3c2df1f 100644 --- a/src/commands/showCommitsInView.ts +++ b/src/commands/showCommitsInView.ts @@ -3,7 +3,7 @@ import { executeGitCommand } from '../commands/gitCommands.actions'; import { Commands } from '../constants'; import type { Container } from '../container'; import { GitUri } from '../git/gitUri'; -import { SearchPattern } from '../git/search'; +import { getSearchPatternFromCommits } from '../git/search'; import { Logger } from '../logger'; import { showFileNotUnderSourceControlWarningMessage, showGenericErrorMessage } from '../messages'; import { command } from '../system/command'; @@ -88,7 +88,7 @@ export class ShowCommitsInViewCommand extends ActiveEditorCommand { command: 'search', state: { repo: args?.repoPath, - pattern: SearchPattern.fromCommits(args.refs), + pattern: getSearchPatternFromCommits(args.refs), showResultsInSideBar: true, }, }); diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 163756c..d86ccdd 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -106,7 +106,8 @@ import type { RemoteProvider } from '../../../git/remotes/remoteProvider'; import type { RemoteProviders } from '../../../git/remotes/remoteProviders'; import { getRemoteProviderMatcher, loadRemoteProviders } from '../../../git/remotes/remoteProviders'; import type { RichRemoteProvider } from '../../../git/remotes/richRemoteProvider'; -import { SearchPattern } from '../../../git/search'; +import type { SearchPattern } from '../../../git/search'; +import { parseSearchOperations } from '../../../git/search'; import { Logger } from '../../../logger'; import type { LogScope } from '../../../logger'; import { @@ -2657,7 +2658,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const limit = options?.limit ?? configuration.get('advanced.maxSearchItems') ?? 0; const similarityThreshold = configuration.get('advanced.similarityThreshold'); - const operations = SearchPattern.parseSearchOperations(search.pattern); + const operations = parseSearchOperations(search.pattern); const searchArgs = new Set(); const files: string[] = []; diff --git a/src/git/search.ts b/src/git/search.ts index 6d59938..c55aff9 100644 --- a/src/git/search.ts +++ b/src/git/search.ts @@ -35,72 +35,70 @@ export interface SearchPattern { matchRegex?: boolean; } -export namespace SearchPattern { - const normalizeSearchOperatorsMap = new Map([ - ['', 'message:'], - ['=:', 'message:'], - ['message:', 'message:'], - ['@:', 'author:'], - ['author:', 'author:'], - ['#:', 'commit:'], - ['commit:', 'commit:'], - ['?:', 'file:'], - ['file:', 'file:'], - ['~:', 'change:'], - ['change:', 'change:'], - ]); +export function getKeyForSearchPattern(search: SearchPattern) { + return `${search.pattern}|${search.matchAll ? 'A' : ''}${search.matchCase ? 'C' : ''}${ + search.matchRegex ? 'R' : '' + }`; +} - const searchOperationRegex = - /(?:(?=:|message:|@:|author:|#:|commit:|\?:|file:|~:|change:)\s?(?".+?"|\S+\b}?))|(?\S+)(?!(?:=|message|@|author|#|commit|\?|file|~|change):)/gi; +export function getSearchPatternFromCommit(ref: string): string; +export function getSearchPatternFromCommit(commit: GitRevisionReference): string; +export function getSearchPatternFromCommit(refOrCommit: string | GitRevisionReference) { + return `#:${typeof refOrCommit === 'string' ? GitRevision.shorten(refOrCommit) : refOrCommit.name}`; +} - export function fromCommit(ref: string): string; - export function fromCommit(commit: GitRevisionReference): string; - export function fromCommit(refOrCommit: string | GitRevisionReference) { - return `#:${typeof refOrCommit === 'string' ? GitRevision.shorten(refOrCommit) : refOrCommit.name}`; - } +export function getSearchPatternFromCommits(refs: string[]): string; +export function getSearchPatternFromCommits(commits: GitRevisionReference[]): string; +export function getSearchPatternFromCommits(refsOrCommits: (string | GitRevisionReference)[]) { + return refsOrCommits.map(r => `#:${typeof r === 'string' ? GitRevision.shorten(r) : r.name}`).join(' '); +} - export function fromCommits(refs: string[]): string; - export function fromCommits(commits: GitRevisionReference[]): string; - export function fromCommits(refsOrCommits: (string | GitRevisionReference)[]) { - return refsOrCommits.map(r => `#:${typeof r === 'string' ? GitRevision.shorten(r) : r.name}`).join(' '); - } +const normalizeSearchOperatorsMap = new Map([ + ['', 'message:'], + ['=:', 'message:'], + ['message:', 'message:'], + ['@:', 'author:'], + ['author:', 'author:'], + ['#:', 'commit:'], + ['commit:', 'commit:'], + ['?:', 'file:'], + ['file:', 'file:'], + ['~:', 'change:'], + ['change:', 'change:'], +]); - export function parseSearchOperations(search: string): Map { - const operations = new Map(); +const searchOperationRegex = + /(?:(?=:|message:|@:|author:|#:|commit:|\?:|file:|~:|change:)\s?(?".+?"|\S+\b}?))|(?\S+)(?!(?:=|message|@|author|#|commit|\?|file|~|change):)/gi; - let op: SearchOperators | undefined; - let value: string | undefined; - let text: string | undefined; +export function parseSearchOperations(search: string): Map { + const operations = new Map(); - let match; - do { - match = searchOperationRegex.exec(search); - if (match?.groups == null) break; + let op: SearchOperators | undefined; + let value: string | undefined; + let text: string | undefined; - op = normalizeSearchOperatorsMap.get(match.groups.op as SearchOperators); - ({ value, text } = match.groups); + let match; + do { + match = searchOperationRegex.exec(search); + if (match?.groups == null) break; - if (text) { - op = GitRevision.isSha(text) ? 'commit:' : 'message:'; - value = text; - } + op = normalizeSearchOperatorsMap.get(match.groups.op as SearchOperators); + ({ value, text } = match.groups); - if (op && value) { - const values = operations.get(op); - if (values == null) { - operations.set(op, [value]); - } else { - values.push(value); - } - } - } while (match != null); + if (text) { + op = GitRevision.isSha(text) ? 'commit:' : 'message:'; + value = text; + } - return operations; - } + if (op && value) { + const values = operations.get(op); + if (values == null) { + operations.set(op, [value]); + } else { + values.push(value); + } + } + } while (match != null); - export function toKey(search: SearchPattern) { - return `${search.pattern}|${search.matchAll ? 'A' : ''}${search.matchCase ? 'C' : ''}${ - search.matchRegex ? 'R' : '' - }`; - } + return operations; } diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 7fb092b..ac2235e 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -72,7 +72,8 @@ import type { RemoteProvider } from '../../git/remotes/remoteProvider'; import type { RemoteProviders } from '../../git/remotes/remoteProviders'; import { getRemoteProviderMatcher, loadRemoteProviders } from '../../git/remotes/remoteProviders'; import type { RichRemoteProvider } from '../../git/remotes/richRemoteProvider'; -import { SearchPattern } from '../../git/search'; +import type { SearchPattern } from '../../git/search'; +import { parseSearchOperations } from '../../git/search'; import type { LogScope } from '../../logger'; import { Logger } from '../../logger'; import { gate } from '../../system/decorators/gate'; @@ -1589,7 +1590,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { const scope = getLogScope(); - const operations = SearchPattern.parseSearchOperations(search.pattern); + const operations = parseSearchOperations(search.pattern); let op; let values = operations.get('commit:'); diff --git a/src/views/nodes/searchResultsNode.ts b/src/views/nodes/searchResultsNode.ts index 3a0dbee..fdd1c95 100644 --- a/src/views/nodes/searchResultsNode.ts +++ b/src/views/nodes/searchResultsNode.ts @@ -3,7 +3,8 @@ import { ThemeIcon } from 'vscode'; import { executeGitCommand } from '../../commands/gitCommands.actions'; import { GitUri } from '../../git/gitUri'; import type { GitLog } from '../../git/models/log'; -import { SearchPattern } from '../../git/search'; +import type { SearchPattern } from '../../git/search'; +import { getKeyForSearchPattern } from '../../git/search'; import { gate } from '../../system/decorators/gate'; import { debug, log } from '../../system/decorators/log'; import { md5, pluralize } from '../../system/string'; @@ -27,12 +28,12 @@ export class SearchResultsNode extends ViewNode implements static key = ':search-results'; static getId(repoPath: string, search: SearchPattern | undefined, instanceId: number): string { return `${RepositoryNode.getId(repoPath)}${this.key}(${ - search == null ? '?' : SearchPattern.toKey(search) + search == null ? '?' : getKeyForSearchPattern(search) }):${instanceId}`; } static getPinnableId(repoPath: string, search: SearchPattern) { - return md5(`${repoPath}|${SearchPattern.toKey(search)}`); + return md5(`${repoPath}|${getKeyForSearchPattern(search)}`); } private _instanceId: number;