You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

227 lines
8.4 KiB

'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();
}
}
}