'use strict';
|
|
import { commands, InputBoxOptions, TextEditor, Uri, window } from 'vscode';
|
|
import { GlyphChars } from '../constants';
|
|
import { Container } from '../container';
|
|
import { GitRepoSearchBy, GitService, GitUri } from '../git/gitService';
|
|
import { Logger } from '../logger';
|
|
import { Messages } from '../messages';
|
|
import { CommandQuickPickItem, CommitsQuickPick, ShowCommitsSearchInResultsQuickPickItem } from '../quickpicks';
|
|
import { Strings } from '../system';
|
|
import { Iterables } from '../system/iterable';
|
|
import {
|
|
ActiveEditorCachedCommand,
|
|
CommandContext,
|
|
Commands,
|
|
getCommandUri,
|
|
getRepoPathOrActiveOrPrompt,
|
|
isCommandViewContextWithRepo
|
|
} from './common';
|
|
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
|
|
|
const searchByRegex = /^([@~=:#])/;
|
|
const symbolToSearchByMap = new Map<string, GitRepoSearchBy>([
|
|
['@', GitRepoSearchBy.Author],
|
|
['~', GitRepoSearchBy.ChangedLines],
|
|
['=', GitRepoSearchBy.Changes],
|
|
[':', GitRepoSearchBy.Files],
|
|
['#', GitRepoSearchBy.Sha]
|
|
]);
|
|
|
|
const searchByToSymbolMap = new Map<GitRepoSearchBy, string>([
|
|
[GitRepoSearchBy.Author, '@'],
|
|
[GitRepoSearchBy.ChangedLines, '~'],
|
|
[GitRepoSearchBy.Changes, '='],
|
|
[GitRepoSearchBy.Files, ':'],
|
|
[GitRepoSearchBy.Sha, '#']
|
|
]);
|
|
|
|
export interface ShowCommitSearchCommandArgs {
|
|
search?: string;
|
|
searchBy?: GitRepoSearchBy;
|
|
maxCount?: number;
|
|
showInResults?: boolean;
|
|
|
|
goBackCommand?: CommandQuickPickItem;
|
|
}
|
|
|
|
export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
|
|
constructor() {
|
|
super(Commands.ShowCommitSearch);
|
|
}
|
|
|
|
protected async preExecute(context: CommandContext, args: ShowCommitSearchCommandArgs = {}) {
|
|
if (context.type === 'view' || context.type === 'viewItem') {
|
|
args = { ...args };
|
|
args.showInResults = true;
|
|
|
|
if (isCommandViewContextWithRepo(context)) {
|
|
return this.execute(context.editor, context.node.uri, args);
|
|
}
|
|
}
|
|
|
|
return this.execute(context.editor, context.uri, args);
|
|
}
|
|
|
|
async execute(editor?: TextEditor, uri?: Uri, args: ShowCommitSearchCommandArgs = {}) {
|
|
uri = getCommandUri(uri, editor);
|
|
|
|
const gitUri = uri && (await GitUri.fromUri(uri));
|
|
|
|
const repoPath = await getRepoPathOrActiveOrPrompt(
|
|
gitUri,
|
|
editor,
|
|
`Search for commits in which repository${GlyphChars.Ellipsis}`,
|
|
args.goBackCommand
|
|
);
|
|
if (!repoPath) return undefined;
|
|
|
|
args = { ...args };
|
|
const originalArgs = { ...args };
|
|
|
|
if (!args.search || args.searchBy == null) {
|
|
let selection;
|
|
if (!args.search && args.searchBy != null) {
|
|
args.search = searchByToSymbolMap.get(args.searchBy);
|
|
selection = [1, 1];
|
|
}
|
|
|
|
args.search = await window.showInputBox({
|
|
value: args.search,
|
|
prompt: `Please enter a search string`,
|
|
placeHolder: `search by message, author (@<pattern>), files (:<pattern>), commit id (#<sha>), changes (=<pattern>), changed lines (~<pattern>)`,
|
|
valueSelection: selection
|
|
} as InputBoxOptions);
|
|
if (args.search === undefined) {
|
|
return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
|
|
}
|
|
|
|
originalArgs.search = args.search;
|
|
|
|
const match = searchByRegex.exec(args.search);
|
|
if (match && match[1]) {
|
|
args.searchBy = symbolToSearchByMap.get(match[1]);
|
|
args.search = args.search.substring(args.search[1] === ' ' ? 2 : 1);
|
|
}
|
|
else if (GitService.isShaLike(args.search)) {
|
|
args.searchBy = GitRepoSearchBy.Sha;
|
|
}
|
|
else {
|
|
args.searchBy = GitRepoSearchBy.Message;
|
|
}
|
|
}
|
|
|
|
if (args.searchBy === undefined) {
|
|
args.searchBy = GitRepoSearchBy.Message;
|
|
}
|
|
|
|
let searchLabel: string | undefined = undefined;
|
|
switch (args.searchBy) {
|
|
case GitRepoSearchBy.Author:
|
|
searchLabel = `commits with an author matching '${args.search}'`;
|
|
break;
|
|
|
|
case GitRepoSearchBy.ChangedLines:
|
|
searchLabel = `commits with changed lines matching '${args.search}'`;
|
|
break;
|
|
|
|
case GitRepoSearchBy.Changes:
|
|
searchLabel = `commits with changes matching '${args.search}'`;
|
|
break;
|
|
|
|
case GitRepoSearchBy.Files:
|
|
searchLabel = `commits with files matching '${args.search}'`;
|
|
break;
|
|
|
|
case GitRepoSearchBy.Message:
|
|
searchLabel = args.search ? `commits with a message matching '${args.search}'` : 'all commits';
|
|
break;
|
|
|
|
case GitRepoSearchBy.Sha:
|
|
searchLabel = `commits with an id matching '${args.search}'`;
|
|
break;
|
|
}
|
|
|
|
if (args.showInResults) {
|
|
Container.resultsView.addSearchResults(
|
|
repoPath,
|
|
Container.git.getLogForSearch(repoPath, args.search!, args.searchBy!, {
|
|
maxCount: args.maxCount
|
|
}),
|
|
{ label: searchLabel! }
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
const progressCancellation = CommitsQuickPick.showProgress(searchLabel!);
|
|
try {
|
|
const log = await Container.git.getLogForSearch(repoPath, args.search, args.searchBy, {
|
|
maxCount: args.maxCount
|
|
});
|
|
|
|
if (progressCancellation.token.isCancellationRequested) return undefined;
|
|
|
|
let goBackCommand: CommandQuickPickItem | undefined =
|
|
args.goBackCommand ||
|
|
new CommandQuickPickItem(
|
|
{
|
|
label: `go back ${GlyphChars.ArrowBack}`,
|
|
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} to commit search`
|
|
},
|
|
Commands.ShowCommitSearch,
|
|
[uri, originalArgs]
|
|
);
|
|
|
|
let commit;
|
|
if (args.searchBy !== GitRepoSearchBy.Sha || log === undefined || log.count !== 1) {
|
|
const pick = await CommitsQuickPick.show(log, searchLabel!, progressCancellation, {
|
|
goBackCommand: goBackCommand,
|
|
showAllCommand:
|
|
log !== undefined && log.truncated
|
|
? new CommandQuickPickItem(
|
|
{
|
|
label: `$(sync) Show All Commits`,
|
|
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} this may take a while`
|
|
},
|
|
Commands.ShowCommitSearch,
|
|
[uri, { ...args, maxCount: 0, goBackCommand: goBackCommand }]
|
|
)
|
|
: undefined,
|
|
showInResultsCommand:
|
|
log !== undefined ? new ShowCommitsSearchInResultsQuickPickItem(log, searchLabel!) : undefined
|
|
});
|
|
if (pick === undefined) return undefined;
|
|
|
|
if (pick instanceof CommandQuickPickItem) return pick.execute();
|
|
|
|
commit = pick.commit;
|
|
goBackCommand = undefined;
|
|
}
|
|
else {
|
|
commit = Iterables.first(log.commits.values());
|
|
}
|
|
|
|
return commands.executeCommand(Commands.ShowQuickCommitDetails, commit.toGitUri(), {
|
|
sha: commit.sha,
|
|
commit: commit,
|
|
goBackCommand:
|
|
goBackCommand ||
|
|
new CommandQuickPickItem(
|
|
{
|
|
label: `go back ${GlyphChars.ArrowBack}`,
|
|
description: `${Strings.pad(GlyphChars.Dash, 2, 2)} to search for ${searchLabel}`
|
|
},
|
|
Commands.ShowCommitSearch,
|
|
[uri, args]
|
|
)
|
|
} as ShowQuickCommitDetailsCommandArgs);
|
|
}
|
|
catch (ex) {
|
|
Logger.error(ex, 'ShowCommitSearchCommand');
|
|
return Messages.showGenericErrorMessage('Unable to find commits');
|
|
}
|
|
finally {
|
|
progressCancellation.cancel();
|
|
}
|
|
}
|
|
}
|