From 6fc635fb6488378fa83ed1070d4c27428e2549c0 Mon Sep 17 00:00:00 2001 From: Christopher Date: Mon, 27 Jan 2020 11:39:50 +0000 Subject: [PATCH] feat: Added log search commands (#782) --- package.json | 18 +++++++++++ src/commands.ts | 4 +++ src/commands/search_log_by_revision.ts | 41 ++++++++++++++++++++++++++ src/commands/search_log_by_text.ts | 35 ++++++++++++++++++++++ src/common/types.ts | 6 +++- src/contexts/isSvn18orGreater.ts | 14 +++++++++ src/extension.ts | 2 ++ src/repository.ts | 12 ++++++++ src/svnContentProvider.ts | 6 ++++ src/svnRepository.ts | 12 ++++++++ 10 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/commands/search_log_by_revision.ts create mode 100644 src/commands/search_log_by_text.ts create mode 100644 src/contexts/isSvn18orGreater.ts diff --git a/package.json b/package.json index cad2f5f4..07ad6cc0 100644 --- a/package.json +++ b/package.json @@ -467,6 +467,16 @@ "light": "icons/light/icon-history.svg", "dark": "icons/dark/icon-history.svg" } + }, + { + "command": "svn.searchLogByRevision", + "title": "Search log by revision", + "category": "SVN" + }, + { + "command": "svn.searchLogByText", + "title": "Search log", + "category": "SVN" } ], "menus": { @@ -650,6 +660,14 @@ { "command": "svn.pickCommitMessage", "when": "config.svn.enabled && svnOpenRepositoryCount != 0" + }, + { + "command": "svn.searchLogByRevision", + "when": "config.svn.enabled && svnOpenRepositoryCount != 0" + }, + { + "command": "svn.searchLogByText", + "when": "config.svn.enabled && svnOpenRepositoryCount != 0 && isSvn18orGreater" } ], "view/title": [ diff --git a/src/commands.ts b/src/commands.ts index a627ce2f..8a856fea 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -43,6 +43,8 @@ import { SwitchBranch } from "./commands/switchBranch"; import { Update } from "./commands/update"; import { Upgrade } from "./commands/upgrade"; import { SourceControlManager } from "./source_control_manager"; +import { SearchLogByRevision } from "./commands/search_log_by_revision"; +import { SearchLogByText } from "./commands/search_log_by_text"; export function registerCommands( sourceControlManager: SourceControlManager, @@ -91,4 +93,6 @@ export function registerCommands( disposables.push(new RevertAll()); disposables.push(new PickCommitMessage()); disposables.push(new RevertExplorer()); + disposables.push(new SearchLogByRevision()); + disposables.push(new SearchLogByText()); } diff --git a/src/commands/search_log_by_revision.ts b/src/commands/search_log_by_revision.ts new file mode 100644 index 00000000..fddd3244 --- /dev/null +++ b/src/commands/search_log_by_revision.ts @@ -0,0 +1,41 @@ +import * as path from "path"; +import { Command } from "./command"; +import { window, Uri, commands } from "vscode"; +import { Repository } from "../repository"; +import { toSvnUri } from "../uri"; +import { SvnUriAction } from "../common/types"; + +export class SearchLogByRevision extends Command { + constructor() { + super("svn.searchLogByRevision", { repository: true }); + } + + public async execute(repository: Repository) { + const input = await window.showInputBox({ prompt: "Revision?" }); + if (!input) { + return; + } + + const revision = parseInt(input, 10); + if (!revision || !/^\+?(0|[1-9]\d*)$/.test(input)) { + window.showErrorMessage("Invalid revision"); + return; + } + + try { + const resource = toSvnUri( + Uri.file(repository.workspaceRoot), + SvnUriAction.LOG_REVISION, + { revision } + ); + const uri = resource.with({ + path: path.join(resource.path, "svn.log") + }); + + await commands.executeCommand("vscode.open", uri); + } catch (error) { + console.error(error); + window.showErrorMessage("Unable to log"); + } + } +} diff --git a/src/commands/search_log_by_text.ts b/src/commands/search_log_by_text.ts new file mode 100644 index 00000000..a07ae1fb --- /dev/null +++ b/src/commands/search_log_by_text.ts @@ -0,0 +1,35 @@ +import * as path from "path"; +import { Command } from "./command"; +import { window, Uri, commands } from "vscode"; +import { Repository } from "../repository"; +import { toSvnUri } from "../uri"; +import { SvnUriAction } from "../common/types"; + +export class SearchLogByText extends Command { + constructor() { + super("svn.searchLogByText", { repository: true }); + } + + public async execute(repository: Repository) { + const input = await window.showInputBox({ prompt: "Search query" }); + if (!input) { + return; + } + + try { + const resource = toSvnUri( + Uri.file(repository.workspaceRoot), + SvnUriAction.LOG_SEARCH, + { search: input } + ); + const uri = resource.with({ + path: path.join(resource.path, "svn.log") + }); + + await commands.executeCommand("vscode.open", uri); + } catch (error) { + console.error(error); + window.showErrorMessage("Unable to log"); + } + } +} diff --git a/src/common/types.ts b/src/common/types.ts index ff32f3fc..49eec539 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -255,13 +255,17 @@ export interface ISvn { export enum SvnUriAction { LOG = "LOG", PATCH = "PATCH", - SHOW = "SHOW" + SHOW = "SHOW", + LOG_REVISION = "LOG_REVISION", + LOG_SEARCH = "LOG_SEARCH" } export interface ISvnUriExtraParams { ref?: string; limit?: string; [key: string]: any; + revision?: number; + search?: string; } export interface ISvnUriParams { diff --git a/src/contexts/isSvn18orGreater.ts b/src/contexts/isSvn18orGreater.ts new file mode 100644 index 00000000..79841667 --- /dev/null +++ b/src/contexts/isSvn18orGreater.ts @@ -0,0 +1,14 @@ +import { Disposable } from "vscode"; +import * as semver from "semver"; +import { setVscodeContext } from "../util"; + +export class IsSvn18orGreater implements Disposable { + constructor(svnVersion: string) { + const is18orGreater = semver.satisfies(svnVersion, ">= 1.8"); + + setVscodeContext("isSvn18orGreater", is18orGreater); + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + dispose() {} +} diff --git a/src/extension.ts b/src/extension.ts index 485e102f..85e437a7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -23,6 +23,7 @@ import SvnProvider from "./treeView/dataProviders/svnProvider"; import { toDisposable } from "./util"; import { BranchChangesProvider } from "./historyView/branchChangesProvider"; import { IsSvn19orGreater } from "./contexts/isSvn19orGreater"; +import { IsSvn18orGreater } from "./contexts/isSvn18orGreater"; async function init( _context: ExtensionContext, @@ -62,6 +63,7 @@ async function init( disposables.push(new CheckActiveEditor(sourceControlManager)); disposables.push(new OpenRepositoryCount(sourceControlManager)); + disposables.push(new IsSvn18orGreater(info.version)); disposables.push(new IsSvn19orGreater(info.version)); outputChannel.appendLine(`Using svn "${info.version}" from "${info.path}"`); diff --git a/src/repository.ts b/src/repository.ts index f3ee3f0b..6f82679e 100644 --- a/src/repository.ts +++ b/src/repository.ts @@ -850,6 +850,18 @@ export class Repository implements IRemoteRepository { return this.run(Operation.Log, () => this.repository.plainLog()); } + public async plainLogByRevision(revision: number) { + return this.run(Operation.Log, () => + this.repository.plainLogByRevision(revision) + ); + } + + public async plainLogByText(search: string) { + return this.run(Operation.Log, () => + this.repository.plainLogByText(search) + ); + } + public async log( rfrom: string, rto: string, diff --git a/src/svnContentProvider.ts b/src/svnContentProvider.ts index a8790896..595690d5 100644 --- a/src/svnContentProvider.ts +++ b/src/svnContentProvider.ts @@ -118,6 +118,12 @@ export class SvnContentProvider if (action === SvnUriAction.LOG) { return await repository.plainLog(); } + if (action === SvnUriAction.LOG_REVISION && extra.revision) { + return await repository.plainLogByRevision(extra.revision); + } + if (action === SvnUriAction.LOG_SEARCH && extra.search) { + return await repository.plainLogByText(extra.search); + } if (action === SvnUriAction.PATCH) { return await repository.patch([fsPath]); } diff --git a/src/svnRepository.ts b/src/svnRepository.ts index e0a038c4..0a62c1d1 100644 --- a/src/svnRepository.ts +++ b/src/svnRepository.ts @@ -657,6 +657,18 @@ export class Repository { return result.stdout; } + public async plainLogByRevision(revision: number) { + const result = await this.exec(["log", "-r", revision.toString()]); + + return result.stdout; + } + + public async plainLogByText(search: string) { + const result = await this.exec(["log", "--search", search]); + + return result.stdout; + } + public async log( rfrom: string, rto: string,