X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=gitk;h=4aa57c01ce56e505aba5384f716376a68a7fdc7a;hb=fa0f02dfa15d0d95f8b6d27688bbf8ac940e3354;hp=a83a75485851c155be838be37f3b973f28cb6327;hpb=da7c24dd9c75d014780179f8eb843968919e4c46;p=git.git diff --git a/gitk b/gitk index a83a7548..4aa57c01 100755 --- a/gitk +++ b/gitk @@ -19,13 +19,13 @@ proc gitdir {} { proc start_rev_list {view} { global startmsecs nextupdate ncmupdate global commfd leftover tclencoding datemode - global revtreeargs viewfiles commitidx + global viewargs viewfiles commitidx set startmsecs [clock clicks -milliseconds] set nextupdate [expr {$startmsecs + 100}] set ncmupdate 1 set commitidx($view) 0 - set args $revtreeargs + set args $viewargs($view) if {$viewfiles($view) ne {}} { set args [concat $args "--" $viewfiles($view)] } @@ -69,9 +69,7 @@ proc getcommits {} { set phase getcommits initlayout start_rev_list $curview - $canv delete all - $canv create text 3 3 -anchor nw -text "Reading commits..." \ - -font $mainfont -tags textitems + show_status "Reading commits..." } proc getcommitlines {fd view} { @@ -84,26 +82,33 @@ proc getcommitlines {fd view} { set stuff [read $fd] if {$stuff == {}} { if {![eof $fd]} return + global viewname unset commfd($view) + notbusy $view # set it blocking so we wait for the process to terminate fconfigure $fd -blocking 1 - if {![catch {close $fd} err]} { - notbusy $view - if {$view == $curview} { - after idle finishcommits + if {[catch {close $fd} err]} { + set fv {} + if {$view != $curview} { + set fv " for the \"$viewname($view)\" view" } - return + if {[string range $err 0 4] == "usage"} { + set err "Gitk: error reading commits$fv:\ + bad arguments to git-rev-list." + if {$viewname($view) eq "Command line"} { + append err \ + " (Note: arguments to gitk are passed to git-rev-list\ + to allow selection of commits to be displayed.)" + } + } else { + set err "Error reading commits$fv: $err" + } + error_popup $err } - if {[string range $err 0 4] == "usage"} { - set err \ - "Gitk: error reading commits: bad arguments to git-rev-list.\ - (Note: arguments to gitk are passed to git-rev-list\ - to allow selection of commits to be displayed.)" - } else { - set err "Error reading commits: $err" + if {$view == $curview} { + after idle finishcommits } - error_popup $err - exit 1 + return } set start 0 set gotsome 0 @@ -217,7 +222,7 @@ proc readcommit {id} { } proc updatecommits {} { - global viewdata curview revtreeargs phase displayorder + global viewdata curview phase displayorder global children commitrow if {$phase ne {}} { @@ -352,10 +357,7 @@ proc readrefs {} { close $refd } -proc error_popup msg { - set w .error - toplevel $w - wm transient $w . +proc show_error {w msg} { message $w.m -text $msg -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text OK -command "destroy $w" @@ -365,6 +367,13 @@ proc error_popup msg { tkwait window $w } +proc error_popup msg { + set w .error + toplevel $w + wm transient $w . + show_error $w $msg +} + proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist global textfont mainfont uifont @@ -512,7 +521,7 @@ proc makewindow {} { set ctext .ctop.cdet.left.ctext text $ctext -bg white -state disabled -font $textfont \ -width $geometry(ctextw) -height $geometry(ctexth) \ - -yscrollcommand scrolltext -wrap none + -yscrollcommand {.ctop.cdet.left.sb set} -wrap none scrollbar .ctop.cdet.left.sb -command "$ctext yview" pack .ctop.cdet.left.sb -side right -fill y pack $ctext -side left -fill both -expand 1 @@ -562,7 +571,8 @@ proc makewindow {} { scrollbar .ctop.cdet.right.sb -command "$cflist yview" pack .ctop.cdet.right.sb -side right -fill y pack $cflist -side left -fill both -expand 1 - $cflist tag configure highlight -background yellow + $cflist tag configure highlight \ + -background [$cflist cget -selectbackground] .ctop.cdet add .ctop.cdet.right bind .ctop.cdet {resizecdetpanes %W %w} @@ -685,7 +695,7 @@ proc savestuff {w} { global canv canv2 canv3 ctext cflist mainfont textfont uifont global stuffsaved findmergefiles maxgraphpct global maxwidth - global viewname viewfiles viewperm nextviewnum + global viewname viewfiles viewargs viewperm nextviewnum global cmitmode if {$stuffsaved} return @@ -714,7 +724,7 @@ proc savestuff {w} { puts -nonewline $f "set permviews {" for {set v 0} {$v < $nextviewnum} {incr v} { if {$viewperm($v)} { - puts $f "{[list $viewname($v) $viewfiles($v)]}" + puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v)]}" } } puts $f "}" @@ -1092,14 +1102,13 @@ image create bitmap tri-dn -background black -foreground blue -data { } proc init_flist {first} { - global cflist cflist_top cflist_bot selectedline difffilestart + global cflist cflist_top selectedline difffilestart $cflist conf -state normal $cflist delete 0.0 end if {$first ne {}} { $cflist insert end $first set cflist_top 1 - set cflist_bot 1 $cflist tag add highlight 1.0 "1.0 lineend" } else { catch {unset cflist_top} @@ -1126,67 +1135,115 @@ proc sel_flist {w x y} { if {$cmitmode eq "tree"} return if {![info exists cflist_top]} return set l [lindex [split [$w index "@$x,$y"] "."] 0] + $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend" + $cflist tag add highlight $l.0 "$l.0 lineend" + set cflist_top $l if {$l == 1} { $ctext yview 1.0 } else { catch {$ctext yview [lindex $difffilestart [expr {$l - 2}]]} } - highlight_flist $l } -proc scrolltext {f0 f1} { - global cflist_top +# Functions for adding and removing shell-type quoting - .ctop.cdet.left.sb set $f0 $f1 - if {[info exists cflist_top]} { - highlight_flist $cflist_top +proc shellquote {str} { + if {![string match "*\['\"\\ \t]*" $str]} { + return $str } -} - -# Given an index $tl in the $ctext window, this works out which line -# of the $cflist window displays the filename whose patch is shown -# at the given point in the $ctext window. $ll is a hint about which -# line it might be, and is used as the starting point of the search. -proc ctext_index {tl ll} { - global ctext difffilestart - - while {$ll >= 2 && [$ctext compare $tl < \ - [lindex $difffilestart [expr {$ll - 2}]]]} { - incr ll -1 + if {![string match "*\['\"\\]*" $str]} { + return "\"$str\"" } - set nfiles [llength $difffilestart] - while {$ll - 1 < $nfiles && [$ctext compare $tl >= \ - [lindex $difffilestart [expr {$ll - 1}]]]} { - incr ll + if {![string match "*'*" $str]} { + return "'$str'" } - return $ll + return "\"[string map {\" \\\" \\ \\\\} $str]\"" } -proc highlight_flist {ll} { - global ctext cflist cflist_top cflist_bot difffilestart - - if {![info exists difffilestart] || [llength $difffilestart] == 0} return - set ll [ctext_index [$ctext index @0,1] $ll] - set lb $cflist_bot - if {$lb < $ll} { - set lb $ll +proc shellarglist {l} { + set str {} + foreach a $l { + if {$str ne {}} { + append str " " + } + append str [shellquote $a] } - set y [expr {[winfo height $ctext] - 2}] - set lb [ctext_index [$ctext index @0,$y] $lb] - if {$ll != $cflist_top || $lb != $cflist_bot} { - $cflist tag remove highlight $cflist_top.0 "$cflist_bot.0 lineend" - for {set l $ll} {$l <= $lb} {incr l} { - $cflist tag add highlight $l.0 "$l.0 lineend" + return $str +} + +proc shelldequote {str} { + set ret {} + set used -1 + while {1} { + incr used + if {![regexp -start $used -indices "\['\"\\\\ \t]" $str first]} { + append ret [string range $str $used end] + set used [string length $str] + break + } + set first [lindex $first 0] + set ch [string index $str $first] + if {$first > $used} { + append ret [string range $str $used [expr {$first - 1}]] + set used $first + } + if {$ch eq " " || $ch eq "\t"} break + incr used + if {$ch eq "'"} { + set first [string first "'" $str $used] + if {$first < 0} { + error "unmatched single-quote" + } + append ret [string range $str $used [expr {$first - 1}]] + set used $first + continue } - set cflist_top $ll - set cflist_bot $lb + if {$ch eq "\\"} { + if {$used >= [string length $str]} { + error "trailing backslash" + } + append ret [string index $str $used] + continue + } + # here ch == "\"" + while {1} { + if {![regexp -start $used -indices "\[\"\\\\]" $str first]} { + error "unmatched double-quote" + } + set first [lindex $first 0] + set ch [string index $str $first] + if {$first > $used} { + append ret [string range $str $used [expr {$first - 1}]] + set used $first + } + if {$ch eq "\""} break + incr used + append ret [string index $str $used] + incr used + } + } + return [list $used $ret] +} + +proc shellsplit {str} { + set l {} + while {1} { + set str [string trimleft $str] + if {$str eq {}} break + set dq [shelldequote $str] + set n [lindex $dq 0] + set word [lindex $dq 1] + set str [string range $str $n end] + lappend l $word } + return $l } # Code to implement multiple views proc newview {ishighlight} { global nextviewnum newviewname newviewperm uifont newishighlight + global newviewargs revtreeargs set newishighlight $ishighlight set top .gitkview @@ -1196,12 +1253,14 @@ proc newview {ishighlight} { } set newviewname($nextviewnum) "View $nextviewnum" set newviewperm($nextviewnum) 0 + set newviewargs($nextviewnum) [shellarglist $revtreeargs] vieweditor $top $nextviewnum "Gitk view definition" } proc editview {} { global curview global viewname viewperm newviewname newviewperm + global viewargs newviewargs set top .gitkvedit-$curview if {[winfo exists $top]} { @@ -1210,6 +1269,7 @@ proc editview {} { } set newviewname($curview) $viewname($curview) set newviewperm($curview) $viewperm($curview) + set newviewargs($curview) [shellarglist $viewargs($curview)] vieweditor $top $curview "Gitk: edit view $viewname($curview)" } @@ -1224,7 +1284,13 @@ proc vieweditor {top n title} { grid $top.nl $top.name -sticky w -pady 5 checkbutton $top.perm -text "Remember this view" -variable newviewperm($n) grid $top.perm - -pady 5 -sticky w - message $top.l -aspect 500 -font $uifont \ + message $top.al -aspect 1000 -font $uifont \ + -text "Commits to include (arguments to git-rev-list):" + grid $top.al - -sticky w -pady 5 + entry $top.args -width 50 -textvariable newviewargs($n) \ + -background white + grid $top.args - -sticky ew -padx 5 + message $top.l -aspect 1000 -font $uifont \ -text "Enter files and directories to include, one per line:" grid $top.l - -sticky w text $top.t -width 40 -height 10 -background white @@ -1236,7 +1302,7 @@ proc vieweditor {top n title} { $top.t delete {end - 1c} end $top.t mark set insert 0.0 } - grid $top.t - -sticky w -padx 5 + grid $top.t - -sticky ew -padx 5 frame $top.buts button $top.buts.ok -text "OK" -command [list newviewok $top $n] button $top.buts.can -text "Cancel" -command [list destroy $top] @@ -1258,14 +1324,23 @@ proc doviewmenu {m first cmd op args} { } proc allviewmenus {n op args} { - doviewmenu .bar.view 6 [list showview $n] $op $args + doviewmenu .bar.view 7 [list showview $n] $op $args doviewmenu .bar.view.hl 3 [list addhighlight $n] $op $args } proc newviewok {top n} { global nextviewnum newviewperm newviewname newishighlight global viewname viewfiles viewperm selectedview curview + global viewargs newviewargs + if {[catch { + set newargs [shellsplit $newviewargs($n)] + } err]} { + error_popup "Error in commit selection arguments: $err" + wm raise $top + focus $top + return + } set files {} foreach f [split [$top.t get 0.0 end] "\n"] { set ft [string trim $f] @@ -1279,6 +1354,7 @@ proc newviewok {top n} { set viewname($n) $newviewname($n) set viewperm($n) $newviewperm($n) set viewfiles($n) $files + set viewargs($n) $newargs addviewmenu $n if {!$newishighlight} { after idle showview $n @@ -1292,8 +1368,9 @@ proc newviewok {top n} { set viewname($n) $newviewname($n) allviewmenus $n entryconf -label $viewname($n) } - if {$files ne $viewfiles($n)} { + if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} { set viewfiles($n) $files + set viewargs($n) $newargs if {$curview == $n} { after idle updatecommits } @@ -1394,8 +1471,8 @@ proc showview {n} { set curview $n set selectedview $n set selectedhlview -1 - .bar.view entryconf 1 -state [expr {$n == 0? "disabled": "normal"}] .bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}] + .bar.view entryconf 3 -state [expr {$n == 0? "disabled": "normal"}] catch {unset hlview} .bar.view.hl entryconf 1 -state disabled @@ -1450,15 +1527,15 @@ proc showview {n} { selectline $row 0 if {$phase ne {}} { if {$phase eq "getcommits"} { - global mainfont - $canv create text 3 3 -anchor nw -text "Reading commits..." \ - -font $mainfont -tags textitems + show_status "Reading commits..." } if {[info exists commfd($n)]} { layoutmore } else { finishcommits } + } elseif {$numcommits == 0} { + show_status "No commits selected" } } @@ -2580,6 +2657,13 @@ proc xcoord {i level ln} { return $x } +proc show_status {msg} { + global canv mainfont + + clear_display + $canv create text 3 3 -anchor nw -text $msg -font $mainfont -tags textitems +} + proc finishcommits {} { global commitidx phase curview global canv mainfont ctext maincursor textcursor @@ -2588,9 +2672,7 @@ proc finishcommits {} { if {$commitidx($curview) > 0} { drawrest } else { - $canv delete all - $canv create text 3 3 -anchor nw -text "No commits selected" \ - -font $mainfont -tags textitems + show_status "No commits selected" } set phase {} catch {unset pending_select} @@ -3561,8 +3643,6 @@ proc getmergediffline {mdf id np} { # start of a new file $ctext insert end "\n" set here [$ctext index "end - 1c"] - $ctext mark set f:$fname $here - $ctext mark gravity f:$fname left lappend difffilestart $here add_flist [list $fname] set l [expr {(78 - [string length $fname]) / 2}] @@ -3693,6 +3773,19 @@ proc getblobdiffs {ids} { set nextupdate [expr {[clock clicks -milliseconds] + 100}] } +proc setinlist {var i val} { + global $var + + while {[llength [set $var]] < $i} { + lappend $var {} + } + if {[llength [set $var]] == $i} { + lappend $var $val + } else { + lset $var $i $val + } +} + proc getblobdiffline {bdf ids} { global diffids blobdifffd ctext curdifftag curtagstart global diffnexthead diffnextnote difffilestart @@ -3719,12 +3812,15 @@ proc getblobdiffline {bdf ids} { set here [$ctext index "end - 1c"] set curtagstart $here set header $newname - lappend difffilestart $here - $ctext mark set f:$fname $here - $ctext mark gravity f:$fname left - if {$newname != $fname} { - $ctext mark set f:$newfname $here - $ctext mark gravity f:$newfname left + set i [lsearch -exact $treediffs($ids) $fname] + if {$i >= 0} { + setinlist difffilestart $i $here + } + if {$newname ne $fname} { + set i [lsearch -exact $treediffs($ids) $newname] + if {$i >= 0} { + setinlist difffilestart $i $here + } } set curdifftag "f:$fname" $ctext tag delete $curdifftag @@ -4815,10 +4911,33 @@ foreach arg $argv { # check that we can find a .git directory somewhere... set gitdir [gitdir] if {![file isdirectory $gitdir]} { - error_popup "Cannot find the git directory \"$gitdir\"." + show_error . "Cannot find the git directory \"$gitdir\"." exit 1 } +set cmdline_files {} +set i [lsearch -exact $revtreeargs "--"] +if {$i >= 0} { + set cmdline_files [lrange $revtreeargs [expr {$i + 1}] end] + set revtreeargs [lrange $revtreeargs 0 [expr {$i - 1}]] +} elseif {$revtreeargs ne {}} { + if {[catch { + set f [eval exec git-rev-parse --no-revs --no-flags $revtreeargs] + set cmdline_files [split $f "\n"] + set n [llength $cmdline_files] + set revtreeargs [lrange $revtreeargs 0 end-$n] + } err]} { + # unfortunately we get both stdout and stderr in $err, + # so look for "fatal:". + set i [string first "fatal:" $err] + if {$i > 0} { + set err [string range [expr {$i + 6}] end] + } + show_error . "Bad arguments to gitk:\n$err" + exit 1 + } +} + set history {} set historyindex 0 @@ -4830,7 +4949,9 @@ set selectedview 0 set selectedhlview {} set viewfiles(0) {} set viewperm(0) 0 +set viewargs(0) {} +set cmdlineok 0 set stopped 0 set stuffsaved 0 set patchnum 0 @@ -4838,28 +4959,18 @@ setcoords makewindow readrefs -set cmdline_files {} -catch { - set fileargs [eval exec git-rev-parse --no-revs --no-flags $revtreeargs] - set cmdline_files [split $fileargs "\n"] - set n [llength $cmdline_files] - set revtreeargs [lrange $revtreeargs 0 end-$n] -} -if {[lindex $revtreeargs end] eq "--"} { - set revtreeargs [lrange $revtreeargs 0 end-1] -} - -if {$cmdline_files ne {}} { +if {$cmdline_files ne {} || $revtreeargs ne {}} { # create a view for the files/dirs specified on the command line set curview 1 set selectedview 1 set nextviewnum 2 set viewname(1) "Command line" set viewfiles(1) $cmdline_files + set viewargs(1) $revtreeargs set viewperm(1) 0 addviewmenu 1 - .bar.view entryconf 1 -state normal .bar.view entryconf 2 -state normal + .bar.view entryconf 3 -state normal } if {[info exists permviews]} { @@ -4868,6 +4979,7 @@ if {[info exists permviews]} { incr nextviewnum set viewname($n) [lindex $v 0] set viewfiles($n) [lindex $v 1] + set viewargs($n) [lindex $v 2] set viewperm($n) 1 addviewmenu $n }