From 3f8923c8f6b4d56deda2cc98156687238cc06e6f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 11 Nov 2018 00:50:04 -0500 Subject: [PATCH] Renames show commit search to search commits Adds search commits button to view --- README.md | 2 +- package.json | 18 +++ src/commands.ts | 2 +- src/commands/common.ts | 3 +- src/commands/searchCommits.ts | 238 +++++++++++++++++++++++++++++++++++++++ src/commands/showCommitSearch.ts | 234 -------------------------------------- src/views/nodes/searchNode.ts | 14 +-- 7 files changed, 267 insertions(+), 244 deletions(-) create mode 100644 src/commands/searchCommits.ts delete mode 100644 src/commands/showCommitSearch.ts diff --git a/README.md b/README.md index 1798135..68849d1 100644 --- a/README.md +++ b/README.md @@ -267,7 +267,7 @@ The search commits view provides the following features, - Provides a semi-persistent results view for searching and exploring commit histories - Accessible via the following commands - - _Show Commit Search_ command (`gitlens.showCommitSearch`) + - _Search Commits_ command (`gitlens.showCommitSearch`) - _Show File History_ command (`gitlens.showQuickFileHistory`) - _Show Commit Details_ command (`gitlens.showQuickCommitDetails`) - An inline toolbar provides a _Clear Results_ command diff --git a/package.json b/package.json index 070b031..6a69cc1 100644 --- a/package.json +++ b/package.json @@ -2429,6 +2429,15 @@ } }, { + "command": "gitlens.views.search.searchCommits", + "title": "Search Commits", + "category": "GitLens", + "icon": { + "dark": "images/dark/icon-search.svg", + "light": "images/light/icon-search.svg" + } + }, + { "command": "gitlens.views.search.clear", "title": "Clear Results", "category": "GitLens", @@ -3013,6 +3022,10 @@ "when": "false" }, { + "command": "gitlens.views.search.searchCommits", + "when": "false" + }, + { "command": "gitlens.views.search.clear", "when": "false" }, @@ -3421,6 +3434,11 @@ "group": "1_gitlens" }, { + "command": "gitlens.views.search.searchCommits", + "when": "view =~ /^gitlens\\.views\\.search:/", + "group": "navigation@1" + }, + { "command": "gitlens.views.search.clear", "when": "view =~ /^gitlens\\.views\\.search:/", "group": "navigation@2" diff --git a/src/commands.ts b/src/commands.ts index a344160..e740720 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -28,7 +28,7 @@ export * from './commands/openRepoInRemote'; export * from './commands/openWorkingFile'; export * from './commands/repositories'; export * from './commands/resetSuppressedWarnings'; -export * from './commands/showCommitSearch'; +export * from './commands/searchCommits'; export * from './commands/showLastQuickPick'; export * from './commands/showQuickBranchHistory'; export * from './commands/showQuickCommitDetails'; diff --git a/src/commands/common.ts b/src/commands/common.ts index 5b15c70..df9cc29 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -57,7 +57,8 @@ export enum Commands { PushRepositories = 'gitlens.pushRepositories', ResetSuppressedWarnings = 'gitlens.resetSuppressedWarnings', ShowCommitInView = 'gitlens.showCommitInView', - ShowCommitSearch = 'gitlens.showCommitSearch', + SearchCommits = 'gitlens.showCommitSearch', + SearchCommitsInView = 'gitlens.views.search.searchCommits', ShowCompareView = 'gitlens.showCompareView', ShowFileHistoryView = 'gitlens.showFileHistoryView', ShowFileHistoryInView = 'gitlens.showFileHistoryInView', diff --git a/src/commands/searchCommits.ts b/src/commands/searchCommits.ts new file mode 100644 index 0000000..7d7d1be --- /dev/null +++ b/src/commands/searchCommits.ts @@ -0,0 +1,238 @@ +'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, ShowCommitSearchResultsInViewQuickPickItem } from '../quickpicks'; +import { Iterables, Strings } from '../system'; +import { + ActiveEditorCachedCommand, + command, + CommandContext, + Commands, + getCommandUri, + getRepoPathOrActiveOrPrompt, + isCommandViewContextWithRepo +} from './common'; +import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails'; + +const searchByRegex = /^([@~=:#])/; +const symbolToSearchByMap = new Map([ + ['@', GitRepoSearchBy.Author], + ['~', GitRepoSearchBy.ChangedLines], + ['=', GitRepoSearchBy.Changes], + [':', GitRepoSearchBy.Files], + ['#', GitRepoSearchBy.Sha] +]); + +const searchByToSymbolMap = new Map([ + [GitRepoSearchBy.Author, '@'], + [GitRepoSearchBy.ChangedLines, '~'], + [GitRepoSearchBy.Changes, '='], + [GitRepoSearchBy.Files, ':'], + [GitRepoSearchBy.Sha, '#'] +]); + +export interface SearchCommitsCommandArgs { + search?: string; + searchBy?: GitRepoSearchBy; + maxCount?: number; + showInView?: boolean; + + goBackCommand?: CommandQuickPickItem; +} + +@command() +export class SearchCommitsCommand extends ActiveEditorCachedCommand { + constructor() { + super([Commands.SearchCommits, Commands.SearchCommitsInView]); + } + + protected async preExecute(context: CommandContext, args: SearchCommitsCommandArgs = {}) { + if (context.type === 'viewItem') { + args = { ...args }; + args.showInView = true; + + if (isCommandViewContextWithRepo(context)) { + return this.execute(context.editor, context.node.uri, args); + } + } + else if (context.command === Commands.SearchCommitsInView) { + args = { ...args }; + args.showInView = true; + } + else { + // TODO: Add a user setting (default to view?) + } + + return this.execute(context.editor, context.uri, args); + } + + async execute(editor?: TextEditor, uri?: Uri, args: SearchCommitsCommandArgs = {}) { + 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]; + } + + if (args.showInView) { + await Container.searchView.show(); + } + + args.search = await window.showInputBox({ + value: args.search, + prompt: `Please enter a search string`, + placeHolder: `Search commits by message, author (@), files (:), commit id (#), changes (=), changed lines (~)`, + 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.showInView) { + void Container.searchView.search(repoPath, args.search, args.searchBy, { + maxCount: args.maxCount, + label: { 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.SearchCommits, + [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.SearchCommits, + [uri, { ...args, maxCount: 0, goBackCommand: goBackCommand }] + ) + : undefined, + showInViewCommand: + log !== undefined + ? new ShowCommitSearchResultsInViewQuickPickItem(log, { label: 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.SearchCommits, + [uri, args] + ) + } as ShowQuickCommitDetailsCommandArgs); + } + catch (ex) { + Logger.error(ex, 'ShowCommitSearchCommand'); + return Messages.showGenericErrorMessage('Unable to find commits'); + } + finally { + progressCancellation.cancel(); + } + } +} diff --git a/src/commands/showCommitSearch.ts b/src/commands/showCommitSearch.ts deleted file mode 100644 index 0148651..0000000 --- a/src/commands/showCommitSearch.ts +++ /dev/null @@ -1,234 +0,0 @@ -'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, ShowCommitSearchResultsInViewQuickPickItem } from '../quickpicks'; -import { Iterables, Strings } from '../system'; -import { - ActiveEditorCachedCommand, - command, - CommandContext, - Commands, - getCommandUri, - getRepoPathOrActiveOrPrompt, - isCommandViewContextWithRepo -} from './common'; -import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails'; - -const searchByRegex = /^([@~=:#])/; -const symbolToSearchByMap = new Map([ - ['@', GitRepoSearchBy.Author], - ['~', GitRepoSearchBy.ChangedLines], - ['=', GitRepoSearchBy.Changes], - [':', GitRepoSearchBy.Files], - ['#', GitRepoSearchBy.Sha] -]); - -const searchByToSymbolMap = new Map([ - [GitRepoSearchBy.Author, '@'], - [GitRepoSearchBy.ChangedLines, '~'], - [GitRepoSearchBy.Changes, '='], - [GitRepoSearchBy.Files, ':'], - [GitRepoSearchBy.Sha, '#'] -]); - -export interface ShowCommitSearchCommandArgs { - search?: string; - searchBy?: GitRepoSearchBy; - maxCount?: number; - showInView?: boolean; - - goBackCommand?: CommandQuickPickItem; -} - -@command() -export class ShowCommitSearchCommand extends ActiveEditorCachedCommand { - constructor() { - super(Commands.ShowCommitSearch); - } - - protected async preExecute(context: CommandContext, args: ShowCommitSearchCommandArgs = {}) { - if (context.type === 'viewItem') { - args = { ...args }; - args.showInView = true; - - if (isCommandViewContextWithRepo(context)) { - return this.execute(context.editor, context.node.uri, args); - } - } - else { - // TODO: Add a user setting (default to view?) - } - - 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]; - } - - if (args.showInView) { - await Container.searchView.show(); - } - - args.search = await window.showInputBox({ - value: args.search, - prompt: `Please enter a search string`, - placeHolder: `Search commits by message, author (@), files (:), commit id (#), changes (=), changed lines (~)`, - 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.showInView) { - void Container.searchView.search(repoPath, args.search, args.searchBy, { - maxCount: args.maxCount, - label: { 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, - showInViewCommand: - log !== undefined - ? new ShowCommitSearchResultsInViewQuickPickItem(log, { label: 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(); - } - } -} diff --git a/src/views/nodes/searchNode.ts b/src/views/nodes/searchNode.ts index 21df7e1..b27fd73 100644 --- a/src/views/nodes/searchNode.ts +++ b/src/views/nodes/searchNode.ts @@ -1,6 +1,6 @@ 'use strict'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; -import { ShowCommitSearchCommandArgs } from '../../commands'; +import { SearchCommitsCommandArgs } from '../../commands'; import { GlyphChars } from '../../constants'; import { GitRepoSearchBy } from '../../git/gitService'; import { debug, Functions, gate, log } from '../../system'; @@ -28,7 +28,7 @@ export class SearchNode extends ViewNode { this, { ...command, - arguments: [this, { searchBy: GitRepoSearchBy.Message } as ShowCommitSearchCommandArgs] + arguments: [this, { searchBy: GitRepoSearchBy.Message } as SearchCommitsCommandArgs] }, `Search commits by message (use <message-pattern>)`, 'Click to search commits by message' @@ -38,7 +38,7 @@ export class SearchNode extends ViewNode { this, { ...command, - arguments: [this, { searchBy: GitRepoSearchBy.Author } as ShowCommitSearchCommandArgs] + arguments: [this, { searchBy: GitRepoSearchBy.Author } as SearchCommitsCommandArgs] }, `${GlyphChars.Space.repeat(4)} or, by author (use @<author-pattern>)`, 'Click to search commits by author' @@ -48,7 +48,7 @@ export class SearchNode extends ViewNode { this, { ...command, - arguments: [this, { searchBy: GitRepoSearchBy.Sha } as ShowCommitSearchCommandArgs] + arguments: [this, { searchBy: GitRepoSearchBy.Sha } as SearchCommitsCommandArgs] }, `${GlyphChars.Space.repeat(4)} or, by commit id (use #<sha>)`, 'Click to search commits by commit id' @@ -58,7 +58,7 @@ export class SearchNode extends ViewNode { this, { ...command, - arguments: [this, { searchBy: GitRepoSearchBy.Files } as ShowCommitSearchCommandArgs] + arguments: [this, { searchBy: GitRepoSearchBy.Files } as SearchCommitsCommandArgs] }, `${GlyphChars.Space.repeat(4)} or, by files (use :<file-pattern>)`, 'Click to search commits by files' @@ -68,7 +68,7 @@ export class SearchNode extends ViewNode { this, { ...command, - arguments: [this, { searchBy: GitRepoSearchBy.Changes } as ShowCommitSearchCommandArgs] + arguments: [this, { searchBy: GitRepoSearchBy.Changes } as SearchCommitsCommandArgs] }, `${GlyphChars.Space.repeat(4)} or, by changes (use =<pattern>)`, 'Click to search commits by changes' @@ -78,7 +78,7 @@ export class SearchNode extends ViewNode { this, { ...command, - arguments: [this, { searchBy: GitRepoSearchBy.ChangedLines } as ShowCommitSearchCommandArgs] + arguments: [this, { searchBy: GitRepoSearchBy.ChangedLines } as SearchCommitsCommandArgs] }, `${GlyphChars.Space.repeat(4)} or, by changed lines (use ~<pattern>)`, 'Click to search commits by changed lines'