{"thread":{"id":"34473","subject":"gitk: \"Show origin of this line\" triggered programatically","startedAt":"2013-07-18T17:38:22Z","lastAt":"2013-07-18T17:38:22Z","messageCount":1,"participants":["Stefan Haller"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"223669","messageId":"1l67wml.upjrrz1nq48l7M%lists@haller-berlin.de","threadId":"34473","inReplyTo":null,"subject":"gitk: \"Show origin of this line\" triggered programatically","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2013-07-18T17:38:22Z","receivedAt":"2013-07-18T17:38:22Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"The \"Show origin of this line\" context menu command on a line in a patch\nin gitk is by far my most frequently used way of navigating back in\nhistory. It's so much faster than git gui blame.\n\nNow, I wish it were available right from my text editor, showing me the\norigin of the line under the cursor when working with code.\n\nIn fact, it is; I have been using this feature in a roughly hacked way\nfor a couple of months now, and I don't want to miss it any more. Most\nof my co-workers are jealous when they see it.\n\nI'd like to get it into gitk for real now, and I need some guidance on\nthe best way to implement it.\n\nI can see two ways:\n\n1) Add an option like '--show-origin=foo.cpp:25'. This would run\n   \"git blame\" on the given line in the working copy, and highlight the\n   result.\n\n2) Add an option like '--select-file=foo.cpp:25'. This would be used in\n   combination with the existing --select-commit option to simply\n   highlight a given line in the patch (so the caller needs to do the\n   initial git blame himself).\n\nThere are pros and cons to both. 1) is certainly easier to use from a\ntext editor scripter's point of view (a simple one-liner in most cases),\nwhereas 2) probably needs a glue script to run the initial git blame. On\nthe other hand, that glue script could also take care of restricting the\nhistory to a week or so forward from the target commit, which makes gitk\nload much faster. Also, 2) could be used from git gui blame's \"Show\nhistory context\" command, which currently only selects the commit but\ncan't highlight the line.\n\nSo I think I'd lean towards option 2).  Below is the prototype that I\nhave been using; not sure how buggy it is. If we go this route, one\nquestion would be whether we want to ship the glue script too, and how.\n\nAny opinions?\n\n-Stefan\n\n\n\n>From 80acb168ef13a55521e9b821450800450660769d Mon Sep 17 00:00:00 2001\nFrom: Stefan Haller <stefan@haller-berlin.de>\nDate: Thu, 18 Jul 2013 18:55:11 +0200\nSubject: [PATCH] gitk: Add options --select-file and --select-line\n\nThese can be used in combination with --select-commit to jump to a given\nline in a patch. This can be useful for scripting your text editor to bring\nup gitk showing you the place in the history that last modified the line\nyou are on.\n\nFor example, given this little glue script, saved as \"show_line_in_gitk.rb\"\nsomewhere in your path:\n\n        #!/usr/bin/env ruby\n\n        if ARGV.length != 2\n          puts \"Usage: #{$0} <file> <line>\"\n          exit 1\n        end\n\n        file, line = ARGV\n        blame_output = `git blame -p -L#{line},+1 \"#{file}\"`\n        exit 1 if $?.exitstatus != 0\n\n        blame_output_lines = blame_output.split(\"\\n\")\n        commit, line = blame_output_lines[0].split\n\n        file = blame_output_lines.grep(/^filename /)[0][9..-1]\n        date = blame_output_lines.grep(/^committer-time /)[0][15..-1]\n        datestr = Time.at(date.to_i + 60 * 60 * 24 * 7).to_s\n\n        system \"gitk --before='#{datestr}' \\\n                --select-commit=#{commit} \\\n                --select-file='#{file}' \\\n                --select-line=#{line} &\"\n\nyou could add this function to your .vimrc:\n\n    function! ShowLineInGitk()\n        execute \"!show_line_in_gitk.rb \" . expand(\"%p\") . \" \" . line(\".\")\n    endfunction\n\nand map it to a key.\n---\n gitk | 32 +++++++++++++++++++++++++++++---\n 1 file changed, 29 insertions(+), 3 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex 5cd00d8..318a484 100755\n--- a/gitk\n+++ b/gitk\n@@ -464,12 +464,17 @@ proc stop_rev_list {view} {\n }\n \n proc reset_pending_select {selid} {\n-    global pending_select mainheadid selectheadid\n+    global pending_select pending_select_file pending_select_line\n+    global mainheadid selectheadid selectfile select_line\n \n     if {$selid ne {}} {\n        set pending_select $selid\n     } elseif {$selectheadid ne {}} {\n        set pending_select $selectheadid\n+       if {$selectfile ne {}} {\n+           set pending_select_file $selectfile\n+           set pending_select_line $select_line\n+       }\n     } else {\n        set pending_select $mainheadid\n     }\n@@ -1597,6 +1602,17 @@ proc getcommitlines {fd inst view updating}  {\n     return 2\n }\n \n+proc select_pending_line {} {\n+    global pending_select pending_select_file pending_select_line\n+\n+    if {[info exists pending_select_file]} {\n+       selectline [rowofcommit $pending_select] 1 \\\n+           [list $pending_select_file $pending_select_line]\n+    } else {\n+       selectline [rowofcommit $pending_select] 1\n+    }\n+}\n+\n proc chewcommits {} {\n     global curview hlview viewcomplete\n     global pending_select\n@@ -1611,7 +1627,7 @@ proc chewcommits {} {\n            reset_pending_select {}\n \n            if {[commitinview $pending_select $curview]} {\n-               selectline [rowofcommit $pending_select] 1\n+               select_pending_line\n            } else {\n                set row [first_real_row]\n                selectline $row 1\n@@ -5083,7 +5099,7 @@ proc layoutmore {} {\n     if {[info exists pending_select] &&\n        [commitinview $pending_select $curview]} {\n        update\n-       selectline [rowofcommit $pending_select] 1\n+       select_pending_line\n     }\n     drawvisible\n }\n@@ -7082,6 +7098,8 @@ proc selectline {l isnew {desired_loc {}}} {\n     global autoselect autosellen jump_to_here\n \n     catch {unset pending_select}\n+    catch {unset pending_select_file}\n+    catch {unset pending_select_line}\n     $canv delete hover\n     normalline\n     unsel_reflist\n@@ -11940,6 +11958,8 @@ if {[catch {set gitdir [exec git rev-parse --git-dir]}]} {\n \n set selecthead {}\n set selectheadid {}\n+set selectfile {}\n+set select_line {}\n \n set revtreeargs {}\n set cmdline_files {}\n@@ -11955,6 +11975,12 @@ foreach arg $argv {\n        \"--select-commit=*\" {\n            set selecthead [string range $arg 16 end]\n        }\n+       \"--select-file=*\" {\n+           set selectfile [string range $arg 14 end]\n+       }\n+       \"--select-line=*\" {\n+           set select_line [string range $arg 14 end]\n+       }\n        \"--argscmd=*\" {\n            set revtreeargscmd [string range $arg 10 end]\n        }\n-- \n1.8.3.2.747.g15edaa9\n\n\n-- \nStefan Haller\nBerlin, Germany\nhttp://www.haller-berlin.de/\n"}]}