kakoune icon indicating copy to clipboard operation
kakoune copied to clipboard

[REQUEST] Make <ret> do git show when on a hash in git log output

Open lobre opened this issue 1 year ago • 3 comments

Feature

The rc/tools/git.kak is really helpful to quickly interact with git on a project.

For example, if you :git log, you see the history that appears in the *git* buffer. This is super handy. If you add the -p option (:git log -p), you directly see the patch for each commit. And if you do <ret> when the cursor is on one of the lines of the diff, you jump there. This is awesome.

To improve even more the experience, I think that doing <ret> while on a hash (a short hash such as when doing :git log --oneline or a long hash in regular :git log) could do a :git show <the_selected_hash>. This way, one could really rapidly navigate the history to check a previous change with :git log and <ret>.

Of course, if :git show is called while within :git log, it means that the user won't be able to go back to the log while seeing the patch, as they are using the same scratch buffer *git*. This could be mitigated if another scratch buffer is used so that the user could use ^O to jump back. But maybe it is not worth it to go that far.

Usecase

Navigate quickly the git history and see patches.

lobre avatar Dec 07 '23 15:12 lobre

Yeah. I use this, mapped to a different key than <ret> though.

define-command -override my-git-enter %{ evaluate-commands -save-regs c %{
	try %{
		evaluate-commands -draft %{
			execute-keys s\S+<ret>
			try %{
				evaluate-commands %sh{
					[ "$(git rev-parse --revs-only "$kak_selection")" ] || echo fail
				}
			} catch %{
				try %{ execute-keys <a-i>w }
				evaluate-commands %sh{
					[ "$(git rev-parse --revs-only "$kak_selection")" ] || echo fail
				}
			}
			set-register c %val{selection}
		}
		git show %reg{c} --
	} catch %{
		git-diff-goto-source
	}
}}

krobelus avatar Dec 08 '23 15:12 krobelus

Nice, thank you for sharing.

According to you, would it be worth it to integrate this behavior directly to rc/tools/git.kak?

lobre avatar Dec 08 '23 16:12 lobre

To improve even more the experience, I think that doing while on a hash (a short hash such as when doing :git log --oneline or a long hash in regular :git log) could do a :git show <the_selected_hash>. This way, one could really rapidly navigate the history to check a previous change with :git log and .

One problem with overloading <ret> with two different behaviors (well, three, we already map it to blame-jump while blame annotations are shown) is that we have to second-guess the user in edge cases where it's not clear whether we are in a diff / whether the thing at cursor is an object ID.

It's probably still worth adding. Here's a rough attempt:

diff --git a/rc/tools/git.kak b/rc/tools/git.kak
index 1a1e8d81e..594e54a4a 100644
--- a/rc/tools/git.kak
+++ b/rc/tools/git.kak
@@ -41,10 +41,10 @@ hook -group git-diff-highlight global WinSetOption filetype=(git-diff|git-log) %
     }
 }
 
-hook global WinSetOption filetype=(?:git-diff|git-log) %{
-    map buffer normal <ret> %exp{:git-diff-goto-source # %val{hook_param}<ret>} -docstring 'Jump to source from git diff'
+hook global WinSetOption filetype=git-(?:commit|diff|log|notes|rebase) %{
+    map buffer normal <ret> %exp{:git-jump # %val{hook_param}<ret>} -docstring 'Jump to source from git diff'
     hook -once -always window WinSetOption filetype=.* %exp{
-        unmap buffer normal <ret> %%{:git-diff-goto-source # %val{hook_param}<ret>}
+        unmap buffer normal <ret> %%{:git-jump # %val{hook_param}<ret>}
     }
 }
 
@@ -776,3 +776,30 @@ define-command git-diff-goto-source \
         fi
     }
 }
+
+define-command git-jump -docstring %{
+    If inside a diff, run git-diff-goto-source,
+    Else show the Git object at cursor.
+} %{ evaluate-commands -save-regs c %{
+    try %{
+        execute-keys -draft l[px<a-k>^diff<ret>
+        set-register c git-diff-goto-source
+    } catch %{
+        evaluate-commands -draft %{
+            try %{
+                execute-keys <a-i>w # TODO this should include characters like -.@# etc
+            } catch %{
+                fail git-jump: no word at cursor
+            }
+            try %{
+                evaluate-commands %sh{
+                    [ "$(git rev-parse --revs-only "$kak_selection")" ] || echo fail
+                }
+            } catch %{
+                fail "git-jump: bad revision '%val{selection}'"
+            }
+            set-register c git show %val{selection} --
+        }
+    }
+    %reg{c}
+}}

Of course, if :git show is called while within :git log, it means that the user won't be able to go back to the log while seeing the patch, as they are using the same scratch buffer git. This could be mitigated if another scratch buffer is used so that the user could use ^O to jump back. But maybe it is not worth it to go that far.

I keep a stack of all git buffers - look for git-stack here

krobelus avatar Feb 09 '24 08:02 krobelus