{"thread":{"id":"15822","subject":"[PATCH 0/7] gitk: UI enhancements","startedAt":"2008-10-08T07:05:33Z","lastAt":"2008-10-26T03:58:31Z","messageCount":26,"participants":["Alexander Gavrilov","Paul Mackerras"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"92593","messageId":"1223449540-20457-1-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":null,"subject":"[PATCH 0/7] gitk: UI enhancements","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:33Z","receivedAt":"2008-10-08T07:05:33Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"This is a set of patches that enhance the UI in various ways.\nThey should be applied in order, and after the previous 4 patches\nthat deal with encodings. The previous set of patches is\napparently not applied yet, but I feel that I should not hold\nthese back any longer.\n\nIf Robin Rosenberg's series gets accepted first, I'll rebase\nand resend the patches.\n\n\nAlexander Gavrilov (7):\n      gitk: Enhance UI popup and accelerator handling.\n      gitk: Allow forcing branch creation if it already exists.\n      gitk: Allow starting gui blame for a specific line.\n      gitk: Fix file list context menu for merge commits.\n      gitk: Make cherry-pick call git-citool on conflicts.\n      gitk: Implement a user-friendly Edit View dialog.\n      gitk: Explicitly position popup windows.\n\n gitk |  550 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------\n 1 files changed, 471 insertions(+), 79 deletions(-)\n"},{"id":"92595","messageId":"1223449540-20457-2-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-1-git-send-email-angavrilov@gmail.com","subject":"[PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:34Z","receivedAt":"2008-10-08T07:05:34Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"- Popups are supposed to be marked transient, otherwise\n  the WM creates them in strange places. Besides, at\n  least under kwin, transients are automatically kept\n  above their parent.\n- Accelerators for menu items should be listed directly\n  on the items, to make them more discoverable.\n- Some more accelerators are added, e.g. F4 for Edit View.\n- Finally, dialogs can now be accepted or dismissed using\n  the Return and Escape keys.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |   96 ++++++++++++++++++++++++++++++++++++++++++++++++++----------------\n 1 files changed, 73 insertions(+), 23 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex e6c2a17..a4ef736 100755\n--- a/gitk\n+++ b/gitk\n@@ -1710,22 +1710,24 @@ proc show_error {w top msg} {\n     pack $w.ok -side bottom -fill x\n     bind $top <Visibility> \"grab $top; focus $top\"\n     bind $top <Key-Return> \"destroy $top\"\n+    bind $top <Key-space>  \"destroy $top\"\n+    bind $top <Key-Escape> \"destroy $top\"\n     tkwait window $top\n }\n \n-proc error_popup msg {\n+proc error_popup {msg {owner .}} {\n     set w .error\n     toplevel $w\n-    wm transient $w .\n+    wm transient $w $owner\n     show_error $w $w $msg\n }\n \n-proc confirm_popup msg {\n+proc confirm_popup {msg {owner .}} {\n     global confirm_ok\n     set confirm_ok 0\n     set w .confirm\n     toplevel $w\n-    wm transient $w .\n+    wm transient $w $owner\n     message $w.m -text $msg -justify center -aspect 400\n     pack $w.m -side top -fill x -padx 20 -pady 20\n     button $w.ok -text [mc OK] -command \"set confirm_ok 1; destroy $w\"\n@@ -1733,6 +1735,9 @@ proc confirm_popup msg {\n     button $w.cancel -text [mc Cancel] -command \"destroy $w\"\n     pack $w.cancel -side right -fill x\n     bind $w <Visibility> \"grab $w; focus $w\"\n+    bind $w <Key-Return> \"set confirm_ok 1; destroy $w\"\n+    bind $w <Key-space>  \"set confirm_ok 1; destroy $w\"\n+    bind $w <Key-Escape> \"destroy $w\"\n     tkwait window $w\n     return $confirm_ok\n }\n@@ -1767,22 +1772,28 @@ proc makewindow {} {\n     global rprogitem rprogcoord rownumsel numcommits\n     global have_tk85\n \n+    if {[tk windowingsystem] eq {aqua}} {\n+\tset M1T Cmd\n+    } else {\n+\tset M1T Ctrl\n+    }\n+\n     menu .bar\n     .bar add cascade -label [mc \"File\"] -menu .bar.file\n     menu .bar.file\n-    .bar.file add command -label [mc \"Update\"] -command updatecommits\n-    .bar.file add command -label [mc \"Reload\"] -command reloadcommits\n+    .bar.file add command -label [mc \"Update\"] -accelerator F5 -command updatecommits\n+    .bar.file add command -label [mc \"Reload\"] -accelerator $M1T-F5 -command reloadcommits\n     .bar.file add command -label [mc \"Reread references\"] -command rereadrefs\n-    .bar.file add command -label [mc \"List references\"] -command showrefs\n-    .bar.file add command -label [mc \"Quit\"] -command doquit\n+    .bar.file add command -label [mc \"List references\"] -accelerator F2 -command showrefs\n+    .bar.file add command -label [mc \"Quit\"] -accelerator $M1T-Q -command doquit\n     menu .bar.edit\n     .bar add cascade -label [mc \"Edit\"] -menu .bar.edit\n     .bar.edit add command -label [mc \"Preferences\"] -command doprefs\n \n     menu .bar.view\n     .bar add cascade -label [mc \"View\"] -menu .bar.view\n-    .bar.view add command -label [mc \"New view...\"] -command {newview 0}\n-    .bar.view add command -label [mc \"Edit view...\"] -command editview \\\n+    .bar.view add command -label [mc \"New view...\"] -accelerator Shift-F4 -command {newview 0}\n+    .bar.view add command -label [mc \"Edit view...\"] -accelerator F4 -command editview \\\n \t-state disabled\n     .bar.view add command -label [mc \"Delete view\"] -command delview -state disabled\n     .bar.view add separator\n@@ -2146,7 +2157,12 @@ proc makewindow {} {\n     bindkey <Key-Return> {dofind 1 1}\n     bindkey ? {dofind -1 1}\n     bindkey f nextfile\n-    bindkey <F5> updatecommits\n+    bind . <F5> updatecommits\n+    bind . <$M1B-F5> reloadcommits\n+    bind . <F2> showrefs\n+    bind . <Shift-F4> {newview 0}\n+    catch { bind . <Shift-Key-XF86_Switch_VT_4> {newview 0} }\n+    bind . <F4> edit_or_newview\n     bind . <$M1B-q> doquit\n     bind . <$M1B-f> {dofind 1 1}\n     bind . <$M1B-g> {dofind 1 0}\n@@ -2456,6 +2472,7 @@ proc about {} {\n     }\n     toplevel $w\n     wm title $w [mc \"About gitk\"]\n+    wm transient $w .\n     message $w.m -text [mc \"\n Gitk - a commit viewer for git\n \n@@ -2484,10 +2501,10 @@ proc keys {} {\n     }\n     toplevel $w\n     wm title $w [mc \"Gitk key bindings\"]\n+    wm transient $w .\n     message $w.m -text \"\n [mc \"Gitk key bindings:\"]\n \n-[mc \"<%s-Q>\t\tQuit\" $M1T]\n [mc \"<Home>\t\tMove to first commit\"]\n [mc \"<End>\t\tMove to last commit\"]\n [mc \"<Up>, p, i\tMove up one commit\"]\n@@ -2521,11 +2538,11 @@ proc keys {} {\n [mc \"<%s-plus>\tIncrease font size\" $M1T]\n [mc \"<%s-KP->\tDecrease font size\" $M1T]\n [mc \"<%s-minus>\tDecrease font size\" $M1T]\n-[mc \"<F5>\t\tUpdate\"]\n \" \\\n \t    -justify left -bg white -border 2 -relief groove\n     pack $w.m -side top -fill both -padx 2 -pady 2\n     button $w.ok -text [mc \"Close\"] -command \"destroy $w\" -default active\n+    bind $w <Key-Escape> [list destroy $w]\n     pack $w.ok -side bottom\n     bind $w <Visibility> \"focus $w.ok\"\n     bind $w <Key-Escape> \"destroy $w\"\n@@ -3171,6 +3188,16 @@ proc newview {ishighlight} {\n     vieweditor $top $nextviewnum [mc \"Gitk view definition\"]\n }\n \n+proc edit_or_newview {} {\n+    global curview\n+\n+    if {$curview > 0} {\n+\teditview\n+    } else {\n+\tnewview 0\n+    }\n+}\n+\n proc editview {} {\n     global curview\n     global viewname viewperm newviewname newviewperm\n@@ -3193,6 +3220,7 @@ proc vieweditor {top n title} {\n \n     toplevel $top\n     wm title $top $title\n+    wm transient $top .\n     label $top.nl -text [mc \"Name\"]\n     entry $top.name -width 20 -textvariable newviewname($n)\n     grid $top.nl $top.name -sticky w -pady 5\n@@ -3229,6 +3257,7 @@ proc vieweditor {top n title} {\n     frame $top.buts\n     button $top.buts.ok -text [mc \"OK\"] -command [list newviewok $top $n]\n     button $top.buts.can -text [mc \"Cancel\"] -command [list destroy $top]\n+    bind $top <Escape> [list destroy $top]\n     grid $top.buts.ok $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n@@ -3261,9 +3290,7 @@ proc newviewok {top n} {\n     if {[catch {\n \tset newargs [shellsplit $newviewargs($n)]\n     } err]} {\n-\terror_popup \"[mc \"Error in commit selection arguments:\"] $err\"\n-\twm raise $top\n-\tfocus $top\n+\terror_popup \"[mc \"Error in commit selection arguments:\"] $err\" $top\n \treturn\n     }\n     set files {}\n@@ -7367,6 +7394,7 @@ proc mkpatch {} {\n     set patchtop $top\n     catch {destroy $top}\n     toplevel $top\n+    wm transient $top .\n     label $top.title -text [mc \"Generate patch\"]\n     grid $top.title - -pady 10\n     label $top.from -text [mc \"From:\"]\n@@ -7397,6 +7425,8 @@ proc mkpatch {} {\n     frame $top.buts\n     button $top.buts.gen -text [mc \"Generate\"] -command mkpatchgo\n     button $top.buts.can -text [mc \"Cancel\"] -command mkpatchcan\n+    bind $top <Key-Return> mkpatchgo\n+    bind $top <Key-Escape> mkpatchcan\n     grid $top.buts.gen $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n@@ -7431,7 +7461,7 @@ proc mkpatchgo {} {\n     set cmd [lrange $cmd 1 end]\n     lappend cmd >$fname &\n     if {[catch {eval exec $cmd} err]} {\n-\terror_popup \"[mc \"Error creating patch:\"] $err\"\n+\terror_popup \"[mc \"Error creating patch:\"] $err\" $patchtop\n     }\n     catch {destroy $patchtop}\n     unset patchtop\n@@ -7451,6 +7481,7 @@ proc mktag {} {\n     set mktagtop $top\n     catch {destroy $top}\n     toplevel $top\n+    wm transient $top .\n     label $top.title -text [mc \"Create tag\"]\n     grid $top.title - -pady 10\n     label $top.id -text [mc \"ID:\"]\n@@ -7468,6 +7499,8 @@ proc mktag {} {\n     frame $top.buts\n     button $top.buts.gen -text [mc \"Create\"] -command mktaggo\n     button $top.buts.can -text [mc \"Cancel\"] -command mktagcan\n+    bind $top <Key-Return> mktaggo\n+    bind $top <Key-Escape> mktagcan\n     grid $top.buts.gen $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n@@ -7481,17 +7514,17 @@ proc domktag {} {\n     set id [$mktagtop.sha1 get]\n     set tag [$mktagtop.tag get]\n     if {$tag == {}} {\n-\terror_popup [mc \"No tag name specified\"]\n+\terror_popup [mc \"No tag name specified\"] $mktagtop\n \treturn\n     }\n     if {[info exists tagids($tag)]} {\n-\terror_popup [mc \"Tag \\\"%s\\\" already exists\" $tag]\n+\terror_popup [mc \"Tag \\\"%s\\\" already exists\" $tag] $mktagtop\n \treturn\n     }\n     if {[catch {\n \texec git tag $tag $id\n     } err]} {\n-\terror_popup \"[mc \"Error creating tag:\"] $err\"\n+\terror_popup \"[mc \"Error creating tag:\"] $err\" $mktagtop\n \treturn\n     }\n \n@@ -7501,6 +7534,7 @@ proc domktag {} {\n     addedtag $id\n     dispneartags 0\n     run refill_reflist\n+    return 1\n }\n \n proc redrawtags {id} {\n@@ -7539,7 +7573,7 @@ proc mktagcan {} {\n }\n \n proc mktaggo {} {\n-    domktag\n+    if {![domktag]} return\n     mktagcan\n }\n \n@@ -7550,6 +7584,7 @@ proc writecommit {} {\n     set wrcomtop $top\n     catch {destroy $top}\n     toplevel $top\n+    wm transient $top .\n     label $top.title -text [mc \"Write commit to file\"]\n     grid $top.title - -pady 10\n     label $top.id -text [mc \"ID:\"]\n@@ -7571,6 +7606,8 @@ proc writecommit {} {\n     frame $top.buts\n     button $top.buts.gen -text [mc \"Write\"] -command wrcomgo\n     button $top.buts.can -text [mc \"Cancel\"] -command wrcomcan\n+    bind $top <Key-Return> wrcomgo\n+    bind $top <Key-Escape> wrcomcan\n     grid $top.buts.gen $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n@@ -7585,7 +7622,7 @@ proc wrcomgo {} {\n     set cmd \"echo $id | [$wrcomtop.cmd get]\"\n     set fname [$wrcomtop.fname get]\n     if {[catch {exec sh -c $cmd >$fname &} err]} {\n-\terror_popup \"[mc \"Error writing commit:\"] $err\"\n+\terror_popup \"[mc \"Error writing commit:\"] $err\" $wrcomtop\n     }\n     catch {destroy $wrcomtop}\n     unset wrcomtop\n@@ -7604,6 +7641,7 @@ proc mkbranch {} {\n     set top .makebranch\n     catch {destroy $top}\n     toplevel $top\n+    wm transient $top .\n     label $top.title -text [mc \"Create new branch\"]\n     grid $top.title - -pady 10\n     label $top.id -text [mc \"ID:\"]\n@@ -7617,6 +7655,8 @@ proc mkbranch {} {\n     frame $top.buts\n     button $top.buts.go -text [mc \"Create\"] -command [list mkbrgo $top]\n     button $top.buts.can -text [mc \"Cancel\"] -command \"catch {destroy $top}\"\n+    bind $top <Key-Return> [list mkbrgo $top]\n+    bind $top <Key-Escape> \"catch {destroy $top}\"\n     grid $top.buts.go $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n@@ -7630,7 +7670,7 @@ proc mkbrgo {top} {\n     set name [$top.name get]\n     set id [$top.sha1 get]\n     if {$name eq {}} {\n-\terror_popup [mc \"Please specify a name for the new branch\"]\n+\terror_popup [mc \"Please specify a name for the new branch\"] $top\n \treturn\n     }\n     catch {destroy $top}\n@@ -7723,6 +7763,7 @@ proc resethead {} {\n     button $w.ok -text [mc OK] -command \"set confirm_ok 1; destroy $w\"\n     pack $w.ok -side left -fill x -padx 20 -pady 20\n     button $w.cancel -text [mc Cancel] -command \"destroy $w\"\n+    bind $w <Key-Escape> [list destroy $w]\n     pack $w.cancel -side right -fill x -padx 20 -pady 20\n     bind $w <Visibility> \"grab $w; focus $w\"\n     tkwait window $w\n@@ -7879,6 +7920,7 @@ proc showrefs {} {\n     }\n     toplevel $top\n     wm title $top [mc \"Tags and heads: %s\" [file tail [pwd]]]\n+    wm transient $top .\n     text $top.list -background $bgcolor -foreground $fgcolor \\\n \t-selectbackground $selectbgcolor -font mainfont \\\n \t-xscrollcommand \"$top.xsb set\" -yscrollcommand \"$top.ysb set\" \\\n@@ -7900,6 +7942,7 @@ proc showrefs {} {\n     pack $top.f.l -side left\n     grid $top.f - -sticky ew -pady 2\n     button $top.close -command [list destroy $top] -text [mc \"Close\"]\n+    bind $top <Key-Escape> [list destroy $top]\n     grid $top.close -\n     grid columnconfigure $top 0 -weight 1\n     grid rowconfigure $top 0 -weight 1\n@@ -9205,6 +9248,7 @@ proc mkfontdisp {font top which} {\n \n proc choosefont {font which} {\n     global fontparam fontlist fonttop fontattr\n+    global prefstop\n \n     set fontparam(which) $which\n     set fontparam(font) $font\n@@ -9218,6 +9262,7 @@ proc choosefont {font which} {\n \tfont create sample\n \teval font config sample [font actual $font]\n \ttoplevel $top\n+\twm transient $top $prefstop\n \twm title $top [mc \"Gitk font chooser\"]\n \tlabel $top.l -textvariable fontparam(which)\n \tpack $top.l -side top\n@@ -9251,6 +9296,8 @@ proc choosefont {font which} {\n \tframe $top.buts\n \tbutton $top.buts.ok -text [mc \"OK\"] -command fontok -default active\n \tbutton $top.buts.can -text [mc \"Cancel\"] -command fontcan -default normal\n+\tbind $top <Key-Return> fontok\n+\tbind $top <Key-Escape> fontcan\n \tgrid $top.buts.ok $top.buts.can\n \tgrid columnconfigure $top.buts 0 -weight 1 -uniform a\n \tgrid columnconfigure $top.buts 1 -weight 1 -uniform a\n@@ -9332,6 +9379,7 @@ proc doprefs {} {\n     }\n     toplevel $top\n     wm title $top [mc \"Gitk preferences\"]\n+    wm transient $top .\n     label $top.ldisp -text [mc \"Commit list display options\"]\n     grid $top.ldisp - -sticky w -pady 10\n     label $top.spacer -text \" \"\n@@ -9419,6 +9467,8 @@ proc doprefs {} {\n     frame $top.buts\n     button $top.buts.ok -text [mc \"OK\"] -command prefsok -default active\n     button $top.buts.can -text [mc \"Cancel\"] -command prefscan -default normal\n+    bind $top <Key-Return> prefsok\n+    bind $top <Key-Escape> prefscan\n     grid $top.buts.ok $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n-- \n1.6.0.20.g6148bc\n"},{"id":"92594","messageId":"1223449540-20457-3-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-2-git-send-email-angavrilov@gmail.com","subject":"[PATCH 2/7] gitk: Allow forcing branch creation if it already exists.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:35Z","receivedAt":"2008-10-08T07:05:35Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"If gitk knows that the branch the user tries to create exists,\nit should ask whether it should overwrite it. This way the user\ncan either decide to choose a new name, or move the head while\npreserving the reflog.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |   28 +++++++++++++++++++++++-----\n 1 files changed, 23 insertions(+), 5 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex a4ef736..96ca965 100755\n--- a/gitk\n+++ b/gitk\n@@ -7669,24 +7669,42 @@ proc mkbrgo {top} {\n \n     set name [$top.name get]\n     set id [$top.sha1 get]\n+    set cmdargs [list]\n+    set old_id {}\n     if {$name eq {}} {\n \terror_popup [mc \"Please specify a name for the new branch\"] $top\n \treturn\n     }\n+    if {[info exists headids($name)]} {\n+\tif {![confirm_popup [mc \\\n+\t\t\"Branch '%s' already exists. Overwrite?\" $name] $top]} {\n+\t    return\n+\t}\n+\tset old_id $headids($name)\n+\tlappend cmdargs -f\n+    }\n     catch {destroy $top}\n+    lappend cmdargs $name $id\n     nowbusy newbranch\n     update\n     if {[catch {\n-\texec git branch $name $id\n+\teval exec git branch $cmdargs\n     } err]} {\n \tnotbusy newbranch\n \terror_popup $err\n     } else {\n-\tset headids($name) $id\n-\tlappend idheads($id) $name\n-\taddedhead $id $name\n \tnotbusy newbranch\n-\tredrawtags $id\n+\tif {$old_id ne {}} {\n+\t    movehead $id $name\n+\t    movedhead $id $name\n+\t    redrawtags $old_id\n+\t    redrawtags $id\n+\t} else {\n+\t    set headids($name) $id\n+\t    lappend idheads($id) $name\n+\t    addedhead $id $name\n+\t    redrawtags $id\n+\t}\n \tdispneartags 0\n \trun refill_reflist\n     }\n-- \n1.6.0.20.g6148bc\n"},{"id":"92597","messageId":"1223449540-20457-4-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-3-git-send-email-angavrilov@gmail.com","subject":"[PATCH 3/7] gitk: Allow starting gui blame for a specific line.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:36Z","receivedAt":"2008-10-08T07:05:36Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"Adds a context menu item to the diff viewer pane that\ncalls blame, focusing it on the clicked line. In case\nof combined diffs, it also automatically deduces which\nparent is to be blamed.\n\nThe context menu itself is added by this patch. It is\npossible to populate it with commands from the flist\nmenu.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 133 insertions(+), 2 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex 96ca965..3c77909 100755\n--- a/gitk\n+++ b/gitk\n@@ -2184,6 +2184,7 @@ proc makewindow {} {\n     bind $cflist <ButtonRelease-1> {treeclick %W %x %y}\n     global ctxbut\n     bind $cflist $ctxbut {pop_flist_menu %W %X %Y %x %y}\n+    bind $ctext $ctxbut {pop_diff_menu %W %X %Y %x %y}\n \n     set maincursor [. cget -cursor]\n     set textcursor [$ctext cget -cursor]\n@@ -2233,6 +2234,12 @@ proc makewindow {} {\n         -command {external_diff}\n     $flist_menu add command -label [mc \"Blame parent commit\"] \\\n         -command {external_blame 1}\n+\n+    global diff_menu\n+    set diff_menu .diffctxmenu\n+    menu $diff_menu -tearoff 0\n+    $diff_menu add command -label [mc \"Blame parent commit\"] \\\n+        -command {external_blame_diff}\n }\n \n # Windows sends all mouse wheel events to the current focused window, not\n@@ -2935,6 +2942,34 @@ proc pop_flist_menu {w X Y x y} {\n     tk_popup $flist_menu $X $Y\n }\n \n+proc find_ctext_fileinfo {line} {\n+    global ctext_file_names ctext_file_lines\n+\n+    set ok [bsearch $ctext_file_lines $line]\n+    set tline [lindex $ctext_file_lines $ok]\n+\n+    if {$ok >= [llength $ctext_file_lines] || $line < $tline} {\n+        return {}\n+    } else {\n+        return [list [lindex $ctext_file_names $ok] $tline]\n+    }\n+}\n+\n+proc pop_diff_menu {w X Y x y} {\n+    global ctext diff_menu flist_menu_file\n+    global diff_menu_txtpos diff_menu_line\n+    global diff_menu_filebase\n+\n+    stopfinding\n+    set diff_menu_txtpos [split [$w index \"@$x,$y\"] \".\"]\n+    set diff_menu_line [lindex $diff_menu_txtpos 0]\n+    set f [find_ctext_fileinfo $diff_menu_line]\n+    if {$f eq {}} return\n+    set flist_menu_file [lindex $f 0]\n+    set diff_menu_filebase [lindex $f 1]\n+    tk_popup $diff_menu $X $Y\n+}\n+\n proc flist_hl {only} {\n     global flist_menu_file findstring gdttype\n \n@@ -3041,7 +3076,84 @@ proc external_diff {} {\n     }\n }\n \n-proc external_blame {parent_idx} {\n+proc find_hunk_blamespec {base line} {\n+    global ctext\n+\n+    # Find and parse the hunk header\n+    set s_lix [$ctext search -backwards -regexp ^@@ \"$line.0 lineend\" $base.0]\n+    if {$s_lix eq {}} return\n+\n+    set s_line [$ctext get $s_lix \"$s_lix + 1 lines\"]\n+    if {![regexp {^@@@?(( -\\d+(,\\d+)?)+) \\+(\\d+)(,\\d+)? @@} $s_line \\\n+\t    s_line old_specs osz osz1 new_line nsz]} {\n+\treturn\n+    }\n+\n+    # base lines for the parents\n+    set old_lines [list]\n+    foreach old_spec [lrange [split $old_specs \" \"] 1 end] {\n+\tif {![regexp -- {-(\\d+)(,\\d+)?} $old_spec \\\n+\t        old_spec old_line osz]} {\n+\t    return\n+\t}\n+\tlappend old_lines $old_line\n+    }\n+\n+    # Now scan the lines to determine offset within the hunk\n+    set parent {}\n+    set dline 0\n+    set s_lno [lindex [split $s_lix \".\"] 0]\n+\n+    for {set i $line} {$i > $s_lno} {incr i -1} {\n+\tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n+\tif {$parent eq {}} {\n+\t    # find first preceeding line that belongs to some parent\n+\t    for {set j 0} {$j < [llength $old_lines]} {incr j} {\n+\t\tset code [string index $c_line $j]\n+\t\tif {$code ne {-} && $code ne { }} continue\n+\t\tif {$code eq { } && $parent ne {}} continue\n+\t\tset parent $j\n+\t\tif {$code eq {-}} break\n+\t    }\n+\t}\n+\tif {$parent ne {}} {\n+\t    # then count other lines that belong to it\n+\t    set code [string index $c_line $parent]\n+\t    if {$code ne {+}} {\n+\t\tincr dline\n+\t    }\n+\t}\n+    }\n+\n+    if {$parent eq {}} { set parent 0 }\n+    incr dline [lindex $old_lines $parent]\n+    incr parent\n+    return [list $parent $dline]\n+}\n+\n+proc external_blame_diff {} {\n+    global currentid diffmergeid cmitmode\n+    global diff_menu_txtpos diff_menu_line\n+    global diff_menu_filebase flist_menu_file\n+\n+    if {$cmitmode eq \"tree\"} {\n+\tset parent_idx 1\n+\tset line [expr {$diff_menu_line - $diff_menu_filebase - 1}]\n+    } else {\n+\tset hinfo [find_hunk_blamespec $diff_menu_filebase $diff_menu_line]\n+\tif {$hinfo ne {}} {\n+\t    set parent_idx [lindex $hinfo 0]\n+\t    set line [lindex $hinfo 1]\n+\t} else {\n+\t    set parent_idx 1\n+\t    set line 0\n+\t}\n+    }\n+\n+    external_blame $parent_idx $line\n+}\n+\n+proc external_blame {parent_idx {line {}}} {\n     global flist_menu_file\n     global nullid nullid2\n     global parentlist selectedline currentid\n@@ -3057,7 +3169,12 @@ proc external_blame {parent_idx} {\n \treturn\n     }\n \n-    if {[catch {exec git gui blame $base_commit $flist_menu_file &} err]} {\n+    set cmdline [list git gui blame]\n+    if {$line ne {} && $line > 1} {\n+\tlappend cmdline \"--line=$line\"\n+    }\n+    lappend cmdline $base_commit $flist_menu_file\n+    if {[catch {eval exec $cmdline &} err]} {\n \terror_popup \"[mc \"git gui blame: command failed:\"] $err\"\n     }\n }\n@@ -6305,6 +6422,7 @@ proc gettreeline {gtf id} {\n \n proc showfile {f} {\n     global treefilelist treeidlist diffids nullid nullid2\n+    global ctext_file_names ctext_file_lines\n     global ctext commentend\n \n     set i [lsearch -exact $treefilelist($diffids) $f]\n@@ -6328,6 +6446,8 @@ proc showfile {f} {\n     filerun $bf [list getblobline $bf $diffids]\n     $ctext config -state normal\n     clear_ctext $commentend\n+    lappend ctext_file_names $f\n+    lappend ctext_file_lines [lindex [split $commentend \".\"] 0]\n     $ctext insert end \"\\n\"\n     $ctext insert end \"$f\\n\" filesep\n     $ctext config -state disabled\n@@ -6387,6 +6507,7 @@ proc mergediff {id} {\n proc getmergediffline {mdf id np} {\n     global diffmergeid ctext cflist mergemax\n     global difffilestart mdifffd\n+    global ctext_file_names ctext_file_lines\n     global diffencoding\n \n     $ctext conf -state normal\n@@ -6404,6 +6525,8 @@ proc getmergediffline {mdf id np} {\n \t    set here [$ctext index \"end - 1c\"]\n \t    lappend difffilestart $here\n \t    add_flist [list $fname]\n+\t    lappend ctext_file_names $fname\n+\t    lappend ctext_file_lines [lindex [split $here \".\"] 0]\n \t    set diffencoding [get_cached_encoding $fname]\n \t    set l [expr {(78 - [string length $fname]) / 2}]\n \t    set pad [string range \"----------------------------------------\" 1 $l]\n@@ -6661,11 +6784,13 @@ proc setinlist {var i val} {\n \n proc makediffhdr {fname ids} {\n     global ctext curdiffstart treediffs\n+    global ctext_file_names\n \n     set i [lsearch -exact $treediffs($ids) $fname]\n     if {$i >= 0} {\n \tsetinlist difffilestart $i $curdiffstart\n     }\n+    set ctext_file_names [lreplace $ctext_file_names end end $fname]\n     set l [expr {(78 - [string length $fname]) / 2}]\n     set pad [string range \"----------------------------------------\" 1 $l]\n     $ctext insert $curdiffstart \"$pad $fname $pad\" filesep\n@@ -6674,6 +6799,7 @@ proc makediffhdr {fname ids} {\n proc getblobdiffline {bdf ids} {\n     global diffids blobdifffd ctext curdiffstart\n     global diffnexthead diffnextnote difffilestart\n+    global ctext_file_names ctext_file_lines\n     global diffinhdr treediffs\n     global diffencoding\n \n@@ -6691,6 +6817,8 @@ proc getblobdiffline {bdf ids} {\n \t    # start of a new file\n \t    $ctext insert end \"\\n\"\n \t    set curdiffstart [$ctext index \"end - 1c\"]\n+\t    lappend ctext_file_names \"\"\n+\t    lappend ctext_file_lines [lindex [split $curdiffstart \".\"] 0]\n \t    $ctext insert end \"\\n\" filesep\n \t    # If the name hasn't changed the length will be odd,\n \t    # the middle char will be a space, and the two bits either\n@@ -6827,6 +6955,7 @@ proc nextfile {} {\n \n proc clear_ctext {{first 1.0}} {\n     global ctext smarktop smarkbot\n+    global ctext_file_names ctext_file_lines\n     global pendinglinks\n \n     set l [lindex [split $first .] 0]\n@@ -6840,6 +6969,8 @@ proc clear_ctext {{first 1.0}} {\n     if {$first eq \"1.0\"} {\n \tcatch {unset pendinglinks}\n     }\n+    set ctext_file_names {}\n+    set ctext_file_lines {}\n }\n \n proc settabs {{firstab {}}} {\n-- \n1.6.0.20.g6148bc\n"},{"id":"92599","messageId":"1223449540-20457-5-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-4-git-send-email-angavrilov@gmail.com","subject":"[PATCH 4/7] gitk: Fix file list context menu for merge commits.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:37Z","receivedAt":"2008-10-08T07:05:37Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"Currently it displays an ugly error box, because the\ntreediffs array is not filled for such commits. This\nis clearly unacceptable.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |    6 ++++--\n 1 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex 3c77909..cfaf7a1 100755\n--- a/gitk\n+++ b/gitk\n@@ -6479,7 +6479,7 @@ proc getblobline {bf id} {\n \n proc mergediff {id} {\n     global diffmergeid mdifffd\n-    global diffids\n+    global diffids treediffs\n     global parents\n     global diffcontext\n     global diffencoding\n@@ -6487,6 +6487,7 @@ proc mergediff {id} {\n \n     set diffmergeid $id\n     set diffids $id\n+    set treediffs($id) [list ]\n     # this doesn't seem to actually affect anything...\n     set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id]\n     if {$limitdiffs && $vfilelimit($curview) ne {}} {\n@@ -6506,7 +6507,7 @@ proc mergediff {id} {\n \n proc getmergediffline {mdf id np} {\n     global diffmergeid ctext cflist mergemax\n-    global difffilestart mdifffd\n+    global difffilestart mdifffd treediffs\n     global ctext_file_names ctext_file_lines\n     global diffencoding\n \n@@ -6524,6 +6525,7 @@ proc getmergediffline {mdf id np} {\n \t    $ctext insert end \"\\n\"\n \t    set here [$ctext index \"end - 1c\"]\n \t    lappend difffilestart $here\n+\t    lappend treediffs($id) $fname\n \t    add_flist [list $fname]\n \t    lappend ctext_file_names $fname\n \t    lappend ctext_file_lines [lindex [split $here \".\"] 0]\n-- \n1.6.0.20.g6148bc\n"},{"id":"92596","messageId":"1223449540-20457-6-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-5-git-send-email-angavrilov@gmail.com","subject":"[PATCH 5/7] gitk: Make cherry-pick call git-citool on conflicts.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:38Z","receivedAt":"2008-10-08T07:05:38Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"Now that git-gui has facilities to help users resolve\nconflicts, it makes sense to launch it from other gui\ntools when they happen.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 58 insertions(+), 1 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex cfaf7a1..e84e109 100755\n--- a/gitk\n+++ b/gitk\n@@ -7843,6 +7843,53 @@ proc mkbrgo {top} {\n     }\n }\n \n+proc exec_citool {args {baseid {}}} {\n+    global commitinfo env\n+\n+    if {[info exists env(GIT_AUTHOR_NAME)]} {\n+\tset old_name $env(GIT_AUTHOR_NAME)\n+    }\n+    if {[info exists env(GIT_AUTHOR_EMAIL)]} {\n+\tset old_email $env(GIT_AUTHOR_EMAIL)\n+    }\n+    if {[info exists env(GIT_AUTHOR_DATE)]} {\n+\tset old_date $env(GIT_AUTHOR_DATE)\n+    }\n+\n+    if {$baseid ne {}} {\n+\tif {![info exists commitinfo($baseid)]} {\n+\t    getcommit $baseid\n+\t}\n+\tset author [lindex $commitinfo($baseid) 1]\n+\tset date [lindex $commitinfo($baseid) 2]\n+\tif {[regexp {^\\s*(\\S.*\\S|\\S)\\s*<(.*)>\\s*$} \\\n+\t            $author author name email]\n+\t    && $date ne {}} {\n+\t    set env(GIT_AUTHOR_NAME) $name\n+\t    set env(GIT_AUTHOR_EMAIL) $email\n+\t    set env(GIT_AUTHOR_DATE) $date\n+\t}\n+    }\n+\n+    eval exec git citool $args &\n+\n+    if {[info exists old_name]} {\n+\tset env(GIT_AUTHOR_NAME) $old_name\n+    } else {\n+\tunset env(GIT_AUTHOR_NAME)\n+    }\n+    if {[info exists old_email]} {\n+\tset env(GIT_AUTHOR_EMAIL) $old_email\n+    } else {\n+\tunset env(GIT_AUTHOR_EMAIL)\n+    }\n+    if {[info exists old_date]} {\n+\tset env(GIT_AUTHOR_DATE) $old_date\n+    } else {\n+\tunset env(GIT_AUTHOR_DATE)\n+    }\n+}\n+\n proc cherrypick {} {\n     global rowmenuid curview\n     global mainhead mainheadid\n@@ -7861,7 +7908,17 @@ proc cherrypick {} {\n     # no error occurs, and exec takes that as an indication of error...\n     if {[catch {exec sh -c \"git cherry-pick -r $rowmenuid 2>&1\"} err]} {\n \tnotbusy cherrypick\n-\terror_popup $err\n+\tif {[regexp -line \\\n+\t    {Entry '(.*)' would be overwritten by merge} $err msg fname]} {\n+\t    error_popup [mc \"Cherry-pick failed: file '%s' had local modifications.\n+Your working directory is in an inconsistent state.\" $fname]\n+\t} elseif {[regexp -line {^CONFLICT \\(.*\\):} $err msg]} {\n+\t    # Force citool to read MERGE_MSG\n+\t    file delete [file join [gitdir] \"GITGUI_MSG\"]\n+\t    exec_citool [list] $rowmenuid\n+\t} else {\n+\t    error_popup $err\n+\t}\n \treturn\n     }\n     set newhead [exec git rev-parse HEAD]\n-- \n1.6.0.20.g6148bc\n"},{"id":"92598","messageId":"1223449540-20457-7-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-6-git-send-email-angavrilov@gmail.com","subject":"[PATCH 6/7] gitk: Implement a user-friendly Edit View dialog.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:39Z","receivedAt":"2008-10-08T07:05:39Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"Originally gitk required the user to specify all limiting\noptions manually in the same field with the list of commits.\nIt is extremely unfriendly for new users, who may not know\nwhich options can be used, or, indeed, that it is possible\nto specify them at all.\n\nThis patch modifies the dialog to present the most useful\noptions as individual fields. Note that options that may\nbe useful to an extent, but produce broken view, are\ndeliberately not included.\n\nIt is still possible to specify options in the commit list\nfield, but when the dialog is reopened, they will be extracted\ninto their own separate fields.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |  207 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------\n 1 files changed, 163 insertions(+), 44 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex e84e109..c7dd487 100755\n--- a/gitk\n+++ b/gitk\n@@ -3289,8 +3289,8 @@ proc shellsplit {str} {\n # Code to implement multiple views\n \n proc newview {ishighlight} {\n-    global nextviewnum newviewname newviewperm newishighlight\n-    global newviewargs revtreeargs viewargscmd newviewargscmd curview\n+    global nextviewnum newviewname newishighlight\n+    global revtreeargs viewargscmd newviewopts curview\n \n     set newishighlight $ishighlight\n     set top .gitkview\n@@ -3299,9 +3299,9 @@ proc newview {ishighlight} {\n \treturn\n     }\n     set newviewname($nextviewnum) \"[mc \"View\"] $nextviewnum\"\n-    set newviewperm($nextviewnum) 0\n-    set newviewargs($nextviewnum) [shellarglist $revtreeargs]\n-    set newviewargscmd($nextviewnum) $viewargscmd($curview)\n+    set newviewopts($nextviewnum,perm) 0\n+    set newviewopts($nextviewnum,cmd)  $viewargscmd($curview)\n+    decode_view_opts $nextviewnum $revtreeargs\n     vieweditor $top $nextviewnum [mc \"Gitk view definition\"]\n }\n \n@@ -3315,53 +3315,167 @@ proc edit_or_newview {} {\n     }\n }\n \n+set known_view_options {\n+    {perm    b    . {}               {mc \"Remember this view\"}}\n+    {args    t50= + {}               {mc \"Commits to include (arguments to git log):\"}}\n+    {all     b    * \"--all\"          {mc \"Use all refs\"}}\n+    {dorder  b    . {\"--date-order\" \"-d\"}      {mc \"Strictly sort by date\"}}\n+    {lright  b    . \"--left-right\"   {mc \"Mark branch sides\"}}\n+    {since   t15  + {\"--since=*\" \"--after=*\"}  {mc \"Since date:\"}}\n+    {until   t15  . {\"--until=*\" \"--before=*\"} {mc \"Until date:\"}}\n+    {limit   t10  + \"--max-count=*\"  {mc \"Max count:\"}}\n+    {skip    t10  . \"--skip=*\"       {mc \"Skip:\"}}\n+    {first   b    . \"--first-parent\" {mc \"Limit to first parent\"}}\n+    {cmd     t50= + {}               {mc \"Command to generate more commits to include:\"}}\n+    }\n+\n+proc encode_view_opts {n} {\n+    global known_view_options newviewopts\n+\n+    set rargs [list]\n+    foreach opt $known_view_options {\n+\tset patterns [lindex $opt 3]\n+\tif {$patterns eq {}} continue\n+\tset pattern [lindex $patterns 0]\n+\n+\tset val $newviewopts($n,[lindex $opt 0])\n+\t\n+\tif {[lindex $opt 1] eq \"b\"} {\n+\t    if {$val} {\n+\t\tlappend rargs $pattern\n+\t    }\n+\t} else {\n+\t    set val [string trim $val]\n+\t    if {$val ne {}} {\n+\t\tset pfix [string range $pattern 0 end-1]\n+\t\tlappend rargs $pfix$val\n+\t    }\n+\t}\n+    }\n+    return [concat $rargs [shellsplit $newviewopts($n,args)]]\n+}\n+\n+proc decode_view_opts {n view_args} {\n+    global known_view_options newviewopts\n+\n+    foreach opt $known_view_options {\n+\tif {[lindex $opt 1] eq \"b\"} {\n+\t    set val 0\n+\t} else {\n+\t    set val {}\n+\t}\n+\tset newviewopts($n,[lindex $opt 0]) $val\n+    }\n+    set oargs [list]\n+    foreach arg $view_args {\n+\tif {[regexp -- {^-([0-9]+)$} $arg arg cnt]\n+\t    && ![info exists found(limit)]} {\n+\t    set newviewopts($n,limit) $cnt\n+\t    set found(limit) 1\n+\t    continue\n+\t}\n+\tcatch { unset val }\n+\tforeach opt $known_view_options {\n+\t    set id [lindex $opt 0]\n+\t    if {[info exists found($id)]} continue\n+\t    foreach pattern [lindex $opt 3] {\n+\t\tif {![string match $pattern $arg]} continue\n+\t\tif {[lindex $opt 1] ne \"b\"} {\n+\t\t    set size [string length $pattern]\n+\t\t    set val [string range $arg [expr {$size-1}] end]\n+\t\t} else {\n+\t\t    set val 1\n+\t\t}\n+\t\tset newviewopts($n,$id) $val\n+\t\tset found($id) 1\n+\t\tbreak\n+\t    }\n+\t    if {[info exists val]} break\n+\t}\n+\tif {[info exists val]} continue\n+\tlappend oargs $arg\n+    }\n+    set newviewopts($n,args) [shellarglist $oargs]\n+}\n+\n proc editview {} {\n     global curview\n-    global viewname viewperm newviewname newviewperm\n-    global viewargs newviewargs viewargscmd newviewargscmd\n+    global viewname viewperm newviewname newviewopts\n+    global viewargs viewargscmd\n \n     set top .gitkvedit-$curview\n     if {[winfo exists $top]} {\n \traise $top\n \treturn\n     }\n-    set newviewname($curview) $viewname($curview)\n-    set newviewperm($curview) $viewperm($curview)\n-    set newviewargs($curview) [shellarglist $viewargs($curview)]\n-    set newviewargscmd($curview) $viewargscmd($curview)\n+    set newviewname($curview)      $viewname($curview)\n+    set newviewopts($curview,perm) $viewperm($curview)\n+    set newviewopts($curview,cmd)  $viewargscmd($curview)\n+    decode_view_opts $curview $viewargs($curview)\n     vieweditor $top $curview \"Gitk: edit view $viewname($curview)\"\n }\n \n proc vieweditor {top n title} {\n-    global newviewname newviewperm viewfiles bgcolor\n+    global newviewname newviewopts viewfiles bgcolor\n+    global known_view_options\n \n     toplevel $top\n     wm title $top $title\n     wm transient $top .\n+\n+    # View name\n+    frame $top.nfr\n     label $top.nl -text [mc \"Name\"]\n     entry $top.name -width 20 -textvariable newviewname($n)\n-    grid $top.nl $top.name -sticky w -pady 5\n-    checkbutton $top.perm -text [mc \"Remember this view\"] \\\n-\t-variable newviewperm($n)\n-    grid $top.perm - -pady 5 -sticky w\n-    message $top.al -aspect 1000 \\\n-\t-text [mc \"Commits to include (arguments to git log):\"]\n-    grid $top.al - -sticky w -pady 5\n-    entry $top.args -width 50 -textvariable newviewargs($n) \\\n-\t-background $bgcolor\n-    grid $top.args - -sticky ew -padx 5\n-\n-    message $top.ac -aspect 1000 \\\n-\t-text [mc \"Command to generate more commits to include:\"]\n-    grid $top.ac - -sticky w -pady 5\n-    entry $top.argscmd -width 50 -textvariable newviewargscmd($n) \\\n-\t-background white\n-    grid $top.argscmd - -sticky ew -padx 5\n-\n-    message $top.l -aspect 1000 \\\n+    pack $top.nfr -in $top -fill x -pady 5 -padx 3\n+    pack $top.nl -in $top.nfr -side left -padx {0 30}\n+    pack $top.name -in $top.nfr -side left\n+\n+    # View options\n+    set cframe $top.nfr\n+    set cexpand 0\n+    set cnt 0\n+    foreach opt $known_view_options {\n+\tset id [lindex $opt 0]\n+\tset type [lindex $opt 1]\n+\tset flags [lindex $opt 2]\n+\tset title [eval [lindex $opt 4]]\n+\tset lxpad 0\n+\n+\tif {$flags eq \"+\" || $flags eq \"*\"} {\n+\t    set cframe $top.fr$cnt\n+\t    incr cnt\n+\t    frame $cframe\n+\t    pack $cframe -in $top -fill x -pady 3 -padx 3\n+\t    set cexpand [expr {$flags eq \"*\"}]\n+\t} else {\n+\t    set lxpad 5\n+\t}\n+\n+\tif {$type eq \"b\"} {\n+\t    checkbutton $cframe.c_$id -text $title -variable newviewopts($n,$id)\n+\t    pack $cframe.c_$id -in $cframe -side left \\\n+\t\t-padx [list $lxpad 0] -expand $cexpand -anchor w\n+\t} elseif {[regexp {^t(\\d+)$} $type type sz]} {\n+\t    message $cframe.l_$id -aspect 1500 -text $title\n+\t    entry $cframe.e_$id -width $sz -background $bgcolor \\\n+\t\t-textvariable newviewopts($n,$id)\n+\t    pack $cframe.l_$id -in $cframe -side left -padx [list $lxpad 0]\n+\t    pack $cframe.e_$id -in $cframe -side left -expand 1 -fill x\n+\t} elseif {[regexp {^t(\\d+)=$} $type type sz]} {\n+\t    message $cframe.l_$id -aspect 1500 -text $title\n+\t    entry $cframe.e_$id -width $sz -background $bgcolor \\\n+\t\t-textvariable newviewopts($n,$id)\n+\t    pack $cframe.l_$id -in $cframe -side top -pady [list 3 0] -anchor w\n+\t    pack $cframe.e_$id -in $cframe -side top -fill x\n+\t}\n+    }\n+\n+    # Path list\n+    message $top.l -aspect 1500 \\\n \t-text [mc \"Enter files and directories to include, one per line:\"]\n-    grid $top.l - -sticky w\n-    text $top.t -width 40 -height 10 -background $bgcolor -font uifont\n+    pack $top.l -in $top -side top -pady [list 7 0] -anchor w -padx 3\n+    text $top.t -width 40 -height 5 -background $bgcolor -font uifont\n     if {[info exists viewfiles($n)]} {\n \tforeach f $viewfiles($n) {\n \t    $top.t insert end $f\n@@ -3370,15 +3484,19 @@ proc vieweditor {top n title} {\n \t$top.t delete {end - 1c} end\n \t$top.t mark set insert 0.0\n     }\n-    grid $top.t - -sticky ew -padx 5\n+    pack $top.t -in $top -side top -pady [list 0 5] -fill both -expand 1 -padx 3\n     frame $top.buts\n     button $top.buts.ok -text [mc \"OK\"] -command [list newviewok $top $n]\n+    button $top.buts.apply -text [mc \"Apply (F5)\"] -command [list newviewok $top $n 1]\n     button $top.buts.can -text [mc \"Cancel\"] -command [list destroy $top]\n+    bind $top <Control-Return> [list newviewok $top $n]\n+    bind $top <F5> [list newviewok $top $n 1]\n     bind $top <Escape> [list destroy $top]\n-    grid $top.buts.ok $top.buts.can\n+    grid $top.buts.ok $top.buts.apply $top.buts.can\n     grid columnconfigure $top.buts 0 -weight 1 -uniform a\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n-    grid $top.buts - -pady 10 -sticky ew\n+    grid columnconfigure $top.buts 2 -weight 1 -uniform a\n+    pack $top.buts -in $top -side top -fill x\n     focus $top.t\n }\n \n@@ -3399,13 +3517,13 @@ proc allviewmenus {n op args} {\n     # doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args\n }\n \n-proc newviewok {top n} {\n+proc newviewok {top n {apply 0}} {\n     global nextviewnum newviewperm newviewname newishighlight\n     global viewname viewfiles viewperm selectedview curview\n-    global viewargs newviewargs viewargscmd newviewargscmd viewhlmenu\n+    global viewargs viewargscmd newviewopts viewhlmenu\n \n     if {[catch {\n-\tset newargs [shellsplit $newviewargs($n)]\n+\tset newargs [encode_view_opts $n]\n     } err]} {\n \terror_popup \"[mc \"Error in commit selection arguments:\"] $err\" $top\n \treturn\n@@ -3421,10 +3539,10 @@ proc newviewok {top n} {\n \t# creating a new view\n \tincr nextviewnum\n \tset viewname($n) $newviewname($n)\n-\tset viewperm($n) $newviewperm($n)\n+\tset viewperm($n) $newviewopts($n,perm)\n \tset viewfiles($n) $files\n \tset viewargs($n) $newargs\n-\tset viewargscmd($n) $newviewargscmd($n)\n+\tset viewargscmd($n) $newviewopts($n,cmd)\n \taddviewmenu $n\n \tif {!$newishighlight} {\n \t    run showview $n\n@@ -3433,7 +3551,7 @@ proc newviewok {top n} {\n \t}\n     } else {\n \t# editing an existing view\n-\tset viewperm($n) $newviewperm($n)\n+\tset viewperm($n) $newviewopts($n,perm)\n \tif {$newviewname($n) ne $viewname($n)} {\n \t    set viewname($n) $newviewname($n)\n \t    doviewmenu .bar.view 5 [list showview $n] \\\n@@ -3442,15 +3560,16 @@ proc newviewok {top n} {\n \t\t# entryconf [list -label $viewname($n) -value $viewname($n)]\n \t}\n \tif {$files ne $viewfiles($n) || $newargs ne $viewargs($n) || \\\n-\t\t$newviewargscmd($n) ne $viewargscmd($n)} {\n+\t\t$newviewopts($n,cmd) ne $viewargscmd($n)} {\n \t    set viewfiles($n) $files\n \t    set viewargs($n) $newargs\n-\t    set viewargscmd($n) $newviewargscmd($n)\n+\t    set viewargscmd($n) $newviewopts($n,cmd)\n \t    if {$curview == $n} {\n \t\trun reloadcommits\n \t    }\n \t}\n     }\n+    if {$apply} return\n     catch {destroy $top}\n }\n \n-- \n1.6.0.20.g6148bc\n"},{"id":"92600","messageId":"1223449540-20457-8-git-send-email-angavrilov@gmail.com","threadId":"15822","inReplyTo":"1223449540-20457-7-git-send-email-angavrilov@gmail.com","subject":"[PATCH 7/7] gitk: Explicitly position popup windows.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-08T07:05:40Z","receivedAt":"2008-10-08T07:05:40Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"For some reason, on Windows all transient windows are placed\nin the upper left corner of the screen. Thus, it is necessary\nto explicitly position the windows using the tk::PlaceWindow\nfunction.\n\nReference list and the Edit View dialog are positioned under\nthe mouse cursor, thus allowing the user to create them in a\nconvenient place using keyboard shortcuts, and providing a\nsane position when opened through the menu.\n\nOther popups are centered on the main window.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |   19 +++++++++++++++++--\n 1 files changed, 17 insertions(+), 2 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex c7dd487..9e580a6 100755\n--- a/gitk\n+++ b/gitk\n@@ -1703,7 +1703,7 @@ proc removehead {id name} {\n     unset headids($name)\n }\n \n-proc show_error {w top msg} {\n+proc show_error {w top msg {owner {}}} {\n     message $w.m -text $msg -justify center -aspect 400\n     pack $w.m -side top -fill x -padx 20 -pady 20\n     button $w.ok -text [mc OK] -command \"destroy $top\"\n@@ -1712,6 +1712,9 @@ proc show_error {w top msg} {\n     bind $top <Key-Return> \"destroy $top\"\n     bind $top <Key-space>  \"destroy $top\"\n     bind $top <Key-Escape> \"destroy $top\"\n+    if {$owner ne {}} {\n+\ttk::PlaceWindow $top widget $owner\n+    }\n     tkwait window $top\n }\n \n@@ -1719,7 +1722,7 @@ proc error_popup {msg {owner .}} {\n     set w .error\n     toplevel $w\n     wm transient $w $owner\n-    show_error $w $w $msg\n+    show_error $w $w $msg $owner\n }\n \n proc confirm_popup {msg {owner .}} {\n@@ -1738,6 +1741,7 @@ proc confirm_popup {msg {owner .}} {\n     bind $w <Key-Return> \"set confirm_ok 1; destroy $w\"\n     bind $w <Key-space>  \"set confirm_ok 1; destroy $w\"\n     bind $w <Key-Escape> \"destroy $w\"\n+    tk::PlaceWindow $w widget $owner\n     tkwait window $w\n     return $confirm_ok\n }\n@@ -2493,6 +2497,7 @@ Use and redistribute under the terms of the GNU General Public License\"] \\\n     bind $w <Visibility> \"focus $w.ok\"\n     bind $w <Key-Escape> \"destroy $w\"\n     bind $w <Key-Return> \"destroy $w\"\n+    tk::PlaceWindow $w widget .\n }\n \n proc keys {} {\n@@ -2554,6 +2559,7 @@ proc keys {} {\n     bind $w <Visibility> \"focus $w.ok\"\n     bind $w <Key-Escape> \"destroy $w\"\n     bind $w <Key-Return> \"destroy $w\"\n+    tk::PlaceWindow $w widget .\n }\n \n # Procedures for manipulating the file list window at the\n@@ -3497,6 +3503,7 @@ proc vieweditor {top n title} {\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n     grid columnconfigure $top.buts 2 -weight 1 -uniform a\n     pack $top.buts -in $top -side top -fill x\n+    tk::PlaceWindow $top pointer .\n     focus $top.t\n }\n \n@@ -7684,6 +7691,7 @@ proc mkpatch {} {\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n     grid $top.buts - -pady 10 -sticky ew\n     focus $top.fname\n+    tk::PlaceWindow $top widget .\n }\n \n proc mkpatchrev {} {\n@@ -7758,6 +7766,7 @@ proc mktag {} {\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n     grid $top.buts - -pady 10 -sticky ew\n     focus $top.tag\n+    tk::PlaceWindow $top widget .\n }\n \n proc domktag {} {\n@@ -7865,6 +7874,7 @@ proc writecommit {} {\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n     grid $top.buts - -pady 10 -sticky ew\n     focus $top.fname\n+    tk::PlaceWindow $top widget .\n }\n \n proc wrcomgo {} {\n@@ -7914,6 +7924,7 @@ proc mkbranch {} {\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n     grid $top.buts - -pady 10 -sticky ew\n     focus $top.name\n+    tk::PlaceWindow $top widget .\n }\n \n proc mkbrgo {top} {\n@@ -8093,6 +8104,7 @@ proc resethead {} {\n     bind $w <Key-Escape> [list destroy $w]\n     pack $w.cancel -side right -fill x -padx 20 -pady 20\n     bind $w <Visibility> \"grab $w; focus $w\"\n+    tk::PlaceWindow $w widget .\n     tkwait window $w\n     if {!$confirm_ok} return\n     if {[catch {set fd [open \\\n@@ -8278,6 +8290,7 @@ proc showrefs {} {\n     bind $top.list <ButtonRelease-1> {sel_reflist %W %x %y; break}\n     set reflist {}\n     refill_reflist\n+    tk::PlaceWindow $top pointer .\n }\n \n proc sel_reflist {w x y} {\n@@ -9630,6 +9643,7 @@ proc choosefont {font which} {\n \tgrid columnconfigure $top.buts 1 -weight 1 -uniform a\n \tpack $top.buts -side bottom -fill x\n \ttrace add variable fontparam write chg_fontparam\n+\ttk::PlaceWindow $top widget $prefstop\n     } else {\n \traise $top\n \t$top.c itemconf text -text $which\n@@ -9801,6 +9815,7 @@ proc doprefs {} {\n     grid columnconfigure $top.buts 1 -weight 1 -uniform a\n     grid $top.buts - - -pady 10 -sticky ew\n     bind $top <Visibility> \"focus $top.buts.ok\"\n+    tk::PlaceWindow $top widget .\n }\n \n proc choose_extdiff {} {\n-- \n1.6.0.20.g6148bc\n"},{"id":"92637","messageId":"18669.20487.88439.584567@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-2-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-09T00:27:51Z","receivedAt":"2008-10-09T00:27:51Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> - Popups are supposed to be marked transient, otherwise\n>   the WM creates them in strange places. Besides, at\n>   least under kwin, transients are automatically kept\n>   above their parent.\n> - Accelerators for menu items should be listed directly\n>   on the items, to make them more discoverable.\n> - Some more accelerators are added, e.g. F4 for Edit View.\n> - Finally, dialogs can now be accepted or dismissed using\n>   the Return and Escape keys.\n\nThanks for the patch series; a few specific comments follow.\n\n> +    catch { bind . <Shift-Key-XF86_Switch_VT_4> {newview 0} }\n\nWhat is this key, or why is this line needed?\n\n> @@ -2484,10 +2501,10 @@ proc keys {} {\n>      }\n>      toplevel $w\n>      wm title $w [mc \"Gitk key bindings\"]\n> +    wm transient $w .\n>      message $w.m -text \"\n>  [mc \"Gitk key bindings:\"]\n>  \n> -[mc \"<%s-Q>\t\tQuit\" $M1T]\n>  [mc \"<Home>\t\tMove to first commit\"]\n>  [mc \"<End>\t\tMove to last commit\"]\n>  [mc \"<Up>, p, i\tMove up one commit\"]\n> @@ -2521,11 +2538,11 @@ proc keys {} {\n>  [mc \"<%s-plus>\tIncrease font size\" $M1T]\n>  [mc \"<%s-KP->\tDecrease font size\" $M1T]\n>  [mc \"<%s-minus>\tDecrease font size\" $M1T]\n> -[mc \"<F5>\t\tUpdate\"]\n\nI think it is useful to have the accelerator keys listed in the key\nbinding help.\n\n> @@ -7501,6 +7534,7 @@ proc domktag {} {\n>      addedtag $id\n>      dispneartags 0\n>      run refill_reflist\n> +    return 1\n>  }\n>  \n>  proc redrawtags {id} {\n> @@ -7539,7 +7573,7 @@ proc mktagcan {} {\n>  }\n>  \n>  proc mktaggo {} {\n> -    domktag\n> +    if {![domktag]} return\n\nYou need to change the error returns in domktag to say \"return 0\",\notherwise this will give a \"can't use empty string as operand of \"!\"\"\nTcl error.\n\nPaul.\n"},{"id":"92652","messageId":"18669.46569.45285.170033@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-6-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 5/7] gitk: Make cherry-pick call git-citool on conflicts.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-09T07:42:33Z","receivedAt":"2008-10-09T07:42:33Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> Now that git-gui has facilities to help users resolve\n> conflicts, it makes sense to launch it from other gui\n> tools when they happen.\n\nNice idea...\n\n> +proc exec_citool {args {baseid {}}} {\n\nI'm a little nervous about you having a parameter called \"args\", since\nthat specific name has a special meaning in Tcl; it's how Tcl handles\nvariable-length argument lists.\n\n> +    global commitinfo env\n> +\n> +    if {[info exists env(GIT_AUTHOR_NAME)]} {\n> +\tset old_name $env(GIT_AUTHOR_NAME)\n> +    }\n> +    if {[info exists env(GIT_AUTHOR_EMAIL)]} {\n> +\tset old_email $env(GIT_AUTHOR_EMAIL)\n> +    }\n> +    if {[info exists env(GIT_AUTHOR_DATE)]} {\n> +\tset old_date $env(GIT_AUTHOR_DATE)\n> +    }\n> +\n> +    if {$baseid ne {}} {\n> +\tif {![info exists commitinfo($baseid)]} {\n> +\t    getcommit $baseid\n> +\t}\n> +\tset author [lindex $commitinfo($baseid) 1]\n> +\tset date [lindex $commitinfo($baseid) 2]\n> +\tif {[regexp {^\\s*(\\S.*\\S|\\S)\\s*<(.*)>\\s*$} \\\n> +\t            $author author name email]\n> +\t    && $date ne {}} {\n> +\t    set env(GIT_AUTHOR_NAME) $name\n> +\t    set env(GIT_AUTHOR_EMAIL) $email\n> +\t    set env(GIT_AUTHOR_DATE) $date\n> +\t}\n> +    }\n> +\n> +    eval exec git citool $args &\n\nIf we can assume the existence of a shell (which we do elsewhere), we\ncan perhaps do this more simply by putting the environment variable\nsettings in the command before the command name.  It's a pity that git\ncitool won't take the author name/email/date as command-line arguments\nor from a file, since it ends up being pretty verbose doing it the way\nyou have.\n\n> @@ -7861,7 +7908,17 @@ proc cherrypick {} {\n>      # no error occurs, and exec takes that as an indication of error...\n>      if {[catch {exec sh -c \"git cherry-pick -r $rowmenuid 2>&1\"} err]} {\n>  \tnotbusy cherrypick\n> -\terror_popup $err\n> +\tif {[regexp -line \\\n> +\t    {Entry '(.*)' would be overwritten by merge} $err msg fname]} {\n> +\t    error_popup [mc \"Cherry-pick failed: file '%s' had local modifications.\n> +Your working directory is in an inconsistent state.\" $fname]\n\nThat message seems a bit too scary.  It's not inconsistent, it's just\ngot local modifications.  If I remember correctly, in this situation\ngit cherry-pick will back out all the changes it did and leave the\nworking directory as it was before.\n\n> +\t} elseif {[regexp -line {^CONFLICT \\(.*\\):} $err msg]} {\n> +\t    # Force citool to read MERGE_MSG\n> +\t    file delete [file join [gitdir] \"GITGUI_MSG\"]\n> +\t    exec_citool [list] $rowmenuid\n\n[list] as an idiom for the empty list is a little unusual (here and\nelsewhere in your patches); {} would be more usual.\n\nPaul.\n"},{"id":"92653","messageId":"bb6f213e0810090112l60d7b4c3v42e42d9d769c6057@mail.gmail.com","threadId":"15822","inReplyTo":"18669.20487.88439.584567@cargo.ozlabs.ibm.com","subject":"Re: [PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-09T08:12:04Z","receivedAt":"2008-10-09T08:12:04Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"On Thu, Oct 9, 2008 at 4:27 AM, Paul Mackerras <paulus@samba.org> wrote:\n>> +    catch { bind . <Shift-Key-XF86_Switch_VT_4> {newview 0} }\n>\n> What is this key, or why is this line needed?\n\nIt is a workaround for an apparent bug in interaction between Tk and\nXKB on some systems.\nXKB configuration files bind those symbols to Ctrl-Alt-F*\ncombinations, but Tk's keyboard\nhandiling code sees them when Shift-F* is pressed. I'll be glad to\nfind a better fix, but that's\nall I could do for now.\n\nThe catch wrapper is there to avoid erroring out if that keysym does not exist.\n\n>> @@ -2484,10 +2501,10 @@ proc keys {} {\n>>\n>> -[mc \"<%s-Q>          Quit\" $M1T]\n>>  [mc \"<Home>          Move to first commit\"]\n>>  [mc \"<End>           Move to last commit\"]\n>>  [mc \"<Up>, p, i      Move up one commit\"]\n>> @@ -2521,11 +2538,11 @@ proc keys {} {\n>>  [mc \"<%s-plus>       Increase font size\" $M1T]\n>>  [mc \"<%s-KP->        Decrease font size\" $M1T]\n>>  [mc \"<%s-minus>      Decrease font size\" $M1T]\n>> -[mc \"<F5>            Update\"]\n>\n> I think it is useful to have the accelerator keys listed in the key\n> binding help.\n\nI don't insist on this part of the patch, it just seemed to be redundant now.\n\n>> @@ -7501,6 +7534,7 @@ proc domktag {} {\n>>      addedtag $id\n>>      dispneartags 0\n>>      run refill_reflist\n>> +    return 1\n>>  }\n>>\n>>  proc redrawtags {id} {\n>> @@ -7539,7 +7573,7 @@ proc mktagcan {} {\n>>  }\n>>\n>>  proc mktaggo {} {\n>> -    domktag\n>> +    if {![domktag]} return\n>\n> You need to change the error returns in domktag to say \"return 0\",\n> otherwise this will give a \"can't use empty string as operand of \"!\"\"\n> Tcl error.\n\nI did not know this. I'm not that familiar with Tcl...\n\nAlexander\n"},{"id":"92654","messageId":"bb6f213e0810090124i62a51e92n45836ee02577331a@mail.gmail.com","threadId":"15822","inReplyTo":"18669.46569.45285.170033@cargo.ozlabs.ibm.com","subject":"Re: [PATCH 5/7] gitk: Make cherry-pick call git-citool on conflicts.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-09T08:24:18Z","receivedAt":"2008-10-09T08:24:18Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"On Thu, Oct 9, 2008 at 11:42 AM, Paul Mackerras <paulus@samba.org> wrote:\n>> +proc exec_citool {args {baseid {}}} {\n>\n> I'm a little nervous about you having a parameter called \"args\", since\n> that specific name has a special meaning in Tcl; it's how Tcl handles\n> variable-length argument lists.\n\nYes, I'd better change that. Probably it works only because that name is\nspecial only as the last parameter.\n\n> If we can assume the existence of a shell (which we do elsewhere), we\n> can perhaps do this more simply by putting the environment variable\n> settings in the command before the command name.  It's a pity that git\n> citool won't take the author name/email/date as command-line arguments\n> or from a file, since it ends up being pretty verbose doing it the way\n> you have.\n\nIf I understand correctly, using a shell would require composing the\ncommand as a string, which itself requires quoting the author name & email,\nand other argument strings. I did not feel confident enough to do that, so\nchose a dumb but safe solution.\n\n>> @@ -7861,7 +7908,17 @@ proc cherrypick {} {\n>>      # no error occurs, and exec takes that as an indication of error...\n>>      if {[catch {exec sh -c \"git cherry-pick -r $rowmenuid 2>&1\"} err]} {\n>>       notbusy cherrypick\n>> -     error_popup $err\n>> +     if {[regexp -line \\\n>> +         {Entry '(.*)' would be overwritten by merge} $err msg fname]} {\n>> +         error_popup [mc \"Cherry-pick failed: file '%s' had local modifications.\n>> +Your working directory is in an inconsistent state.\" $fname]\n>\n> That message seems a bit too scary.  It's not inconsistent, it's just\n> got local modifications.  If I remember correctly, in this situation\n> git cherry-pick will back out all the changes it did and leave the\n> working directory as it was before.\n\nYes, I'll have to reword it.\n\n> [list] as an idiom for the empty list is a little unusual (here and\n> elsewhere in your patches); {} would be more usual.\n\nI'm more used to languages where lists and strings are very different types...\nEven in perl you have to use [] for an empty list ref, and '' for an\nempty string.\n\nAlexander\n"},{"id":"92658","messageId":"18669.58277.929130.165032@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"bb6f213e0810090124i62a51e92n45836ee02577331a@mail.gmail.com","subject":"Re: [PATCH 5/7] gitk: Make cherry-pick call git-citool on conflicts.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-09T10:57:41Z","receivedAt":"2008-10-09T10:57:41Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> If I understand correctly, using a shell would require composing the\n> command as a string, which itself requires quoting the author name & email,\n> and other argument strings. I did not feel confident enough to do that, so\n> chose a dumb but safe solution.\n\nYou're right.  I think we should do it basically the way you suggest,\nbut the saving/restoring of the environment can be done a bit more\nconcisely like this:\n\nproc exec_citool {args {baseid {}}} {\n    global commitinfo env\n\n    set save_env [array get env GIT_AUTHOR_*]\n\n    if {$baseid ne {}} {\n\t# as before ...\n    }\n\n    eval exec git citool $args &\n\n    catch {array unset env GIT_AUTHOR_*}\n    array set env $save_env\n}\n\n> I'm more used to languages where lists and strings are very different types...\n> Even in perl you have to use [] for an empty list ref, and '' for an\n> empty string.\n\nIn Tcl, everything is a string. :)\n\nPaul.\n"},{"id":"92659","messageId":"18669.58582.403341.404978@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"bb6f213e0810090112l60d7b4c3v42e42d9d769c6057@mail.gmail.com","subject":"Re: [PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-09T11:02:46Z","receivedAt":"2008-10-09T11:02:46Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> On Thu, Oct 9, 2008 at 4:27 AM, Paul Mackerras <paulus@samba.org> wrote:\n> >> +    catch { bind . <Shift-Key-XF86_Switch_VT_4> {newview 0} }\n> >\n> > What is this key, or why is this line needed?\n> \n> It is a workaround for an apparent bug in interaction between Tk and\n> XKB on some systems.\n> XKB configuration files bind those symbols to Ctrl-Alt-F*\n> combinations, but Tk's keyboard\n> handiling code sees them when Shift-F* is pressed. I'll be glad to\n> find a better fix, but that's\n> all I could do for now.\n\nOK, that information should go in the patch description.\n\n> > You need to change the error returns in domktag to say \"return 0\",\n> > otherwise this will give a \"can't use empty string as operand of \"!\"\"\n> > Tcl error.\n> \n> I did not know this. I'm not that familiar with Tcl...\n\nThen I am amazed at how much you have been able to accomplish...\n\nThere's a lot of information available in the Tcl/Tk man pages.  On\nDebian or Ubuntu, you need the tcl8.5-doc and tk8.5-doc packages\ninstalled.  Then you can do e.g. \"man 3tcl Tcl\" to get a summary of\nthe Tcl language syntax, etc.\n\nBTW, I haven't forgotten about your encoding support patches.  The\nlast month has been occupied with travelling for Kernel Summit and the\nLinux Plumbers Conference, followed by a vacation, and then catching\nup with work that has piled up, so I haven't had much time to spare\nfor gitk hacking.\n\nPaul.\n"},{"id":"93245","messageId":"18679.47194.852924.385301@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-2-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-16T21:55:38Z","receivedAt":"2008-10-16T21:55:38Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> - Popups are supposed to be marked transient, otherwise\n>   the WM creates them in strange places. Besides, at\n>   least under kwin, transients are automatically kept\n>   above their parent.\n\nI agree with most of the places where you add wm transient commands,\nbut in the case of the list of references (showrefs), I think of that\nas a long-lived window that one would normally place beside the main\nwindow.  (In fact, it should be a pane in the main window, but I\ncouldn't think of a place for it.  Maybe I should split the\nbottom-right pane in two.)\n\nSo I don't think the wm transient in showrefs is what we want.\nComments?\n\nPaul.\n"},{"id":"93246","messageId":"bb6f213e0810161508l68b0548bsbee5e81ef7830b4a@mail.gmail.com","threadId":"15822","inReplyTo":"18679.47194.852924.385301@cargo.ozlabs.ibm.com","subject":"Re: [PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-16T22:08:15Z","receivedAt":"2008-10-16T22:08:15Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"On Fri, Oct 17, 2008 at 1:55 AM, Paul Mackerras <paulus@samba.org> wrote:\n> Alexander Gavrilov writes:\n>> - Popups are supposed to be marked transient, otherwise\n>>   the WM creates them in strange places. Besides, at\n>>   least under kwin, transients are automatically kept\n>>   above their parent.\n>\n> I agree with most of the places where you add wm transient commands,\n> but in the case of the list of references (showrefs), I think of that\n> as a long-lived window that one would normally place beside the main\n> window.  (In fact, it should be a pane in the main window, but I\n> couldn't think of a place for it.  Maybe I should split the\n> bottom-right pane in two.)\n>\n> So I don't think the wm transient in showrefs is what we want.\n> Comments?\n\nOn the other hand, wm transient makes it always stay on top of the\nmain window. If the main window is maximized, it is useful.\n\nBtw, gitk probably should not save its geometry if the window is\nmaximized, because when it is started again the window is too large.\n\nAlexander\n"},{"id":"93598","messageId":"18685.48795.892869.474750@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-2-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 1/7] gitk: Enhance UI popup and accelerator handling.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-21T11:35:55Z","receivedAt":"2008-10-21T11:35:55Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> - Popups are supposed to be marked transient, otherwise\n>   the WM creates them in strange places. Besides, at\n>   least under kwin, transients are automatically kept\n>   above their parent.\n> - Accelerators for menu items should be listed directly\n>   on the items, to make them more discoverable.\n> - Some more accelerators are added, e.g. F4 for Edit View.\n> - Finally, dialogs can now be accepted or dismissed using\n>   the Return and Escape keys.\n\nCould you rebase this and split it into 3 patches, one each for the\ntransient popups, accelerators, and return/escape key bindings?\n\nThanks,\nPaul.\n"},{"id":"93597","messageId":"18685.48945.637464.604058@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-3-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 2/7] gitk: Allow forcing branch creation if it already exists.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-21T11:38:25Z","receivedAt":"2008-10-21T11:38:25Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> If gitk knows that the branch the user tries to create exists,\n> it should ask whether it should overwrite it. This way the user\n> can either decide to choose a new name, or move the head while\n> preserving the reflog.\n\nApplied, thanks.\n\nPaul.\n"},{"id":"93596","messageId":"18685.49035.922737.347026@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-5-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 4/7] gitk: Fix file list context menu for merge commits.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-21T11:39:55Z","receivedAt":"2008-10-21T11:39:55Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> Currently it displays an ugly error box, because the\n> treediffs array is not filled for such commits. This\n> is clearly unacceptable.\n\nApplied, thanks, with a better patch description, one that actually\ndescribed the remedial action. :)\n\nPaul.\n"},{"id":"93595","messageId":"18685.49152.25344.398737@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-8-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 7/7] gitk: Explicitly position popup windows.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-21T11:41:52Z","receivedAt":"2008-10-21T11:41:52Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> For some reason, on Windows all transient windows are placed\n> in the upper left corner of the screen. Thus, it is necessary\n> to explicitly position the windows using the tk::PlaceWindow\n> function.\n\nHmmm, this is not part of the official Tk API as far as I can see, and\nhaving to call tk::PlaceWindow on every window we create is a bit\ngross.  What exactly does it do, and what effect will this change have\non Linux?  Are you sure there isn't some other way to fix the problem?\n\nPaul.\n"},{"id":"93603","messageId":"bb6f213e0810210552k1e18ad83l9e06981454818cd2@mail.gmail.com","threadId":"15822","inReplyTo":"18685.49152.25344.398737@cargo.ozlabs.ibm.com","subject":"Re: [PATCH 7/7] gitk: Explicitly position popup windows.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-21T12:52:27Z","receivedAt":"2008-10-21T12:52:27Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"On Tue, Oct 21, 2008 at 3:41 PM, Paul Mackerras <paulus@samba.org> wrote:\n> Alexander Gavrilov writes:\n>\n>> For some reason, on Windows all transient windows are placed\n>> in the upper left corner of the screen. Thus, it is necessary\n>> to explicitly position the windows using the tk::PlaceWindow\n>> function.\n>\n> Hmmm, this is not part of the official Tk API as far as I can see, and\n> having to call tk::PlaceWindow on every window we create is a bit\n> gross.  What exactly does it do, and what effect will this change have\n> on Linux?  Are you sure there isn't some other way to fix the problem?\n\nIt is just a convenient helper function that can explicitly compute\nand set the window position in a number of ways. It is used in Tk's\ndialog implementations. If you don't like using an unofficial\nfunction, I can pull out the relevant ~8 lines of code as a separate\nfunction in gitk.\n\n\nhttp://objectmix.com/tcl/390381-tile-dialog-boxes-not-transient-parent-under-windows.html\nhttp://wiki.tcl.tk/1254\n\nAlexander\n"},{"id":"93769","messageId":"18688.26370.467724.404768@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"1223449540-20457-4-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH 3/7] gitk: Allow starting gui blame for a specific line.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-23T11:58:58Z","receivedAt":"2008-10-23T11:58:58Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> Adds a context menu item to the diff viewer pane that\n> calls blame, focusing it on the clicked line. In case\n> of combined diffs, it also automatically deduces which\n> parent is to be blamed.\n\nI have some comments on this one, but I haven't finished reviewing it\ncompletely, so I may have more... :)\n\n> +proc find_hunk_blamespec {base line} {\n> +    global ctext\n> +\n> +    # Find and parse the hunk header\n> +    set s_lix [$ctext search -backwards -regexp ^@@ \"$line.0 lineend\" $base.0]\n> +    if {$s_lix eq {}} return\n> +\n> +    set s_line [$ctext get $s_lix \"$s_lix + 1 lines\"]\n> +    if {![regexp {^@@@?(( -\\d+(,\\d+)?)+) \\+(\\d+)(,\\d+)? @@} $s_line \\\n\nIn fact there can be many @ characters at the beginning of the line;\nthe number of parents plus one, in fact.  See commit\nc465a76af658b443075d6efee1c3131257643020 in the kernel tree for an\nexample.  I suggest starting with ^@@@* rather than ^@@@?.\n\n> +    # Now scan the lines to determine offset within the hunk\n> +    set parent {}\n> +    set dline 0\n> +    set s_lno [lindex [split $s_lix \".\"] 0]\n> +\n> +    for {set i $line} {$i > $s_lno} {incr i -1} {\n> +\tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n> +\tif {$parent eq {}} {\n> +\t    # find first preceeding line that belongs to some parent\n> +\t    for {set j 0} {$j < [llength $old_lines]} {incr j} {\n> +\t\tset code [string index $c_line $j]\n> +\t\tif {$code ne {-} && $code ne { }} continue\n> +\t\tif {$code eq { } && $parent ne {}} continue\n> +\t\tset parent $j\n> +\t\tif {$code eq {-}} break\n> +\t    }\n> +\t}\n\nThis part worries me a bit.  If the user clicks on a line where all\nthe $code values are \"+\" then I think we should blame the current\ncommit.  Either that, or we disable the context menu item before\nposting it if the user clicks on a line that starts with all \"+\"\ncharacters (as many \"+\" as there are parents).\n\nBTW, writing \"-\" rather than {-} in expressions is more idiomatic.\n\nPaul.\n"},{"id":"93837","messageId":"200810241213.01337.angavrilov@gmail.com","threadId":"15822","inReplyTo":"18688.26370.467724.404768@cargo.ozlabs.ibm.com","subject":"Re: [PATCH 3/7] gitk: Allow starting gui blame for a specific line.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-24T08:13:01Z","receivedAt":"2008-10-24T08:13:01Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"On Thursday 23 October 2008 15:58:58 Paul Mackerras wrote:\n> > +    # Now scan the lines to determine offset within the hunk\n> > +    set parent {}\n> > +    set dline 0\n> > +    set s_lno [lindex [split $s_lix \".\"] 0]\n> > +\n> > +    for {set i $line} {$i > $s_lno} {incr i -1} {\n> > +\tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n> > +\tif {$parent eq {}} {\n> > +\t    # find first preceeding line that belongs to some parent\n> > +\t    for {set j 0} {$j < [llength $old_lines]} {incr j} {\n> > +\t\tset code [string index $c_line $j]\n> > +\t\tif {$code ne {-} && $code ne { }} continue\n> > +\t\tif {$code eq { } && $parent ne {}} continue\n> > +\t\tset parent $j\n> > +\t\tif {$code eq {-}} break\n> > +\t    }\n> > +\t}\n> \n> This part worries me a bit.  If the user clicks on a line where all\n> the $code values are \"+\" then I think we should blame the current\n> commit.  Either that, or we disable the context menu item before\n> posting it if the user clicks on a line that starts with all \"+\"\n> characters (as many \"+\" as there are parents).\n\nGood point. How about this variant? I renamed the menu item, and\nchanged the code to blame the current commit if:\n\n- The display is in the tree mode, or\n- The line is added relative to all parents, or\n- Diff analysis failed\n\nI also fixed a bug in processing of deleted lines in combined diffs,\nand made the parent selection code more readable (hopefully).\n\n--- >8 ---\nFrom: Alexander Gavrilov <angavrilov@gmail.com>\nSubject: [PATCH] gitk: Allow starting gui blame for a specific line.\n\nAdds a context menu item to the diff viewer pane that\ncalls blame, focusing it on the clicked line. In case\nof combined diffs, it also automatically deduces which\nparent is to be blamed. Lines added by the diff are\nblamed on the current commit itself.\n\nThe context menu itself is added by this patch. It is\npossible to populate it with commands from the flist\nmenu.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n gitk |  148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 146 insertions(+), 2 deletions(-)\n\ndiff --git a/gitk b/gitk\nindex f6a3e10..6fbd6bb 100755\n--- a/gitk\n+++ b/gitk\n@@ -2249,6 +2249,7 @@ proc makewindow {} {\n     bind $cflist <ButtonRelease-1> {treeclick %W %x %y}\n     global ctxbut\n     bind $cflist $ctxbut {pop_flist_menu %W %X %Y %x %y}\n+    bind $ctext $ctxbut {pop_diff_menu %W %X %Y %x %y}\n \n     set maincursor [. cget -cursor]\n     set textcursor [$ctext cget -cursor]\n@@ -2291,6 +2292,13 @@ proc makewindow {} {\n \t{mc \"Blame parent commit\" command {external_blame 1}}\n     }\n     $flist_menu configure -tearoff 0\n+\n+    global diff_menu\n+    set diff_menu .diffctxmenu\n+    makemenu $diff_menu {\n+\t{mc \"Blame this line\" command {external_blame_diff}}\n+    }\n+    $diff_menu configure -tearoff 0\n }\n \n # Windows sends all mouse wheel events to the current focused window, not\n@@ -2993,6 +3001,34 @@ proc pop_flist_menu {w X Y x y} {\n     tk_popup $flist_menu $X $Y\n }\n \n+proc find_ctext_fileinfo {line} {\n+    global ctext_file_names ctext_file_lines\n+\n+    set ok [bsearch $ctext_file_lines $line]\n+    set tline [lindex $ctext_file_lines $ok]\n+\n+    if {$ok >= [llength $ctext_file_lines] || $line < $tline} {\n+        return {}\n+    } else {\n+        return [list [lindex $ctext_file_names $ok] $tline]\n+    }\n+}\n+\n+proc pop_diff_menu {w X Y x y} {\n+    global ctext diff_menu flist_menu_file\n+    global diff_menu_txtpos diff_menu_line\n+    global diff_menu_filebase\n+\n+    stopfinding\n+    set diff_menu_txtpos [split [$w index \"@$x,$y\"] \".\"]\n+    set diff_menu_line [lindex $diff_menu_txtpos 0]\n+    set f [find_ctext_fileinfo $diff_menu_line]\n+    if {$f eq {}} return\n+    set flist_menu_file [lindex $f 0]\n+    set diff_menu_filebase [lindex $f 1]\n+    tk_popup $diff_menu $X $Y\n+}\n+\n proc flist_hl {only} {\n     global flist_menu_file findstring gdttype\n \n@@ -3099,7 +3135,96 @@ proc external_diff {} {\n     }\n }\n \n-proc external_blame {parent_idx} {\n+proc find_hunk_blamespec {base line} {\n+    global ctext\n+\n+    # Find and parse the hunk header\n+    set s_lix [$ctext search -backwards -regexp ^@@ \"$line.0 lineend\" $base.0]\n+    if {$s_lix eq {}} return\n+\n+    set s_line [$ctext get $s_lix \"$s_lix + 1 lines\"]\n+    if {![regexp {^@@@*(( -\\d+(,\\d+)?)+) \\+(\\d+)(,\\d+)? @@} $s_line \\\n+\t    s_line old_specs osz osz1 new_line nsz]} {\n+\treturn\n+    }\n+\n+    # base lines for the parents\n+    set base_lines [list $new_line]\n+    foreach old_spec [lrange [split $old_specs \" \"] 1 end] {\n+\tif {![regexp -- {-(\\d+)(,\\d+)?} $old_spec \\\n+\t        old_spec old_line osz]} {\n+\t    return\n+\t}\n+\tlappend base_lines $old_line\n+    }\n+\n+    # Now scan the lines to determine offset within the hunk\n+    set parent {}\n+    set dline 0\n+    set s_lno [lindex [split $s_lix \".\"] 0]\n+\n+    for {set i $line} {$i > $s_lno} {incr i -1} {\n+\tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n+\t# Determine if the line is removed\n+\tset chunk [string range $c_line 0 [llength $base_lines]-2]\n+\tset removed_idx [string first \"-\" $chunk]\n+\t# Choose a parent index\n+\tif {$parent eq {}} {\n+\t    if {$removed_idx >= 0} {\n+\t\tset parent $removed_idx\n+\t\tincr parent\n+\t    } else {\n+\t\tset unchanged_idx [string first \" \" $chunk]\n+\t\tif {$unchanged_idx >= 0} {\n+\t\t    set parent $unchanged_idx\n+\t\t    incr parent\n+\t\t} else {\n+\t\t    # blame the current commit\n+\t\t    set parent 0\n+\t\t}\n+\t    }\n+\t}\n+\t# then count other lines that belong to it\n+\tif {$parent > 0} {\n+\t    set code [string index $c_line $parent-1]\n+\t    if {$code eq \"-\" || ($removed_idx < 0 && $code ne \"+\")} {\n+\t\tincr dline\n+\t    }\n+\t} else {\n+\t    if {$removed_idx < 0} {\n+\t\tincr dline\n+\t    }\n+\t}\n+    }\n+\n+    if {$parent eq {}} { set parent 0 }\n+    incr dline [lindex $base_lines $parent]\n+    return [list $parent $dline]\n+}\n+\n+proc external_blame_diff {} {\n+    global currentid diffmergeid cmitmode\n+    global diff_menu_txtpos diff_menu_line\n+    global diff_menu_filebase flist_menu_file\n+\n+    if {$cmitmode eq \"tree\"} {\n+\tset parent_idx 0\n+\tset line [expr {$diff_menu_line - $diff_menu_filebase - 1}]\n+    } else {\n+\tset hinfo [find_hunk_blamespec $diff_menu_filebase $diff_menu_line]\n+\tif {$hinfo ne {}} {\n+\t    set parent_idx [lindex $hinfo 0]\n+\t    set line [lindex $hinfo 1]\n+\t} else {\n+\t    set parent_idx 0\n+\t    set line 0\n+\t}\n+    }\n+\n+    external_blame $parent_idx $line\n+}\n+\n+proc external_blame {parent_idx {line {}}} {\n     global flist_menu_file\n     global nullid nullid2\n     global parentlist selectedline currentid\n@@ -3115,7 +3240,12 @@ proc external_blame {parent_idx} {\n \treturn\n     }\n \n-    if {[catch {exec git gui blame $base_commit $flist_menu_file &} err]} {\n+    set cmdline [list git gui blame]\n+    if {$line ne {} && $line > 1} {\n+\tlappend cmdline \"--line=$line\"\n+    }\n+    lappend cmdline $base_commit $flist_menu_file\n+    if {[catch {eval exec $cmdline &} err]} {\n \terror_popup \"[mc \"git gui blame: command failed:\"] $err\"\n     }\n }\n@@ -6364,6 +6494,7 @@ proc gettreeline {gtf id} {\n \n proc showfile {f} {\n     global treefilelist treeidlist diffids nullid nullid2\n+    global ctext_file_names ctext_file_lines\n     global ctext commentend\n \n     set i [lsearch -exact $treefilelist($diffids) $f]\n@@ -6387,6 +6518,8 @@ proc showfile {f} {\n     filerun $bf [list getblobline $bf $diffids]\n     $ctext config -state normal\n     clear_ctext $commentend\n+    lappend ctext_file_names $f\n+    lappend ctext_file_lines [lindex [split $commentend \".\"] 0]\n     $ctext insert end \"\\n\"\n     $ctext insert end \"$f\\n\" filesep\n     $ctext config -state disabled\n@@ -6447,6 +6580,7 @@ proc mergediff {id} {\n proc getmergediffline {mdf id np} {\n     global diffmergeid ctext cflist mergemax\n     global difffilestart mdifffd treediffs\n+    global ctext_file_names ctext_file_lines\n     global diffencoding\n \n     $ctext conf -state normal\n@@ -6465,6 +6599,8 @@ proc getmergediffline {mdf id np} {\n \t    lappend difffilestart $here\n \t    lappend treediffs($id) $fname\n \t    add_flist [list $fname]\n+\t    lappend ctext_file_names $fname\n+\t    lappend ctext_file_lines [lindex [split $here \".\"] 0]\n \t    set diffencoding [get_path_encoding $fname]\n \t    set l [expr {(78 - [string length $fname]) / 2}]\n \t    set pad [string range \"----------------------------------------\" 1 $l]\n@@ -6733,11 +6869,13 @@ proc setinlist {var i val} {\n \n proc makediffhdr {fname ids} {\n     global ctext curdiffstart treediffs\n+    global ctext_file_names\n \n     set i [lsearch -exact $treediffs($ids) $fname]\n     if {$i >= 0} {\n \tsetinlist difffilestart $i $curdiffstart\n     }\n+    set ctext_file_names [lreplace $ctext_file_names end end $fname]\n     set l [expr {(78 - [string length $fname]) / 2}]\n     set pad [string range \"----------------------------------------\" 1 $l]\n     $ctext insert $curdiffstart \"$pad $fname $pad\" filesep\n@@ -6746,6 +6884,7 @@ proc makediffhdr {fname ids} {\n proc getblobdiffline {bdf ids} {\n     global diffids blobdifffd ctext curdiffstart\n     global diffnexthead diffnextnote difffilestart\n+    global ctext_file_names ctext_file_lines\n     global diffinhdr treediffs\n     global diffencoding\n \n@@ -6763,6 +6902,8 @@ proc getblobdiffline {bdf ids} {\n \t    # start of a new file\n \t    $ctext insert end \"\\n\"\n \t    set curdiffstart [$ctext index \"end - 1c\"]\n+\t    lappend ctext_file_names \"\"\n+\t    lappend ctext_file_lines [lindex [split $curdiffstart \".\"] 0]\n \t    $ctext insert end \"\\n\" filesep\n \t    # If the name hasn't changed the length will be odd,\n \t    # the middle char will be a space, and the two bits either\n@@ -6899,6 +7040,7 @@ proc nextfile {} {\n \n proc clear_ctext {{first 1.0}} {\n     global ctext smarktop smarkbot\n+    global ctext_file_names ctext_file_lines\n     global pendinglinks\n \n     set l [lindex [split $first .] 0]\n@@ -6912,6 +7054,8 @@ proc clear_ctext {{first 1.0}} {\n     if {$first eq \"1.0\"} {\n \tcatch {unset pendinglinks}\n     }\n+    set ctext_file_names {}\n+    set ctext_file_lines {}\n }\n \n proc settabs {{firstab {}}} {\n-- \n1.6.0.20.g6148bc\n"},{"id":"93919","messageId":"18691.2467.601039.480382@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"200810241213.01337.angavrilov@gmail.com","subject":"Re: [PATCH 3/7] gitk: Allow starting gui blame for a specific line.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-25T11:57:23Z","receivedAt":"2008-10-25T11:57:23Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> Good point. How about this variant? I renamed the menu item, and\n> changed the code to blame the current commit if:\n\nSounds good, just a couple of minor nits...\n\n> +    # Now scan the lines to determine offset within the hunk\n> +    set parent {}\n> +    set dline 0\n> +    set s_lno [lindex [split $s_lix \".\"] 0]\n> +\n> +    for {set i $line} {$i > $s_lno} {incr i -1} {\n> +\tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n> +\t# Determine if the line is removed\n> +\tset chunk [string range $c_line 0 [llength $base_lines]-2]\n\nYou need an [expr]:\n\nset chunk [string range $c_line 0 [expr {[llength $base_lines] - 2}]]\n\n> +\tset removed_idx [string first \"-\" $chunk]\n> +\t# Choose a parent index\n> +\tif {$parent eq {}} {\n> +\t    if {$removed_idx >= 0} {\n> +\t\tset parent $removed_idx\n> +\t\tincr parent\n> +\t    } else {\n> +\t\tset unchanged_idx [string first \" \" $chunk]\n> +\t\tif {$unchanged_idx >= 0} {\n> +\t\t    set parent $unchanged_idx\n> +\t\t    incr parent\n> +\t\t} else {\n> +\t\t    # blame the current commit\n> +\t\t    set parent 0\n> +\t\t}\n> +\t    }\n> +\t}\n\nI like this better than the previous version, but it would turn out a\nbit simpler if you use parent = -1 to indicate that we're blaming the\ncurrent commit, and then increment it right at the end.\n\n> +\t# then count other lines that belong to it\n> +\tif {$parent > 0} {\n> +\t    set code [string index $c_line $parent-1]\n\nOnce again you need an [expr].\n\nApart from those things, it looks good.  If you like I will fix those\nthings and commit it.\n\nPaul.\n"},{"id":"93931","messageId":"200810252045.54010.angavrilov@gmail.com","threadId":"15822","inReplyTo":"18691.2467.601039.480382@cargo.ozlabs.ibm.com","subject":"Re: [PATCH 3/7] gitk: Allow starting gui blame for a specific line.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-10-25T16:45:53Z","receivedAt":"2008-10-25T16:45:53Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"On Saturday 25 October 2008 15:57:23 Paul Mackerras wrote:\n> > +    # Now scan the lines to determine offset within the hunk\n> > +    set parent {}\n> > +    set dline 0\n> > +    set s_lno [lindex [split $s_lix \".\"] 0]\n> > +\n> > +    for {set i $line} {$i > $s_lno} {incr i -1} {\n> > +\tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n> > +\t# Determine if the line is removed\n> > +\tset chunk [string range $c_line 0 [llength $base_lines]-2]\n> \n> You need an [expr]:\n> \n> set chunk [string range $c_line 0 [expr {[llength $base_lines] - 2}]]\n\nUgh. I guess I'll have to install docs from Tcl 8.4...\n \n> > +\tset removed_idx [string first \"-\" $chunk]\n> > +\t# Choose a parent index\n> > +\tif {$parent eq {}} {\n> > +\t    if {$removed_idx >= 0} {\n> > +\t\tset parent $removed_idx\n> > +\t\tincr parent\n> > +\t    } else {\n> > +\t\tset unchanged_idx [string first \" \" $chunk]\n> > +\t\tif {$unchanged_idx >= 0} {\n> > +\t\t    set parent $unchanged_idx\n> > +\t\t    incr parent\n> > +\t\t} else {\n> > +\t\t    # blame the current commit\n> > +\t\t    set parent 0\n> > +\t\t}\n> > +\t    }\n> > +\t}\n> \n> I like this better than the previous version, but it would turn out a\n> bit simpler if you use parent = -1 to indicate that we're blaming the\n> current commit, and then increment it right at the end.\n\nYes, it's probably better to apply the following fixup.\n\nAlexander\n\n\ndiff --git a/gitk b/gitk\nindex 6fbd6bb..68f07c2 100755\n--- a/gitk\n+++ b/gitk\n@@ -3160,33 +3160,32 @@ proc find_hunk_blamespec {base line} {\n \n     # Now scan the lines to determine offset within the hunk\n     set parent {}\n+    set max_parent [expr {[llength $base_lines]-2}]\n     set dline 0\n     set s_lno [lindex [split $s_lix \".\"] 0]\n \n     for {set i $line} {$i > $s_lno} {incr i -1} {\n \tset c_line [$ctext get $i.0 \"$i.0 + 1 lines\"]\n \t# Determine if the line is removed\n-\tset chunk [string range $c_line 0 [llength $base_lines]-2]\n+\tset chunk [string range $c_line 0 $max_parent]\n \tset removed_idx [string first \"-\" $chunk]\n \t# Choose a parent index\n \tif {$parent eq {}} {\n \t    if {$removed_idx >= 0} {\n \t\tset parent $removed_idx\n-\t\tincr parent\n \t    } else {\n \t\tset unchanged_idx [string first \" \" $chunk]\n \t\tif {$unchanged_idx >= 0} {\n \t\t    set parent $unchanged_idx\n-\t\t    incr parent\n \t\t} else {\n \t\t    # blame the current commit\n-\t\t    set parent 0\n+\t\t    set parent -1\n \t\t}\n \t    }\n \t}\n \t# then count other lines that belong to it\n-\tif {$parent > 0} {\n-\t    set code [string index $c_line $parent-1]\n+\tif {$parent >= 0} {\n+\t    set code [string index $c_line $parent]\n \t    if {$code eq \"-\" || ($removed_idx < 0 && $code ne \"+\")} {\n \t\tincr dline\n \t    }\n@@ -3197,7 +3196,8 @@ proc find_hunk_blamespec {base line} {\n \t}\n     }\n \n-    if {$parent eq {}} { set parent 0 }\n+    if {$parent eq {}} { set parent -1 }\n+    incr parent\n     incr dline [lindex $base_lines $parent]\n     return [list $parent $dline]\n }\n"},{"id":"93969","messageId":"18691.60135.339841.3748@cargo.ozlabs.ibm.com","threadId":"15822","inReplyTo":"200810252045.54010.angavrilov@gmail.com","subject":"Re: [PATCH 3/7] gitk: Allow starting gui blame for a specific line.","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2008-10-26T03:58:31Z","receivedAt":"2008-10-26T03:58:31Z","isPatch":true,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Alexander Gavrilov writes:\n\n> Ugh. I guess I'll have to install docs from Tcl 8.4...\n\nYes, although I strongly encourage people to move to 8.5, I haven't\nmade it a requirement (yet :).\n\nPaul.\n"}]}