From: Paul Mackerras Date: Sun, 9 Nov 2008 11:05:50 +0000 (+1100) Subject: Merge branch 'dev' X-Git-Tag: v1.6.1-rc1~49^2~4 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/dbc4941facba9f43f1b95af254d667425d383d45?hp=-c Merge branch 'dev' --- dbc4941facba9f43f1b95af254d667425d383d45 diff --combined gitk index 2048798bcf,bea5026f62..18d153e569 --- a/gitk +++ b/gitk @@@ -1746,24 -1746,22 +1746,24 @@@ proc show_error {w top msg} pack $w.ok -side bottom -fill x bind $top "grab $top; focus $top" bind $top "destroy $top" + bind $top "destroy $top" + bind $top "destroy $top" tkwait window $top } -proc error_popup msg { +proc error_popup {msg {owner .}} { set w .error toplevel $w - wm transient $w . + wm transient $w $owner show_error $w $w $msg } -proc confirm_popup msg { +proc confirm_popup {msg {owner .}} { global confirm_ok set confirm_ok 0 set w .confirm toplevel $w - wm transient $w . + wm transient $w $owner message $w.m -text $msg -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w" @@@ -1771,9 -1769,6 +1771,9 @@@ button $w.cancel -text [mc Cancel] -command "destroy $w" pack $w.cancel -side right -fill x bind $w "grab $w; focus $w" + bind $w "set confirm_ok 1; destroy $w" + bind $w "set confirm_ok 1; destroy $w" + bind $w "destroy $w" tkwait window $w return $confirm_ok } @@@ -2103,7 -2098,7 +2103,7 @@@ proc makewindow {} $ctext tag conf filesep -font textfontbold -back "#aaaaaa" $ctext tag conf hunksep -fore [lindex $diffcolors 2] $ctext tag conf d0 -fore [lindex $diffcolors 0] - $ctext tag conf d1 -fore [lindex $diffcolors 1] + $ctext tag conf dresult -fore [lindex $diffcolors 1] $ctext tag conf m0 -fore red $ctext tag conf m1 -fore blue $ctext tag conf m2 -fore green @@@ -2546,7 -2541,6 +2546,7 @@@ proc about {} } toplevel $w wm title $w [mc "About gitk"] + wm transient $w . message $w.m -text [mc " Gitk - a commit viewer for git @@@ -2575,7 -2569,6 +2575,7 @@@ proc keys {} } toplevel $w wm title $w [mc "Gitk key bindings"] + wm transient $w . message $w.m -text " [mc "Gitk key bindings:"] @@@ -2618,7 -2611,6 +2618,7 @@@ -justify left -bg white -border 2 -relief groove pack $w.m -side top -fill both -padx 2 -pady 2 button $w.ok -text [mc "Close"] -command "destroy $w" -default active + bind $w [list destroy $w] pack $w.ok -side bottom bind $w "focus $w.ok" bind $w "destroy $w" @@@ -3225,7 -3217,7 +3225,7 @@@ proc find_hunk_blamespec {base line} } proc external_blame_diff {} { - global currentid diffmergeid cmitmode + global currentid cmitmode global diff_menu_txtpos diff_menu_line global diff_menu_filebase flist_menu_file @@@ -3246,6 -3238,22 +3246,22 @@@ external_blame $parent_idx $line } + # Find the SHA1 ID of the blob for file $fname in the index + # at stage 0 or 2 + proc index_sha1 {fname} { + set f [open [list | git ls-files -s $fname] r] + while {[gets $f line] >= 0} { + set info [lindex [split $line "\t"] 0] + set stage [lindex $info 2] + if {$stage eq "0" || $stage eq "2"} { + close $f + return [lindex $info 1] + } + } + close $f + return {} + } + proc external_blame {parent_idx {line {}}} { global flist_menu_file global nullid nullid2 @@@ -3275,7 -3283,9 +3291,9 @@@ proc show_line_source {} { global cmitmode currentid parents curview blamestuff blameinst global diff_menu_line diff_menu_filebase flist_menu_file + global nullid nullid2 gitdir + set from_index {} if {$cmitmode eq "tree"} { set id $currentid set line [expr {$diff_menu_line - $diff_menu_filebase}] @@@ -3287,11 -3297,46 +3305,46 @@@ mark_ctext_line $diff_menu_line return } - set id [lindex $parents($curview,$currentid) [expr {$pi - 1}]] + incr pi -1 + if {$currentid eq $nullid} { + if {$pi > 0} { + # must be a merge in progress... + if {[catch { + # get the last line from .git/MERGE_HEAD + set f [open [file join $gitdir MERGE_HEAD] r] + set id [lindex [split [read $f] "\n"] end-1] + close $f + } err]} { + error_popup [mc "Couldn't read merge head: %s" $err] + return + } + } elseif {$parents($curview,$currentid) eq $nullid2} { + # need to do the blame from the index + if {[catch { + set from_index [index_sha1 $flist_menu_file] + } err]} { + error_popup [mc "Error reading index: %s" $err] + return + } + } + } else { + set id [lindex $parents($curview,$currentid) $pi] + } set line [lindex $h 1] } + set blameargs {} + if {$from_index ne {}} { + lappend blameargs | git cat-file blob $from_index + } + lappend blameargs | git blame -p -L$line,+1 + if {$from_index ne {}} { + lappend blameargs --contents - + } else { + lappend blameargs $id + } + lappend blameargs -- $flist_menu_file if {[catch { - set f [open [list | git blame -p -L$line,+1 $id -- $flist_menu_file] r] + set f [open $blameargs r] } err]} { error_popup [mc "Couldn't start git blame: %s" $err] return @@@ -3313,7 -3358,7 +3366,7 @@@ proc stopblaming {} } proc read_line_source {fd inst} { - global blamestuff curview commfd blameinst + global blamestuff curview commfd blameinst nullid nullid2 while {[gets $fd line] >= 0} { lappend blamestuff($inst) $line @@@ -3345,6 -3390,11 +3398,11 @@@ } if {$fname ne {}} { # all looks good, select it + if {$id eq $nullid} { + # blame uses all-zeroes to mean not committed, + # which would mean a change in the index + set id $nullid2 + } if {[commitinview $id $curview]} { selectline [rowofcommit $id] 1 [list $fname $lnum] } else { @@@ -3467,8 -3517,8 +3525,8 @@@ proc shellsplit {str} # Code to implement multiple views proc newview {ishighlight} { - global nextviewnum newviewname newviewperm newishighlight - global newviewargs revtreeargs viewargscmd newviewargscmd curview + global nextviewnum newviewname newishighlight + global revtreeargs viewargscmd newviewopts curview set newishighlight $ishighlight set top .gitkview @@@ -3477,173 -3527,58 +3535,173 @@@ return } set newviewname($nextviewnum) "[mc "View"] $nextviewnum" - set newviewperm($nextviewnum) 0 - set newviewargs($nextviewnum) [shellarglist $revtreeargs] - set newviewargscmd($nextviewnum) $viewargscmd($curview) + set newviewopts($nextviewnum,perm) 0 + set newviewopts($nextviewnum,cmd) $viewargscmd($curview) + decode_view_opts $nextviewnum $revtreeargs vieweditor $top $nextviewnum [mc "Gitk view definition"] } +set known_view_options { + {perm b . {} {mc "Remember this view"}} + {args t50= + {} {mc "Commits to include (arguments to git log):"}} + {all b * "--all" {mc "Use all refs"}} + {dorder b . {"--date-order" "-d"} {mc "Strictly sort by date"}} + {lright b . "--left-right" {mc "Mark branch sides"}} + {since t15 + {"--since=*" "--after=*"} {mc "Since date:"}} + {until t15 . {"--until=*" "--before=*"} {mc "Until date:"}} + {limit t10 + "--max-count=*" {mc "Max count:"}} + {skip t10 . "--skip=*" {mc "Skip:"}} + {first b . "--first-parent" {mc "Limit to first parent"}} + {cmd t50= + {} {mc "Command to generate more commits to include:"}} + } + +proc encode_view_opts {n} { + global known_view_options newviewopts + + set rargs [list] + foreach opt $known_view_options { + set patterns [lindex $opt 3] + if {$patterns eq {}} continue + set pattern [lindex $patterns 0] + + set val $newviewopts($n,[lindex $opt 0]) + + if {[lindex $opt 1] eq "b"} { + if {$val} { + lappend rargs $pattern + } + } else { + set val [string trim $val] + if {$val ne {}} { + set pfix [string range $pattern 0 end-1] + lappend rargs $pfix$val + } + } + } + return [concat $rargs [shellsplit $newviewopts($n,args)]] +} + +proc decode_view_opts {n view_args} { + global known_view_options newviewopts + + foreach opt $known_view_options { + if {[lindex $opt 1] eq "b"} { + set val 0 + } else { + set val {} + } + set newviewopts($n,[lindex $opt 0]) $val + } + set oargs [list] + foreach arg $view_args { + if {[regexp -- {^-([0-9]+)$} $arg arg cnt] + && ![info exists found(limit)]} { + set newviewopts($n,limit) $cnt + set found(limit) 1 + continue + } + catch { unset val } + foreach opt $known_view_options { + set id [lindex $opt 0] + if {[info exists found($id)]} continue + foreach pattern [lindex $opt 3] { + if {![string match $pattern $arg]} continue + if {[lindex $opt 1] ne "b"} { + set size [string length $pattern] + set val [string range $arg [expr {$size-1}] end] + } else { + set val 1 + } + set newviewopts($n,$id) $val + set found($id) 1 + break + } + if {[info exists val]} break + } + if {[info exists val]} continue + lappend oargs $arg + } + set newviewopts($n,args) [shellarglist $oargs] +} + proc editview {} { global curview - global viewname viewperm newviewname newviewperm - global viewargs newviewargs viewargscmd newviewargscmd + global viewname viewperm newviewname newviewopts + global viewargs viewargscmd set top .gitkvedit-$curview if {[winfo exists $top]} { raise $top return } - set newviewname($curview) $viewname($curview) - set newviewperm($curview) $viewperm($curview) - set newviewargs($curview) [shellarglist $viewargs($curview)] - set newviewargscmd($curview) $viewargscmd($curview) + set newviewname($curview) $viewname($curview) + set newviewopts($curview,perm) $viewperm($curview) + set newviewopts($curview,cmd) $viewargscmd($curview) + decode_view_opts $curview $viewargs($curview) vieweditor $top $curview "Gitk: edit view $viewname($curview)" } proc vieweditor {top n title} { - global newviewname newviewperm viewfiles bgcolor + global newviewname newviewopts viewfiles bgcolor + global known_view_options toplevel $top wm title $top $title + wm transient $top . + + # View name + frame $top.nfr label $top.nl -text [mc "Name"] entry $top.name -width 20 -textvariable newviewname($n) - grid $top.nl $top.name -sticky w -pady 5 - checkbutton $top.perm -text [mc "Remember this view"] \ - -variable newviewperm($n) - grid $top.perm - -pady 5 -sticky w - message $top.al -aspect 1000 \ - -text [mc "Commits to include (arguments to git log):"] - grid $top.al - -sticky w -pady 5 - entry $top.args -width 50 -textvariable newviewargs($n) \ - -background $bgcolor - grid $top.args - -sticky ew -padx 5 - - message $top.ac -aspect 1000 \ - -text [mc "Command to generate more commits to include:"] - grid $top.ac - -sticky w -pady 5 - entry $top.argscmd -width 50 -textvariable newviewargscmd($n) \ - -background white - grid $top.argscmd - -sticky ew -padx 5 - - message $top.l -aspect 1000 \ + pack $top.nfr -in $top -fill x -pady 5 -padx 3 + pack $top.nl -in $top.nfr -side left -padx {0 30} + pack $top.name -in $top.nfr -side left + + # View options + set cframe $top.nfr + set cexpand 0 + set cnt 0 + foreach opt $known_view_options { + set id [lindex $opt 0] + set type [lindex $opt 1] + set flags [lindex $opt 2] + set title [eval [lindex $opt 4]] + set lxpad 0 + + if {$flags eq "+" || $flags eq "*"} { + set cframe $top.fr$cnt + incr cnt + frame $cframe + pack $cframe -in $top -fill x -pady 3 -padx 3 + set cexpand [expr {$flags eq "*"}] + } else { + set lxpad 5 + } + + if {$type eq "b"} { + checkbutton $cframe.c_$id -text $title -variable newviewopts($n,$id) + pack $cframe.c_$id -in $cframe -side left \ + -padx [list $lxpad 0] -expand $cexpand -anchor w + } elseif {[regexp {^t(\d+)$} $type type sz]} { + message $cframe.l_$id -aspect 1500 -text $title + entry $cframe.e_$id -width $sz -background $bgcolor \ + -textvariable newviewopts($n,$id) + pack $cframe.l_$id -in $cframe -side left -padx [list $lxpad 0] + pack $cframe.e_$id -in $cframe -side left -expand 1 -fill x + } elseif {[regexp {^t(\d+)=$} $type type sz]} { + message $cframe.l_$id -aspect 1500 -text $title + entry $cframe.e_$id -width $sz -background $bgcolor \ + -textvariable newviewopts($n,$id) + pack $cframe.l_$id -in $cframe -side top -pady [list 3 0] -anchor w + pack $cframe.e_$id -in $cframe -side top -fill x + } + } + + # Path list + message $top.l -aspect 1500 \ -text [mc "Enter files and directories to include, one per line:"] - grid $top.l - -sticky w - text $top.t -width 40 -height 10 -background $bgcolor -font uifont + pack $top.l -in $top -side top -pady [list 7 0] -anchor w -padx 3 + text $top.t -width 40 -height 5 -background $bgcolor -font uifont if {[info exists viewfiles($n)]} { foreach f $viewfiles($n) { $top.t insert end $f @@@ -3652,19 -3587,14 +3710,19 @@@ $top.t delete {end - 1c} end $top.t mark set insert 0.0 } - grid $top.t - -sticky ew -padx 5 + pack $top.t -in $top -side top -pady [list 0 5] -fill both -expand 1 -padx 3 frame $top.buts button $top.buts.ok -text [mc "OK"] -command [list newviewok $top $n] + button $top.buts.apply -text [mc "Apply (F5)"] -command [list newviewok $top $n 1] button $top.buts.can -text [mc "Cancel"] -command [list destroy $top] - grid $top.buts.ok $top.buts.can + bind $top [list newviewok $top $n] + bind $top [list newviewok $top $n 1] + bind $top [list destroy $top] + grid $top.buts.ok $top.buts.apply $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a - grid $top.buts - -pady 10 -sticky ew + grid columnconfigure $top.buts 2 -weight 1 -uniform a + pack $top.buts -in $top -side top -fill x focus $top.t } @@@ -3685,15 -3615,17 +3743,15 @@@ proc allviewmenus {n op args} # doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args } -proc newviewok {top n} { +proc newviewok {top n {apply 0}} { global nextviewnum newviewperm newviewname newishighlight global viewname viewfiles viewperm selectedview curview - global viewargs newviewargs viewargscmd newviewargscmd viewhlmenu + global viewargs viewargscmd newviewopts viewhlmenu if {[catch { - set newargs [shellsplit $newviewargs($n)] + set newargs [encode_view_opts $n] } err]} { - error_popup "[mc "Error in commit selection arguments:"] $err" - wm raise $top - focus $top + error_popup "[mc "Error in commit selection arguments:"] $err" $top return } set files {} @@@ -3707,10 -3639,10 +3765,10 @@@ # creating a new view incr nextviewnum set viewname($n) $newviewname($n) - set viewperm($n) $newviewperm($n) + set viewperm($n) $newviewopts($n,perm) set viewfiles($n) $files set viewargs($n) $newargs - set viewargscmd($n) $newviewargscmd($n) + set viewargscmd($n) $newviewopts($n,cmd) addviewmenu $n if {!$newishighlight} { run showview $n @@@ -3719,7 -3651,7 +3777,7 @@@ } } else { # editing an existing view - set viewperm($n) $newviewperm($n) + set viewperm($n) $newviewopts($n,perm) if {$newviewname($n) ne $viewname($n)} { set viewname($n) $newviewname($n) doviewmenu .bar.view 5 [list showview $n] \ @@@ -3728,16 -3660,15 +3786,16 @@@ # entryconf [list -label $viewname($n) -value $viewname($n)] } if {$files ne $viewfiles($n) || $newargs ne $viewargs($n) || \ - $newviewargscmd($n) ne $viewargscmd($n)} { + $newviewopts($n,cmd) ne $viewargscmd($n)} { set viewfiles($n) $files set viewargs($n) $newargs - set viewargscmd($n) $newviewargscmd($n) + set viewargscmd($n) $newviewopts($n,cmd) if {$curview == $n} { run reloadcommits } } } + if {$apply} return catch {destroy $top} } @@@ -6795,130 -6726,16 +6853,16 @@@ proc mark_ctext_line {lnum} } proc mergediff {id} { - global diffmergeid mdifffd + global diffmergeid global diffids treediffs - global parents - global diffcontext - global diffencoding - global limitdiffs vfilelimit curview - global targetline + global parents curview set diffmergeid $id set diffids $id set treediffs($id) {} - set targetline {} - # this doesn't seem to actually affect anything... - set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id] - if {$limitdiffs && $vfilelimit($curview) ne {}} { - set cmd [concat $cmd -- $vfilelimit($curview)] - } - if {[catch {set mdf [open $cmd r]} err]} { - error_popup "[mc "Error getting merge diffs:"] $err" - return - } - fconfigure $mdf -blocking 0 -encoding binary - set mdifffd($id) $mdf set np [llength $parents($curview,$id)] - set diffencoding [get_path_encoding {}] settabs $np - filerun $mdf [list getmergediffline $mdf $id $np] - } - - proc getmergediffline {mdf id np} { - global diffmergeid ctext cflist mergemax - global difffilestart mdifffd treediffs - global ctext_file_names ctext_file_lines - global diffencoding jump_to_here targetline diffline - - $ctext conf -state normal - set nr 0 - while {[incr nr] <= 1000 && [gets $mdf line] >= 0} { - if {![info exists diffmergeid] || $id != $diffmergeid - || $mdf != $mdifffd($id)} { - close $mdf - return 0 - } - if {[regexp {^diff --cc (.*)} $line match fname]} { - # start of a new file - set fname [encoding convertfrom $fname] - $ctext insert end "\n" - set here [$ctext index "end - 1c"] - lappend difffilestart $here - lappend treediffs($id) $fname - add_flist [list $fname] - lappend ctext_file_names $fname - lappend ctext_file_lines [lindex [split $here "."] 0] - set diffencoding [get_path_encoding $fname] - set l [expr {(78 - [string length $fname]) / 2}] - set pad [string range "----------------------------------------" 1 $l] - $ctext insert end "$pad $fname $pad\n" filesep - set targetline {} - if {$jump_to_here ne {} && [lindex $jump_to_here 0] eq $fname} { - set targetline [lindex $jump_to_here 1] - } - set diffline 0 - } elseif {[regexp {^@@} $line]} { - set line [encoding convertfrom $diffencoding $line] - $ctext insert end "$line\n" hunksep - if {[regexp { \+(\d+),\d+ @@} $line m nl]} { - set diffline $nl - } - } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} { - # do nothing - } else { - set line [encoding convertfrom $diffencoding $line] - # parse the prefix - one ' ', '-' or '+' for each parent - set spaces {} - set minuses {} - set pluses {} - set isbad 0 - for {set j 0} {$j < $np} {incr j} { - set c [string range $line $j $j] - if {$c == " "} { - lappend spaces $j - } elseif {$c == "-"} { - lappend minuses $j - } elseif {$c == "+"} { - lappend pluses $j - } else { - set isbad 1 - break - } - } - set tags {} - set num {} - if {!$isbad && $minuses ne {} && $pluses eq {}} { - # line doesn't appear in result, parents in $minuses have the line - set num [lindex $minuses 0] - } elseif {!$isbad && $pluses ne {} && $minuses eq {}} { - # line appears in result, parents in $pluses don't have the line - lappend tags mresult - set num [lindex $spaces 0] - } - if {$num ne {}} { - if {$num >= $mergemax} { - set num "max" - } - lappend tags m$num - } - $ctext insert end "$line\n" $tags - if {$targetline ne {} && $minuses eq {}} { - if {$diffline == $targetline} { - set here [$ctext index "end - 1 line"] - mark_ctext_line [lindex [split $here .] 0] - set targetline {} - } else { - incr diffline - } - } - } - } - $ctext conf -state disabled - if {[eof $mdf]} { - close $mdf - return 0 - } - return [expr {$nr >= 1000? 2: 1}] + getblobdiffs $id } proc startdiff {ids} { @@@ -7037,8 -6854,10 +6981,10 @@@ proc gettreediffline {gdtf ids} set file [lindex $file 0] } set file [encoding convertfrom $file] - lappend treediff $file - lappend sublist $file + if {$file ne [lindex $treediff end]} { + lappend treediff $file + lappend sublist $file + } } } if {$perfile_attrs} { @@@ -7098,9 -6917,9 +7044,9 @@@ proc getblobdiffs {ids} global diffcontext global ignorespace global limitdiffs vfilelimit curview - global diffencoding targetline + global diffencoding targetline diffnparents - set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"] + set cmd [diffcmd $ids "-p -C --cc --no-commit-id -U$diffcontext"] if {$ignorespace} { append cmd " -w" } @@@ -7108,10 -6927,11 +7054,11 @@@ set cmd [concat $cmd -- $vfilelimit($curview)] } if {[catch {set bdf [open $cmd r]} err]} { - puts "error getting diffs: $err" + error_popup [mc "Error getting diffs: %s" $err] return } set targetline {} + set diffnparents 0 set diffinhdr 0 set diffencoding [get_path_encoding {}] fconfigure $bdf -blocking 0 -encoding binary @@@ -7133,14 -6953,16 +7080,16 @@@ proc setinlist {var i val} } proc makediffhdr {fname ids} { - global ctext curdiffstart treediffs + global ctext curdiffstart treediffs diffencoding global ctext_file_names jump_to_here targetline diffline + set fname [encoding convertfrom $fname] + set diffencoding [get_path_encoding $fname] set i [lsearch -exact $treediffs($ids) $fname] if {$i >= 0} { setinlist difffilestart $i $curdiffstart } - set ctext_file_names [lreplace $ctext_file_names end end $fname] + lset ctext_file_names end $fname set l [expr {(78 - [string length $fname]) / 2}] set pad [string range "----------------------------------------" 1 $l] $ctext insert $curdiffstart "$pad $fname $pad" filesep @@@ -7155,7 -6977,7 +7104,7 @@@ proc getblobdiffline {bdf ids} global diffids blobdifffd ctext curdiffstart global diffnexthead diffnextnote difffilestart global ctext_file_names ctext_file_lines - global diffinhdr treediffs + global diffinhdr treediffs mergemax diffnparents global diffencoding jump_to_here targetline diffline set nr 0 @@@ -7165,47 -6987,75 +7114,75 @@@ close $bdf return 0 } - if {![string compare -length 11 "diff --git " $line]} { - # trim off "diff --git " - set line [string range $line 11 end] - set diffinhdr 1 + if {![string compare -length 5 "diff " $line]} { + if {![regexp {^diff (--cc|--git) } $line m type]} { + set line [encoding convertfrom $line] + $ctext insert end "$line\n" hunksep + continue + } # start of a new file + set diffinhdr 1 $ctext insert end "\n" set curdiffstart [$ctext index "end - 1c"] lappend ctext_file_names "" lappend ctext_file_lines [lindex [split $curdiffstart "."] 0] $ctext insert end "\n" filesep - # If the name hasn't changed the length will be odd, - # the middle char will be a space, and the two bits either - # side will be a/name and b/name, or "a/name" and "b/name". - # If the name has changed we'll get "rename from" and - # "rename to" or "copy from" and "copy to" lines following this, - # and we'll use them to get the filenames. - # This complexity is necessary because spaces in the filename(s) - # don't get escaped. - set l [string length $line] - set i [expr {$l / 2}] - if {!(($l & 1) && [string index $line $i] eq " " && - [string range $line 2 [expr {$i - 1}]] eq \ - [string range $line [expr {$i + 3}] end])} { - continue - } - # unescape if quoted and chop off the a/ from the front - if {[string index $line 0] eq "\""} { - set fname [string range [lindex $line 0] 2 end] + + if {$type eq "--cc"} { + # start of a new file in a merge diff + set fname [string range $line 10 end] + if {[lsearch -exact $treediffs($ids) $fname] < 0} { + lappend treediffs($ids) $fname + add_flist [list $fname] + } + } else { - set fname [string range $line 2 [expr {$i - 1}]] + set line [string range $line 11 end] + # If the name hasn't changed the length will be odd, + # the middle char will be a space, and the two bits either + # side will be a/name and b/name, or "a/name" and "b/name". + # If the name has changed we'll get "rename from" and + # "rename to" or "copy from" and "copy to" lines following + # this, and we'll use them to get the filenames. + # This complexity is necessary because spaces in the + # filename(s) don't get escaped. + set l [string length $line] + set i [expr {$l / 2}] + if {!(($l & 1) && [string index $line $i] eq " " && + [string range $line 2 [expr {$i - 1}]] eq \ + [string range $line [expr {$i + 3}] end])} { + continue + } + # unescape if quoted and chop off the a/ from the front + if {[string index $line 0] eq "\""} { + set fname [string range [lindex $line 0] 2 end] + } else { + set fname [string range $line 2 [expr {$i - 1}]] + } } - set fname [encoding convertfrom $fname] - set diffencoding [get_path_encoding $fname] makediffhdr $fname $ids - } elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \ - $line match f1l f1c f2l f2c rest]} { + } elseif {![string compare -length 16 "* Unmerged path " $line]} { + set fname [encoding convertfrom [string range $line 16 end]] + $ctext insert end "\n" + set curdiffstart [$ctext index "end - 1c"] + lappend ctext_file_names $fname + lappend ctext_file_lines [lindex [split $curdiffstart "."] 0] + $ctext insert end "$line\n" filesep + set i [lsearch -exact $treediffs($ids) $fname] + if {$i >= 0} { + setinlist difffilestart $i $curdiffstart + } + + } elseif {![string compare -length 2 "@@" $line]} { + regexp {^@@+} $line ats set line [encoding convertfrom $diffencoding $line] $ctext insert end "$line\n" hunksep + if {[regexp { \+(\d+),\d+ @@} $line m nl]} { + set diffline $nl + } + set diffnparents [expr {[string length $ats] - 1}] set diffinhdr 0 - set diffline $f2l } elseif {$diffinhdr} { if {![string compare -length 12 "rename from " $line]} { @@@ -7224,8 -7074,6 +7201,6 @@@ if {[string index $fname 0] eq "\""} { set fname [lindex $fname 0] } - set fname [encoding convertfrom $fname] - set diffencoding [get_path_encoding $fname] makediffhdr $fname $ids } elseif {[string compare -length 3 $line "---"] == 0} { # do nothing @@@ -7238,28 -7086,53 +7213,53 @@@ } else { set line [encoding convertfrom $diffencoding $line] - set x [string range $line 0 0] - set here [$ctext index "end - 1 chars"] - if {$x == "-" || $x == "+"} { - set tag [expr {$x == "+"}] - $ctext insert end "$line\n" d$tag - } elseif {$x == " "} { - $ctext insert end "$line\n" + # parse the prefix - one ' ', '-' or '+' for each parent + set prefix [string range $line 0 [expr {$diffnparents - 1}]] + set tag [expr {$diffnparents > 1? "m": "d"}] + if {[string trim $prefix " -+"] eq {}} { + # prefix only has " ", "-" and "+" in it: normal diff line + set num [string first "-" $prefix] + if {$num >= 0} { + # removed line, first parent with line is $num + if {$num >= $mergemax} { + set num "max" + } + $ctext insert end "$line\n" $tag$num + } else { + set tags {} + if {[string first "+" $prefix] >= 0} { + # added line + lappend tags ${tag}result + if {$diffnparents > 1} { + set num [string first " " $prefix] + if {$num >= 0} { + if {$num >= $mergemax} { + set num "max" + } + lappend tags m$num + } + } + } + if {$targetline ne {}} { + if {$diffline == $targetline} { + set seehere [$ctext index "end - 1 chars"] + set targetline {} + } else { + incr diffline + } + } + $ctext insert end "$line\n" $tags + } } else { # "\ No newline at end of file", # or something else we don't recognize $ctext insert end "$line\n" hunksep } - if {$targetline ne {} && ($x eq " " || $x eq "+")} { - if {$diffline == $targetline} { - mark_ctext_line [lindex [split $here .] 0] - set targetline {} - } else { - incr diffline - } - } } } + if {[info exists seehere]} { + mark_ctext_line [lindex [split $seehere .] 0] + } $ctext conf -state disabled if {[eof $bdf]} { close $bdf @@@ -7272,7 -7145,7 +7272,7 @@@ proc changediffdisp {} global ctext diffelide $ctext tag conf d0 -elide [lindex $diffelide 0] - $ctext tag conf d1 -elide [lindex $diffelide 1] + $ctext tag conf dresult -elide [lindex $diffelide 1] } proc highlightfile {loc cline} { @@@ -7890,7 -7763,6 +7890,7 @@@ proc mkpatch {} set patchtop $top catch {destroy $top} toplevel $top + wm transient $top . label $top.title -text [mc "Generate patch"] grid $top.title - -pady 10 label $top.from -text [mc "From:"] @@@ -7921,8 -7793,6 +7921,8 @@@ frame $top.buts button $top.buts.gen -text [mc "Generate"] -command mkpatchgo button $top.buts.can -text [mc "Cancel"] -command mkpatchcan + bind $top mkpatchgo + bind $top mkpatchcan grid $top.buts.gen $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@@ -7957,7 -7827,7 +7957,7 @@@ proc mkpatchgo {} set cmd [lrange $cmd 1 end] lappend cmd >$fname & if {[catch {eval exec $cmd} err]} { - error_popup "[mc "Error creating patch:"] $err" + error_popup "[mc "Error creating patch:"] $err" $patchtop } catch {destroy $patchtop} unset patchtop @@@ -7977,7 -7847,6 +7977,7 @@@ proc mktag {} set mktagtop $top catch {destroy $top} toplevel $top + wm transient $top . label $top.title -text [mc "Create tag"] grid $top.title - -pady 10 label $top.id -text [mc "ID:"] @@@ -7995,8 -7864,6 +7995,8 @@@ frame $top.buts button $top.buts.gen -text [mc "Create"] -command mktaggo button $top.buts.can -text [mc "Cancel"] -command mktagcan + bind $top mktaggo + bind $top mktagcan grid $top.buts.gen $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@@ -8010,18 -7877,18 +8010,18 @@@ proc domktag {} set id [$mktagtop.sha1 get] set tag [$mktagtop.tag get] if {$tag == {}} { - error_popup [mc "No tag name specified"] - return + error_popup [mc "No tag name specified"] $mktagtop + return 0 } if {[info exists tagids($tag)]} { - error_popup [mc "Tag \"%s\" already exists" $tag] - return + error_popup [mc "Tag \"%s\" already exists" $tag] $mktagtop + return 0 } if {[catch { exec git tag $tag $id } err]} { - error_popup "[mc "Error creating tag:"] $err" - return + error_popup "[mc "Error creating tag:"] $err" $mktagtop + return 0 } set tagids($tag) $id @@@ -8030,7 -7897,6 +8030,7 @@@ addedtag $id dispneartags 0 run refill_reflist + return 1 } proc redrawtags {id} { @@@ -8069,7 -7935,7 +8069,7 @@@ proc mktagcan {} } proc mktaggo {} { - domktag + if {![domktag]} return mktagcan } @@@ -8080,7 -7946,6 +8080,7 @@@ proc writecommit {} set wrcomtop $top catch {destroy $top} toplevel $top + wm transient $top . label $top.title -text [mc "Write commit to file"] grid $top.title - -pady 10 label $top.id -text [mc "ID:"] @@@ -8102,8 -7967,6 +8102,8 @@@ frame $top.buts button $top.buts.gen -text [mc "Write"] -command wrcomgo button $top.buts.can -text [mc "Cancel"] -command wrcomcan + bind $top wrcomgo + bind $top wrcomcan grid $top.buts.gen $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@@ -8118,7 -7981,7 +8118,7 @@@ proc wrcomgo {} set cmd "echo $id | [$wrcomtop.cmd get]" set fname [$wrcomtop.fname get] if {[catch {exec sh -c $cmd >$fname &} err]} { - error_popup "[mc "Error writing commit:"] $err" + error_popup "[mc "Error writing commit:"] $err" $wrcomtop } catch {destroy $wrcomtop} unset wrcomtop @@@ -8137,7 -8000,6 +8137,7 @@@ proc mkbranch {} set top .makebranch catch {destroy $top} toplevel $top + wm transient $top . label $top.title -text [mc "Create new branch"] grid $top.title - -pady 10 label $top.id -text [mc "ID:"] @@@ -8152,8 -8014,6 +8152,8 @@@ frame $top.buts button $top.buts.go -text [mc "Create"] -command [list mkbrgo $top] button $top.buts.can -text [mc "Cancel"] -command "catch {destroy $top}" + bind $top [list mkbrgo $top] + bind $top "catch {destroy $top}" grid $top.buts.go $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@@ -8169,12 -8029,12 +8169,12 @@@ proc mkbrgo {top} set cmdargs {} set old_id {} if {$name eq {}} { - error_popup [mc "Please specify a name for the new branch"] + error_popup [mc "Please specify a name for the new branch"] $top return } if {[info exists headids($name)]} { if {![confirm_popup [mc \ - "Branch '%s' already exists. Overwrite?" $name]]} { + "Branch '%s' already exists. Overwrite?" $name] $top]} { return } set old_id $headids($name) @@@ -8207,32 -8067,6 +8207,32 @@@ } } +proc exec_citool {tool_args {baseid {}}} { + global commitinfo env + + set save_env [array get env GIT_AUTHOR_*] + + if {$baseid ne {}} { + if {![info exists commitinfo($baseid)]} { + getcommit $baseid + } + set author [lindex $commitinfo($baseid) 1] + set date [lindex $commitinfo($baseid) 2] + if {[regexp {^\s*(\S.*\S|\S)\s*<(.*)>\s*$} \ + $author author name email] + && $date ne {}} { + set env(GIT_AUTHOR_NAME) $name + set env(GIT_AUTHOR_EMAIL) $email + set env(GIT_AUTHOR_DATE) $date + } + } + + eval exec git citool $tool_args & + + array unset env GIT_AUTHOR_* + array set env $save_env +} + proc cherrypick {} { global rowmenuid curview global mainhead mainheadid @@@ -8251,26 -8085,7 +8251,26 @@@ # no error occurs, and exec takes that as an indication of error... if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} { notbusy cherrypick - error_popup $err + if {[regexp -line \ + {Entry '(.*)' (would be overwritten by merge|not uptodate)} \ + $err msg fname]} { + error_popup [mc "Cherry-pick failed because of local changes\ + to file '%s'.\nPlease commit, reset or stash\ + your changes and try again." $fname] + } elseif {[regexp -line \ + {^(CONFLICT \(.*\):|Automatic cherry-pick failed)} \ + $err]} { + if {[confirm_popup [mc "Cherry-pick failed because of merge\ + conflict.\nDo you wish to run git citool to\ + resolve it?"]]} { + # Force citool to read MERGE_MSG + file delete [file join [gitdir] "GITGUI_MSG"] + exec_citool {} $rowmenuid + } + } else { + error_popup $err + } + run updatecommits return } set newhead [exec git rev-parse HEAD] @@@ -8323,7 -8138,6 +8323,7 @@@ proc resethead {} button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w" pack $w.ok -side left -fill x -padx 20 -pady 20 button $w.cancel -text [mc Cancel] -command "destroy $w" + bind $w [list destroy $w] pack $w.cancel -side right -fill x -padx 20 -pady 20 bind $w "grab $w; focus $w" tkwait window $w @@@ -8480,7 -8294,6 +8480,7 @@@ proc showrefs {} } toplevel $top wm title $top [mc "Tags and heads: %s" [file tail [pwd]]] + wm transient $top . text $top.list -background $bgcolor -foreground $fgcolor \ -selectbackground $selectbgcolor -font mainfont \ -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \ @@@ -8502,7 -8315,6 +8502,7 @@@ pack $top.f.l -side left grid $top.f - -sticky ew -pady 2 button $top.close -command [list destroy $top] -text [mc "Close"] + bind $top [list destroy $top] grid $top.close - grid columnconfigure $top 0 -weight 1 grid rowconfigure $top 0 -weight 1 @@@ -9808,7 -9620,6 +9808,7 @@@ proc mkfontdisp {font top which} proc choosefont {font which} { global fontparam fontlist fonttop fontattr + global prefstop set fontparam(which) $which set fontparam(font) $font @@@ -9822,7 -9633,6 +9822,7 @@@ font create sample eval font config sample [font actual $font] toplevel $top + wm transient $top $prefstop wm title $top [mc "Gitk font chooser"] label $top.l -textvariable fontparam(which) pack $top.l -side top @@@ -9856,8 -9666,6 +9856,8 @@@ frame $top.buts button $top.buts.ok -text [mc "OK"] -command fontok -default active button $top.buts.can -text [mc "Cancel"] -command fontcan -default normal + bind $top fontok + bind $top fontcan grid $top.buts.ok $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@@ -9939,7 -9747,6 +9939,7 @@@ proc doprefs {} } toplevel $top wm title $top [mc "Gitk preferences"] + wm transient $top . label $top.ldisp -text [mc "Commit list display options"] grid $top.ldisp - -sticky w -pady 10 label $top.spacer -text " " @@@ -10010,7 -9817,7 +10010,7 @@@ label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1] button $top.diffnewbut -text [mc "Diff: new lines"] -font optionfont \ -command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \ - [list $ctext tag conf d1 -foreground]] + [list $ctext tag conf dresult -foreground]] grid x $top.diffnewbut $top.diffnew -sticky w label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2] button $top.hunksepbut -text [mc "Diff: hunk header"] -font optionfont \ @@@ -10038,8 -9845,6 +10038,8 @@@ frame $top.buts button $top.buts.ok -text [mc "OK"] -command prefsok -default active button $top.buts.can -text [mc "Cancel"] -command prefscan -default normal + bind $top prefsok + bind $top prefscan grid $top.buts.ok $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a