Browse Source

Renames SearchPattern to SearchQuery

Renames more to hasMore
main
Eric Amodio 2 years ago
parent
commit
954a3be68d
19 changed files with 244 additions and 222 deletions
  1. +17
    -17
      src/commands/git/search.ts
  2. +2
    -2
      src/commands/searchCommits.ts
  3. +2
    -2
      src/commands/showCommitsInView.ts
  4. +19
    -96
      src/env/node/git/localGitProvider.ts
  5. +3
    -3
      src/git/gitProvider.ts
  6. +3
    -3
      src/git/gitProviderService.ts
  7. +1
    -1
      src/git/models/graph.ts
  8. +3
    -3
      src/git/models/repository.ts
  9. +116
    -16
      src/git/search.ts
  10. +9
    -9
      src/plus/github/githubGitProvider.ts
  11. +8
    -15
      src/plus/webviews/graph/graphWebview.ts
  12. +6
    -11
      src/plus/webviews/graph/protocol.ts
  13. +2
    -2
      src/storage.ts
  14. +11
    -11
      src/views/nodes/searchResultsNode.ts
  15. +12
    -3
      src/views/searchAndCompareView.ts
  16. +18
    -18
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  17. +5
    -5
      src/webviews/apps/plus/graph/graph.tsx
  18. +5
    -3
      src/webviews/apps/shared/components/search/search-field.ts
  19. +2
    -2
      src/webviews/rebase/rebaseEditor.ts

+ 17
- 17
src/commands/git/search.ts View File

@ -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, SearchPattern } from '../../git/search';
import { getSearchPatternComparisonKey, parseSearchOperations, searchOperators } from '../../git/search';
import type { SearchOperators, SearchQuery } from '../../git/search';
import { getSearchQueryComparisonKey, parseSearchQuery, searchOperators } from '../../git/search';
import type { QuickPickItemOfT } from '../../quickpicks/items/common';
import { ActionQuickPickItem } from '../../quickpicks/items/common';
import { pluralize } from '../../system/string';
@ -34,7 +34,7 @@ interface Context {
title: string;
}
interface State extends Required<SearchPattern> {
interface State extends Required<SearchQuery> {
repo: string | Repository;
openPickInView?: boolean;
showResultsInSideBar: boolean | SearchResultsNode;
@ -73,7 +73,7 @@ export class SearchGitCommand extends QuickCommand {
counter++;
}
if (args?.state?.pattern != null && !args.prefillOnly) {
if (args?.state?.query != null && !args.prefillOnly) {
counter++;
}
@ -144,7 +144,7 @@ export class SearchGitCommand extends QuickCommand {
}
}
if (state.counter < 2 || state.pattern == null) {
if (state.counter < 2 || state.query == null) {
const result = yield* this.pickSearchOperatorStep(state as SearchStepState, context);
if (result === StepResult.Break) {
// If we skipped the previous step, make sure we back up past it
@ -152,21 +152,21 @@ export class SearchGitCommand extends QuickCommand {
state.counter--;
}
state.pattern = undefined;
state.query = undefined;
continue;
}
state.pattern = result;
state.query = result;
}
const search: SearchPattern = {
pattern: state.pattern,
const search: SearchQuery = {
query: state.query,
matchAll: state.matchAll,
matchCase: state.matchCase,
matchRegex: state.matchRegex,
};
const searchKey = getSearchPatternComparisonKey(search);
const searchKey = getSearchQueryComparisonKey(search);
if (context.resultsPromise == null || context.resultsKey !== searchKey) {
context.resultsPromise = state.repo.searchForCommits(search);
@ -178,7 +178,7 @@ export class SearchGitCommand extends QuickCommand {
state.repo.path,
search,
{
label: { label: `for ${state.pattern}` },
label: { label: `for ${state.query}` },
},
context.resultsPromise,
state.showResultsInSideBar instanceof SearchResultsNode ? state.showResultsInSideBar : undefined,
@ -195,10 +195,10 @@ export class SearchGitCommand extends QuickCommand {
onDidLoadMore: log => (context.resultsPromise = Promise.resolve(log)),
placeholder: (context, log) =>
log == null
? `No results for ${state.pattern}`
? `No results for ${state.query}`
: `${pluralize('result', log.count, {
format: c => (log.hasMore ? `${c}+` : undefined),
})} for ${state.pattern}`,
})} for ${state.query}`,
picked: context.commit?.ref,
showInSideBarCommand: new ActionQuickPickItem(
'$(link-external) Show Results in Side Bar',
@ -207,7 +207,7 @@ export class SearchGitCommand extends QuickCommand {
repoPath,
search,
{
label: { label: `for ${state.pattern}` },
label: { label: `for ${state.query}` },
reveal: {
select: true,
focus: false,
@ -224,7 +224,7 @@ export class SearchGitCommand extends QuickCommand {
repoPath,
search,
{
label: { label: `for ${state.pattern}` },
label: { label: `for ${state.query}` },
reveal: {
select: true,
focus: false,
@ -317,7 +317,7 @@ export class SearchGitCommand extends QuickCommand {
matchOnDetail: true,
additionalButtons: [matchCaseButton, matchAllButton, matchRegexButton],
items: items,
value: state.pattern,
value: state.query,
selectValueWhenShown: false,
onDidAccept: (quickpick): boolean => {
const pick = quickpick.selectedItems[0];
@ -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 = parseSearchOperations(value);
const operations = parseSearchQuery(value);
quickpick.title = appendReposToTitle(
operations.size === 0 || operations.size > 1

+ 2
- 2
src/commands/searchCommits.ts View File

@ -2,14 +2,14 @@ import { executeGitCommand } from '../commands/gitCommands.actions';
import { configuration } from '../configuration';
import { Commands } from '../constants';
import type { Container } from '../container';
import type { SearchPattern } from '../git/search';
import type { SearchQuery } from '../git/search';
import { command } from '../system/command';
import { SearchResultsNode } from '../views/nodes/searchResultsNode';
import type { CommandContext } from './base';
import { Command, isCommandContextViewNodeHasRepository } from './base';
export interface SearchCommitsCommandArgs {
search?: Partial<SearchPattern>;
search?: Partial<SearchQuery>;
repoPath?: string;
prefillOnly?: boolean;

+ 2
- 2
src/commands/showCommitsInView.ts View File

@ -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 { getSearchPatternFromCommits } from '../git/search';
import { createSearchQueryForCommits } 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: getSearchPatternFromCommits(args.refs),
query: createSearchQueryForCommits(args.refs),
showResultsInSideBar: true,
},
});

+ 19
- 96
src/env/node/git/localGitProvider.ts View File

@ -106,8 +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 type { GitSearch, SearchPattern } from '../../../git/search';
import { getSearchPatternComparisonKey, parseSearchOperations } from '../../../git/search';
import type { GitSearch, SearchQuery } from '../../../git/search';
import { getGitArgsFromSearchQuery, getSearchQueryComparisonKey } from '../../../git/search';
import { Logger } from '../../../logger';
import type { LogScope } from '../../../logger';
import {
@ -155,7 +155,6 @@ const RepoSearchWarnings = {
doesNotExist: /no such file or directory/i,
};
const doubleQuoteRegex = /"/g;
const driveLetterRegex = /(?<=^\/?)([a-zA-Z])(?=:\/)/;
const userConfigRegex = /^user\.(name|email) (.*)$/gm;
const mappedAuthorRegex = /(.+)\s<(.+)>/;
@ -1859,7 +1858,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
paging: {
limit: limit === 0 ? count : limit,
startingCursor: startingCursor,
more: count > limit,
hasMore: count > limit,
},
more: async (limit: number, sha?: string): Promise<GitGraph | undefined> =>
getCommitsForGraphCore.call(this, limit, sha, cursor),
@ -2640,20 +2639,20 @@ export class LocalGitProvider implements GitProvider, Disposable {
@log()
async searchForCommitsSimple(
repoPath: string,
search: SearchPattern,
search: SearchQuery,
options?: { cancellation?: CancellationToken; limit?: number; ordering?: 'date' | 'author-date' | 'topo' },
): Promise<GitSearch> {
search = { matchAll: false, matchCase: false, matchRegex: true, ...search };
const comparisonKey = getSearchPatternComparisonKey(search);
const comparisonKey = getSearchQueryComparisonKey(search);
try {
const { args: searchArgs, files, commits } = this.getArgsFromSearchPattern(search);
if (commits?.size) {
const { args: searchArgs, files, shas } = getGitArgsFromSearchQuery(search);
if (shas?.size) {
return {
repoPath: repoPath,
pattern: search,
query: search,
comparisonKey: comparisonKey,
results: commits,
results: shas,
};
}
@ -2683,7 +2682,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
if (options?.cancellation?.isCancellationRequested) {
// TODO@eamodio: Should we throw an error here?
return { repoPath: repoPath, pattern: search, comparisonKey: comparisonKey, results: results };
return { repoPath: repoPath, query: search, comparisonKey: comparisonKey, results: results };
}
const data = await this.git.log2(
@ -2699,7 +2698,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
if (options?.cancellation?.isCancellationRequested) {
// TODO@eamodio: Should we throw an error here?
return { repoPath: repoPath, pattern: search, comparisonKey: comparisonKey, results: results };
return { repoPath: repoPath, query: search, comparisonKey: comparisonKey, results: results };
}
let count = 0;
@ -2722,15 +2721,14 @@ export class LocalGitProvider implements GitProvider, Disposable {
return {
repoPath: repoPath,
pattern: search,
query: search,
comparisonKey: comparisonKey,
results: results,
paging:
limit !== 0 && count > limit
? {
limit: limit,
startingCursor: cursor?.sha,
more: true,
hasMore: true,
}
: undefined,
more: async (limit: number): Promise<GitSearch> => searchForCommitsCore.call(this, limit, cursor),
@ -2740,10 +2738,10 @@ export class LocalGitProvider implements GitProvider, Disposable {
return searchForCommitsCore.call(this, limit);
} catch (ex) {
// TODO@eamodio: Should we throw an error here?
// TODO@eamodio handle error reporting -- just invalid patterns? or more detailed?
// TODO@eamodio handle error reporting -- just invalid queries? or more detailed?
return {
repoPath: repoPath,
pattern: search,
query: search,
comparisonKey: comparisonKey,
results: new Set<string>(),
};
@ -2753,7 +2751,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
@log()
async getLogForSearch(
repoPath: string,
search: SearchPattern,
search: SearchQuery,
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null; skip?: number },
): Promise<GitLog | undefined> {
search = { matchAll: false, matchCase: false, matchRegex: true, ...search };
@ -2762,7 +2760,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const limit = options?.limit ?? configuration.get('advanced.maxSearchItems') ?? 0;
const similarityThreshold = configuration.get('advanced.similarityThreshold');
const { args, files, commits } = this.getArgsFromSearchPattern(search);
const { args, files, shas } = getGitArgsFromSearchQuery(search);
args.push(`-M${similarityThreshold == null ? '' : `${similarityThreshold}%`}`, '--');
if (files.length !== 0) {
@ -2773,7 +2771,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
ordering: configuration.get('advanced.commitOrdering'),
...options,
limit: limit,
useShow: Boolean(commits?.size),
useShow: Boolean(shas?.size),
});
const log = GitLogParser.parse(
this.container,
@ -2802,84 +2800,9 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
}
private getArgsFromSearchPattern(search: SearchPattern): {
args: string[];
files: string[];
commits?: Set<string> | undefined;
} {
const operations = parseSearchOperations(search.pattern);
const searchArgs = new Set<string>();
const files: string[] = [];
let commits;
let op;
let values = operations.get('commit:');
if (values != null) {
// searchArgs.add('-m');
for (const value of values) {
searchArgs.add(value.replace(doubleQuoteRegex, ''));
}
commits = searchArgs;
} else {
searchArgs.add('--all');
searchArgs.add('--full-history');
searchArgs.add(search.matchRegex ? '--extended-regexp' : '--fixed-strings');
if (search.matchRegex && !search.matchCase) {
searchArgs.add('--regexp-ignore-case');
}
for ([op, values] of operations.entries()) {
switch (op) {
case 'message:':
searchArgs.add('-m');
if (search.matchAll) {
searchArgs.add('--all-match');
}
for (const value of values) {
searchArgs.add(`--grep=${value.replace(doubleQuoteRegex, search.matchRegex ? '\\b' : '')}`);
}
break;
case 'author:':
searchArgs.add('-m');
for (const value of values) {
searchArgs.add(
`--author=${value.replace(doubleQuoteRegex, search.matchRegex ? '\\b' : '')}`,
);
}
break;
case 'change:':
for (const value of values) {
searchArgs.add(
search.matchRegex
? `-G${value.replace(doubleQuoteRegex, '')}`
: `-S${value.replace(doubleQuoteRegex, '')}`,
);
}
break;
case 'file:':
for (const value of values) {
files.push(value.replace(doubleQuoteRegex, ''));
}
break;
}
}
}
return { args: [...searchArgs.values()], files: files, commits: commits };
}
private getLogForSearchMoreFn(
log: GitLog,
search: SearchPattern,
search: SearchQuery,
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null },
): (limit: number | undefined) => Promise<GitLog> {
return async (limit: number | undefined) => {

+ 3
- 3
src/git/gitProvider.ts View File

@ -26,7 +26,7 @@ import type { GitWorktree } from './models/worktree';
import type { RemoteProvider } from './remotes/remoteProvider';
import type { RemoteProviders } from './remotes/remoteProviders';
import type { RichRemoteProvider } from './remotes/richRemoteProvider';
import type { GitSearch, SearchPattern } from './search';
import type { GitSearch, SearchQuery } from './search';
export const enum GitProviderId {
Git = 'git',
@ -298,12 +298,12 @@ export interface GitProvider extends Disposable {
): Promise<Set<string> | undefined>;
searchForCommitsSimple(
repoPath: string | Uri,
search: SearchPattern,
search: SearchQuery,
options?: { cancellation?: CancellationToken; limit?: number; ordering?: 'date' | 'author-date' | 'topo' },
): Promise<GitSearch>;
getLogForSearch(
repoPath: string,
search: SearchPattern,
search: SearchQuery,
options?: {
limit?: number | undefined;
ordering?: 'date' | 'author-date' | 'topo' | null | undefined;

+ 3
- 3
src/git/gitProviderService.ts View File

@ -70,7 +70,7 @@ import type { GitWorktree } from './models/worktree';
import { RichRemoteProviders } from './remotes/remoteProviderConnections';
import type { RemoteProviders } from './remotes/remoteProviders';
import type { RichRemoteProvider } from './remotes/richRemoteProvider';
import type { GitSearch, SearchPattern } from './search';
import type { GitSearch, SearchQuery } from './search';
const maxDefaultBranchWeight = 100;
const weightedDefaultBranches = new Map<string, number>([
@ -1468,7 +1468,7 @@ export class GitProviderService implements Disposable {
@log()
searchForCommitsSimple(
repoPath: string | Uri,
search: SearchPattern,
search: SearchQuery,
options?: { cancellation?: CancellationToken; limit?: number; ordering?: 'date' | 'author-date' | 'topo' },
): Promise<GitSearch> {
const { provider, path } = this.getProvider(repoPath);
@ -1478,7 +1478,7 @@ export class GitProviderService implements Disposable {
@log()
async getLogForSearch(
repoPath: string | Uri,
search: SearchPattern,
search: SearchQuery,
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null; skip?: number },
): Promise<GitLog | undefined> {
const { provider, path } = this.getProvider(repoPath);

+ 1
- 1
src/git/models/graph.ts View File

@ -32,7 +32,7 @@ export interface GitGraph {
readonly paging?: {
readonly limit: number | undefined;
readonly startingCursor: string | undefined;
readonly more: boolean;
readonly hasMore: boolean;
};
more?(limit: number, sha?: string): Promise<GitGraph | undefined>;

+ 3
- 3
src/git/models/repository.ts View File

@ -23,7 +23,7 @@ import type { GitProviderDescriptor } from '../gitProvider';
import { loadRemoteProviders } from '../remotes/remoteProviders';
import type { RemoteProviders } from '../remotes/remoteProviders';
import type { RichRemoteProvider } from '../remotes/richRemoteProvider';
import type { GitSearch, SearchPattern } from '../search';
import type { GitSearch, SearchQuery } from '../search';
import type { BranchSortOptions, GitBranch } from './branch';
import { getBranchNameWithoutRemote, getRemoteNameFromBranchName } from './branch';
import type { GitCommit } from './commit';
@ -853,14 +853,14 @@ export class Repository implements Disposable {
}
searchForCommits(
search: SearchPattern,
search: SearchQuery,
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo'; skip?: number },
): Promise<GitLog | undefined> {
return this.container.git.getLogForSearch(this.path, search, options);
}
searchForCommitsSimple(
search: SearchPattern,
search: SearchQuery,
options?: { cancellation?: CancellationToken; limit?: number; ordering?: 'date' | 'author-date' | 'topo' },
): Promise<GitSearch> {
return this.container.git.searchForCommitsSimple(this.path, search, options);

+ 116
- 16
src/git/search.ts View File

@ -28,7 +28,15 @@ export const searchOperators = new Set([
'change:',
]);
export interface SearchPattern {
export interface SearchQuery {
query: string;
matchAll?: boolean;
matchCase?: boolean;
matchRegex?: boolean;
}
// Don't change this shape as it is persisted in storage
export interface StoredSearchQuery {
pattern: string;
matchAll?: boolean;
matchCase?: boolean;
@ -37,34 +45,51 @@ export interface SearchPattern {
export interface GitSearch {
repoPath: string;
pattern: SearchPattern;
query: SearchQuery;
comparisonKey: string;
results: Set<string>;
readonly paging?: {
readonly limit: number | undefined;
readonly startingCursor: string | undefined;
readonly more: boolean;
readonly hasMore: boolean;
};
more?(limit: number): Promise<GitSearch>;
}
export function getSearchPatternComparisonKey(search: SearchPattern) {
return `${search.pattern}|${search.matchAll ? 'A' : ''}${search.matchCase ? 'C' : ''}${
search.matchRegex ? 'R' : ''
}`;
export function getSearchQuery(search: StoredSearchQuery): SearchQuery {
return {
query: search.pattern,
matchAll: search.matchAll,
matchCase: search.matchCase,
matchRegex: search.matchRegex,
};
}
export function getStoredSearchQuery(search: SearchQuery): StoredSearchQuery {
return {
pattern: search.query,
matchAll: search.matchAll,
matchCase: search.matchCase,
matchRegex: search.matchRegex,
};
}
export function getSearchQueryComparisonKey(search: SearchQuery | StoredSearchQuery) {
return `${'query' in search ? search.query : search.pattern}|${search.matchAll ? 'A' : ''}${
search.matchCase ? 'C' : ''
}${search.matchRegex ? 'R' : ''}`;
}
export function getSearchPatternFromCommit(ref: string): string;
export function getSearchPatternFromCommit(commit: GitRevisionReference): string;
export function getSearchPatternFromCommit(refOrCommit: string | GitRevisionReference) {
export function createSearchQueryForCommit(ref: string): string;
export function createSearchQueryForCommit(commit: GitRevisionReference): string;
export function createSearchQueryForCommit(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)[]) {
export function createSearchQueryForCommits(refs: string[]): string;
export function createSearchQueryForCommits(commits: GitRevisionReference[]): string;
export function createSearchQueryForCommits(refsOrCommits: (string | GitRevisionReference)[]) {
return refsOrCommits.map(r => `#:${typeof r === 'string' ? GitRevision.shorten(r) : r.name}`).join(' ');
}
@ -85,7 +110,7 @@ const normalizeSearchOperatorsMap = new Map([
const searchOperationRegex =
/(?:(?<op>=:|message:|@:|author:|#:|commit:|\?:|file:|~:|change:)\s?(?<value>".+?"|\S+\b}?))|(?<text>\S+)(?!(?:=|message|@|author|#|commit|\?|file|~|change):)/gi;
export function parseSearchOperations(search: string): Map<string, string[]> {
export function parseSearchQuery(query: string): Map<string, string[]> {
const operations = new Map<string, string[]>();
let op: SearchOperators | undefined;
@ -94,7 +119,7 @@ export function parseSearchOperations(search: string): Map {
let match;
do {
match = searchOperationRegex.exec(search);
match = searchOperationRegex.exec(query);
if (match?.groups == null) break;
op = normalizeSearchOperatorsMap.get(match.groups.op as SearchOperators);
@ -117,3 +142,78 @@ export function parseSearchOperations(search: string): Map {
return operations;
}
const doubleQuoteRegex = /"/g;
export function getGitArgsFromSearchQuery(search: SearchQuery): {
args: string[];
files: string[];
shas?: Set<string> | undefined;
} {
const operations = parseSearchQuery(search.query);
const searchArgs = new Set<string>();
const files: string[] = [];
let shas;
let op;
let values = operations.get('commit:');
if (values != null) {
// searchArgs.add('-m');
for (const value of values) {
searchArgs.add(value.replace(doubleQuoteRegex, ''));
}
shas = searchArgs;
} else {
searchArgs.add('--all');
searchArgs.add('--full-history');
searchArgs.add(search.matchRegex ? '--extended-regexp' : '--fixed-strings');
if (search.matchRegex && !search.matchCase) {
searchArgs.add('--regexp-ignore-case');
}
for ([op, values] of operations.entries()) {
switch (op) {
case 'message:':
searchArgs.add('-m');
if (search.matchAll) {
searchArgs.add('--all-match');
}
for (const value of values) {
searchArgs.add(`--grep=${value.replace(doubleQuoteRegex, search.matchRegex ? '\\b' : '')}`);
}
break;
case 'author:':
searchArgs.add('-m');
for (const value of values) {
searchArgs.add(`--author=${value.replace(doubleQuoteRegex, search.matchRegex ? '\\b' : '')}`);
}
break;
case 'change:':
for (const value of values) {
searchArgs.add(
search.matchRegex
? `-G${value.replace(doubleQuoteRegex, '')}`
: `-S${value.replace(doubleQuoteRegex, '')}`,
);
}
break;
case 'file:':
for (const value of values) {
files.push(value.replace(doubleQuoteRegex, ''));
}
break;
}
}
}
return { args: [...searchArgs.values()], files: files, shas: shas };
}

+ 9
- 9
src/plus/github/githubGitProvider.ts View File

@ -73,8 +73,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 type { GitSearch, SearchPattern } from '../../git/search';
import { getSearchPatternComparisonKey, parseSearchOperations } from '../../git/search';
import type { GitSearch, SearchQuery } from '../../git/search';
import { getSearchQueryComparisonKey, parseSearchQuery } from '../../git/search';
import type { LogScope } from '../../logger';
import { Logger } from '../../logger';
import { gate } from '../../system/decorators/gate';
@ -1215,7 +1215,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
limit: log.limit,
// endingCursor: log.endingCursor,
startingCursor: log.startingCursor,
more: log.hasMore,
hasMore: log.hasMore,
},
more: async (limit: number | { until: string } | undefined): Promise<GitGraph | undefined> => {
const moreLog = await log.more?.(limit);
@ -1584,15 +1584,15 @@ export class GitHubGitProvider implements GitProvider, Disposable {
@log()
async searchForCommitsSimple(
repoPath: string,
search: SearchPattern,
search: SearchQuery,
_options?: { cancellation?: CancellationToken; limit?: number; ordering?: 'date' | 'author-date' | 'topo' },
): Promise<GitSearch> {
search = { matchAll: false, matchCase: false, matchRegex: true, ...search };
const comparisonKey = getSearchPatternComparisonKey(search);
const comparisonKey = getSearchQueryComparisonKey(search);
return {
repoPath: repoPath,
pattern: search,
query: search,
comparisonKey: comparisonKey,
results: new Set<string>(),
};
@ -1685,14 +1685,14 @@ export class GitHubGitProvider implements GitProvider, Disposable {
@log()
async getLogForSearch(
repoPath: string,
search: SearchPattern,
search: SearchQuery,
options?: { cursor?: string; limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null; skip?: number },
): Promise<GitLog | undefined> {
if (repoPath == null) return undefined;
const scope = getLogScope();
const operations = parseSearchOperations(search.pattern);
const operations = parseSearchQuery(search.query);
let op;
let values = operations.get('commit:');
@ -1838,7 +1838,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
private getLogForSearchMoreFn(
log: GitLog,
search: SearchPattern,
search: SearchQuery,
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null; skip?: number },
): (limit: number | undefined) => Promise<GitLog> {
return async (limit: number | undefined) => {

+ 8
- 15
src/plus/webviews/graph/graphWebview.ts View File

@ -14,7 +14,7 @@ import type { GitGraph } from '../../../git/models/graph';
import type { Repository, RepositoryChangeEvent } from '../../../git/models/repository';
import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository';
import type { GitSearch } from '../../../git/search';
import { getSearchPatternComparisonKey } from '../../../git/search';
import { getSearchQueryComparisonKey } from '../../../git/search';
import { registerCommand } from '../../../system/command';
import { gate } from '../../../system/decorators/gate';
import { debug } from '../../../system/decorators/log';
@ -432,9 +432,8 @@ export class GraphWebview extends WebviewBase {
private async onSearchCommits(e: SearchCommitsParams, completionId?: string) {
let search: GitSearch | undefined = this._search;
if (search?.more != null && e.more && search.comparisonKey === getSearchPatternComparisonKey(e.search)) {
const limit = typeof e.more !== 'boolean' ? e.more.limit : undefined;
search = await search.more(limit ?? configuration.get('graph.searchItemLimit') ?? 100);
if (e.more && search?.more != null && search.comparisonKey === getSearchQueryComparisonKey(e.search)) {
search = await search.more(e.limit ?? configuration.get('graph.searchItemLimit') ?? 100);
if (search != null) {
this._search = search;
@ -443,10 +442,7 @@ export class GraphWebview extends WebviewBase {
{
results: {
ids: [...search.results.values()],
paging: {
startingCursor: search.paging?.startingCursor,
more: search.paging?.more ?? false,
},
paging: { hasMore: search.paging?.hasMore ?? false },
},
selectedRows: this._selectedRows,
},
@ -457,7 +453,7 @@ export class GraphWebview extends WebviewBase {
return;
}
if (search == null || search.comparisonKey !== getSearchPatternComparisonKey(e.search)) {
if (search == null || search.comparisonKey !== getSearchQueryComparisonKey(e.search)) {
if (this._repository == null) return;
if (this._repository.etag !== this._etagRepository) {
@ -499,10 +495,7 @@ export class GraphWebview extends WebviewBase {
{
results: {
ids: [...search.results.values()],
paging: {
startingCursor: search.paging?.startingCursor,
more: search.paging?.more ?? false,
},
paging: { hasMore: search.paging?.hasMore ?? false },
},
selectedRows: this._selectedRows,
},
@ -636,7 +629,7 @@ export class GraphWebview extends WebviewBase {
selectedRows: this._selectedRows,
paging: {
startingCursor: data.paging?.startingCursor,
more: data.paging?.more ?? false,
hasMore: data.paging?.hasMore ?? false,
},
},
completionId,
@ -729,7 +722,7 @@ export class GraphWebview extends WebviewBase {
data != null
? {
startingCursor: data.paging?.startingCursor,
more: data.paging?.more ?? false,
hasMore: data.paging?.hasMore ?? false,
}
: undefined,
config: this.getComponentConfig(),

+ 6
- 11
src/plus/webviews/graph/protocol.ts View File

@ -2,7 +2,7 @@ import type { GraphRow, Remote } from '@gitkraken/gitkraken-components';
import type { DateStyle, GraphColumnConfig } from '../../../config';
import type { RepositoryVisibility } from '../../../git/gitProvider';
import type { GitGraphRowType } from '../../../git/models/graph';
import type { SearchPattern } from '../../../git/search';
import type { SearchQuery } from '../../../git/search';
import type { Subscription } from '../../../subscription';
import type { DateTimeFormat } from '../../../system/date';
import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol';
@ -30,7 +30,7 @@ export interface State {
export interface GraphPaging {
startingCursor?: string;
more: boolean;
hasMore: boolean;
}
export interface GraphRepository {
@ -96,9 +96,9 @@ export interface GetMoreCommitsParams {
export const GetMoreCommitsCommandType = new IpcCommandType<GetMoreCommitsParams>('graph/getMoreCommits');
export interface SearchCommitsParams {
search: SearchPattern;
more?: boolean | { limit?: number };
search: SearchQuery;
limit?: number;
more?: boolean;
}
export const SearchCommitsCommandType = new IpcCommandType<SearchCommitsParams>('graph/searchCommits');
@ -174,12 +174,7 @@ export const DidEnsureCommitNotificationType = new IpcNotificationType
);
export interface DidSearchCommitsParams {
results:
| {
ids: string[];
paging?: GraphPaging;
}
| undefined;
results: { ids: string[]; paging?: { hasMore: boolean } } | undefined;
selectedRows?: { [id: string]: true };
}
export const DidSearchCommitsNotificationType = new IpcNotificationType<DidSearchCommitsParams>(

+ 2
- 2
src/storage.ts View File

@ -1,7 +1,7 @@
import type { Disposable, Event, ExtensionContext, SecretStorageChangeEvent } from 'vscode';
import { EventEmitter } from 'vscode';
import type { GraphColumnConfig, ViewShowBranchComparison } from './config';
import type { SearchPattern } from './git/search';
import type { StoredSearchQuery } from './git/search';
import type { Subscription } from './subscription';
import type { TrackedUsage, TrackedUsageKeys } from './usageTracker';
import type { CompletedActions } from './webviews/home/protocol';
@ -239,7 +239,7 @@ export interface StoredPinnedSearch {
resultsType?: { singular: string; plural: string };
};
};
search: SearchPattern;
search: StoredSearchQuery;
}
export type StoredPinnedItem = StoredPinnedComparison | StoredPinnedSearch;

+ 11
- 11
src/views/nodes/searchResultsNode.ts View File

@ -3,8 +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 type { SearchPattern } from '../../git/search';
import { getSearchPatternComparisonKey } from '../../git/search';
import type { SearchQuery, StoredSearchQuery } from '../../git/search';
import { getSearchQueryComparisonKey, getStoredSearchQuery } from '../../git/search';
import { gate } from '../../system/decorators/gate';
import { debug, log } from '../../system/decorators/log';
import { md5, pluralize } from '../../system/string';
@ -26,14 +26,14 @@ interface SearchQueryResults {
export class SearchResultsNode extends ViewNode<SearchAndCompareView> implements PageableViewNode {
static key = ':search-results';
static getId(repoPath: string, search: SearchPattern | undefined, instanceId: number): string {
static getId(repoPath: string, search: SearchQuery | undefined, instanceId: number): string {
return `${RepositoryNode.getId(repoPath)}${this.key}(${
search == null ? '?' : getSearchPatternComparisonKey(search)
search == null ? '?' : getSearchQueryComparisonKey(search)
}):${instanceId}`;
}
static getPinnableId(repoPath: string, search: SearchPattern) {
return md5(`${repoPath}|${getSearchPatternComparisonKey(search)}`);
static getPinnableId(repoPath: string, search: SearchQuery | StoredSearchQuery) {
return md5(`${repoPath}|${getSearchQueryComparisonKey(search)}`);
}
private _instanceId: number;
@ -41,7 +41,7 @@ export class SearchResultsNode extends ViewNode implements
view: SearchAndCompareView,
parent: ViewNode,
public readonly repoPath: string,
search: SearchPattern,
search: SearchQuery,
private _labels: {
label: string;
queryLabel:
@ -83,8 +83,8 @@ export class SearchResultsNode extends ViewNode implements
return this._pinned !== 0;
}
private _search: SearchPattern;
get search(): SearchPattern {
private _search: SearchQuery;
get search(): SearchQuery {
return this._search;
}
@ -153,7 +153,7 @@ export class SearchResultsNode extends ViewNode implements
}
async edit(search?: {
pattern: SearchPattern;
pattern: SearchQuery;
labels: {
label: string;
queryLabel:
@ -296,7 +296,7 @@ export class SearchResultsNode extends ViewNode implements
timestamp: this._pinned,
path: this.repoPath,
labels: this._labels,
search: this.search,
search: getStoredSearchQuery(this.search),
});
}
}

+ 12
- 3
src/views/searchAndCompareView.ts View File

@ -8,7 +8,8 @@ import { setContext } from '../context';
import { unknownGitUri } from '../git/gitUri';
import type { GitLog } from '../git/models/log';
import { GitRevision } from '../git/models/reference';
import type { SearchPattern } from '../git/search';
import type { SearchQuery } from '../git/search';
import { getSearchQuery } from '../git/search';
import { ReferencePicker, ReferencesQuickPickIncludes } from '../quickpicks/referencePicker';
import { RepositoryPicker } from '../quickpicks/repositoryPicker';
import type { StoredNamedRef, StoredPinnedItem, StoredPinnedItems } from '../storage';
@ -377,7 +378,7 @@ export class SearchAndCompareView extends ViewBase
async search(
repoPath: string,
search: SearchPattern,
search: SearchQuery,
{
label,
reveal,
@ -469,7 +470,15 @@ export class SearchAndCompareView extends ViewBase
migratedPins[k] = p;
}
return new SearchResultsNode(this, root, p.path, p.search, p.labels, undefined, p.timestamp);
return new SearchResultsNode(
this,
root,
p.path,
getSearchQuery(p.search),
p.labels,
undefined,
p.timestamp,
);
});
if (migrated) {

+ 18
- 18
src/webviews/apps/plus/graph/GraphWrapper.tsx View File

@ -14,7 +14,7 @@ import { DateStyle } from '../../../../config';
import type { GraphColumnConfig } from '../../../../config';
import { RepositoryVisibility } from '../../../../git/gitProvider';
import type { GitGraphRowType } from '../../../../git/models/graph';
import type { SearchPattern } from '../../../../git/search';
import type { SearchQuery } from '../../../../git/search';
import type {
DidEnsureCommitParams,
DidSearchCommitsParams,
@ -38,10 +38,10 @@ export interface GraphWrapperProps extends State {
onColumnChange?: (name: string, settings: GraphColumnConfig) => void;
onMissingAvatars?: (emails: { [email: string]: string }) => void;
onMoreCommits?: (id?: string) => void;
onSearchCommits?: (search: SearchPattern | undefined) => void;
onSearchCommits?: (search: SearchQuery | undefined, options?: { limit?: number }) => void;
onSearchCommitsPromise?: (
search: SearchPattern,
options?: { more?: boolean | { limit?: number } },
search: SearchQuery,
options?: { limit?: number; more?: boolean },
) => Promise<DidSearchCommitsParams>;
onDismissBanner?: (key: DismissBannerParams['key']) => void;
onSelectionChange?: (selection: { id: string; type: GitGraphRowType }[]) => void;
@ -248,10 +248,10 @@ export function GraphWrapper({
// column setting UI
const [columnSettingsExpanded, setColumnSettingsExpanded] = useState(false);
// search state
const [search, setSearch] = useState<SearchPattern | undefined>(undefined);
const [searchQuery, setSearchQuery] = useState<SearchQuery | undefined>(undefined);
const [searchResultKey, setSearchResultKey] = useState<string | undefined>(undefined);
const [searchResultIds, setSearchResultIds] = useState(searchResults?.ids);
const [hasMoreSearchResults, setHasMoreSearchResults] = useState(searchResults?.paging?.more ?? false);
const [hasMoreSearchResults, setHasMoreSearchResults] = useState(searchResults?.paging?.hasMore ?? false);
useEffect(() => {
if (graphRows.length === 0) {
@ -289,8 +289,8 @@ export function GraphWrapper({
if (next) {
if (rowIndex < resultIds.length - 1) {
rowIndex++;
} else if (search != null && hasMoreSearchResults) {
const results = await onSearchCommitsPromise?.(search, { more: true });
} else if (searchQuery != null && hasMoreSearchResults) {
const results = await onSearchCommitsPromise?.(searchQuery, { more: true });
if (results?.results != null) {
if (resultIds.length < results.results.ids.length) {
resultIds = results.results.ids;
@ -307,8 +307,8 @@ export function GraphWrapper({
} else if (rowIndex > 0) {
rowIndex--;
} else {
if (search != null && hasMoreSearchResults) {
const results = await onSearchCommitsPromise?.(search, { more: { limit: 0 } });
if (searchQuery != null && hasMoreSearchResults) {
const results = await onSearchCommitsPromise?.(searchQuery, { limit: 0, more: true });
if (results?.results != null) {
if (resultIds.length < results.results.ids.length) {
resultIds = results.results.ids;
@ -347,11 +347,11 @@ export function GraphWrapper({
}
};
const handleSearchInput = (e: CustomEvent<SearchPattern>) => {
const handleSearchInput = (e: CustomEvent<SearchQuery>) => {
const detail = e.detail;
setSearch(detail);
setSearchQuery(detail);
const isValid = detail.pattern.length >= 3;
const isValid = detail.query.length >= 3;
if (!isValid) {
setSearchResultKey(undefined);
setSearchResultIds(undefined);
@ -394,7 +394,7 @@ export function GraphWrapper({
setIsPrivateRepo(state.selectedRepositoryVisibility === RepositoryVisibility.Private);
setIsLoading(state.loading);
setSearchResultIds(state.searchResults?.ids);
setHasMoreSearchResults(state.searchResults?.paging?.more ?? false);
setHasMoreSearchResults(state.searchResults?.paging?.hasMore ?? false);
}
useEffect(() => subscriber?.(transformData), []);
@ -621,8 +621,8 @@ export function GraphWrapper({
<header className="titlebar graph-app__header">
<div className="titlebar__group">
<SearchField
value={search?.pattern}
onChange={e => handleSearchInput(e as CustomEvent<SearchPattern>)}
value={searchQuery?.query}
onChange={e => handleSearchInput(e as CustomEvent<SearchQuery>)}
onPrevious={() => handleSearchNavigation(false)}
onNext={() => handleSearchNavigation(true)}
/>
@ -630,7 +630,7 @@ export function GraphWrapper({
aria-label="Graph search navigation"
step={searchPosition}
total={searchResultIds?.length ?? 0}
valid={Boolean(search?.pattern && search.pattern.length > 2)}
valid={Boolean(searchQuery?.query && searchQuery.query.length > 2)}
more={hasMoreSearchResults}
onPrevious={() => handleSearchNavigation(false)}
onNext={() => handleSearchNavigation(true)}
@ -656,7 +656,7 @@ export function GraphWrapper({
formatCommitDateTime={getGraphDateFormatter(graphConfig)}
getExternalIcon={getIconElementLibrary}
graphRows={graphRows}
hasMoreCommits={pagingState?.more}
hasMoreCommits={pagingState?.hasMore}
height={mainHeight}
highlightedShas={searchHighlights}
// highlightRowssOnRefHover={graphConfig?.highlightRowsOnRefHover}

+ 5
- 5
src/webviews/apps/plus/graph/graph.tsx View File

@ -4,7 +4,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import type { GraphColumnConfig } from '../../../../config';
import type { GitGraphRowType } from '../../../../git/models/graph';
import type { SearchPattern } from '../../../../git/search';
import type { SearchQuery } from '../../../../git/search';
import type {
DismissBannerParams,
GraphRepository,
@ -299,18 +299,18 @@ export class GraphApp extends App {
return this.sendCommand(GetMoreCommitsCommandType, { sha: sha });
}
private onSearchCommits(search: SearchPattern | undefined) {
private onSearchCommits(search: SearchQuery | undefined, options?: { limit?: number }) {
if (search == null) {
this.state.searchResults = undefined;
return;
}
return this.sendCommand(SearchCommitsCommandType, { search: search });
return this.sendCommand(SearchCommitsCommandType, { search: search, limit: options?.limit });
}
private onSearchCommitsPromise(search: SearchPattern, options?: { more?: boolean | { limit?: number } }) {
private onSearchCommitsPromise(search: SearchQuery, options?: { limit?: number; more?: boolean }) {
return this.sendCommandWithCompletion(
SearchCommitsCommandType,
{ search: search, more: options?.more },
{ search: search, limit: options?.limit, more: options?.more },
DidSearchCommitsNotificationType,
);
}

+ 5
- 3
src/webviews/apps/shared/components/search/search-field.ts View File

@ -1,4 +1,5 @@
import { attr, css, customElement, FASTElement, html } from '@microsoft/fast-element';
import type { SearchQuery } from '../../../../../git/search';
import '../codicon';
// match case is disabled unless regex is true
@ -191,11 +192,12 @@ export class SearchField extends FASTElement {
}
emitSearch() {
this.$emit('change', {
pattern: this.value,
const search: SearchQuery = {
query: this.value,
matchAll: this.all,
matchCase: this.case,
matchRegex: this.regex,
});
};
this.$emit('change', search);
}
}

+ 2
- 2
src/webviews/rebase/rebaseEditor.ts View File

@ -495,7 +495,7 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl
const html = content.replace(
/#{(head|body|endOfBody|placement|cspSource|cspNonce|root|webroot)}/g,
(_substring, token) => {
(_substring: string, token: string) => {
switch (token) {
case 'endOfBody':
return `<script type="text/javascript" nonce="${cspNonce}">window.bootstrap=${JSON.stringify(
@ -541,7 +541,7 @@ async function parseRebaseTodo(
const commits: Commit[] = [];
const log = await container.git.getLogForSearch(repoPath, {
pattern: `${onto ? `#:${onto} ` : ''}${join(
query: `${onto ? `#:${onto} ` : ''}${join(
map(entries, e => `#:${e.ref}`),
' ',
)}`,

Loading…
Cancel
Save