X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-gui%2Flib%2Fdiff.tcl;h=77990c537c9d068fdcdf62a83b8c132399dff749;hb=392f1300911120fbaa4b77c737fe13e205726aca;hp=694834ab7a515667dbd14b38165fbe74b37a0349;hpb=5e389c430d232e8b1a16e7357596328985111eab;p=git.git diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index 694834ab7..77990c537 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -39,13 +39,13 @@ proc handle_empty_diff {} { set s $file_states($path) if {[lindex $s 0] ne {_M}} return - info_popup "No differences detected. + info_popup [mc "No differences detected. -[short_path $path] has no changes. +%s has no changes. The modification date of this file was updated by another application, but the content within the file was not changed. -A rescan will be automatically started to find other files which may have the same state." +A rescan will be automatically started to find other files which may have the same state." [short_path $path]] clear_diff display_file $path __ @@ -78,7 +78,7 @@ proc show_diff {path w {lno {}}} { set current_diff_path $path set current_diff_side $w set current_diff_header {} - ui_status "Loading diff of [escape_path $path]..." + ui_status [mc "Loading diff of %s..." [escape_path $path]] # - Git won't give us the diff, there's nothing to compare to! # @@ -111,13 +111,16 @@ proc show_diff {path w {lno {}}} { } err ]} { set diff_active 0 unlock_index - ui_status "Unable to display [escape_path $path]" - error_popup "Error loading file:\n\n$err" + ui_status [mc "Unable to display %s" [escape_path $path]] + error_popup [strcat [mc "Error loading file:"] "\n\n$err"] return } $ui_diff conf -state normal if {$type eq {submodule}} { - $ui_diff insert end "* Git Repository (subproject)\n" d_@ + $ui_diff insert end [append \ + "* " \ + [mc "Git Repository (subproject)"] \ + "\n"] d_@ } elseif {![catch {set type [exec file $path]}]} { set n [string length $path] if {[string equal -length $n $path $type]} { @@ -128,7 +131,7 @@ proc show_diff {path w {lno {}}} { } if {[string first "\0" $content] != -1} { $ui_diff insert end \ - "* Binary file (not showing content)." \ + [mc "* Binary file (not showing content)."] \ d_@ } else { if {$sz > $max_sz} { @@ -178,8 +181,8 @@ proc show_diff {path w {lno {}}} { if {[catch {set fd [eval git_read --nice $cmd]} err]} { set diff_active 0 unlock_index - ui_status "Unable to display [escape_path $path]" - error_popup "Error loading diff:\n\n$err" + ui_status [mc "Unable to display %s" [escape_path $path]] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] return } @@ -217,6 +220,7 @@ proc read_diff {fd} { if {[string match {mode *} $line] || [string match {new file *} $line] + || [regexp {^(old|new) mode *} $line] || [string match {deleted file *} $line] || [string match {deleted symlink} $line] || [string match {Binary files * and * differ} $line] @@ -296,14 +300,14 @@ proc apply_hunk {x y} { set apply_cmd {apply --cached --whitespace=nowarn} set mi [lindex $file_states($current_diff_path) 0] if {$current_diff_side eq $ui_index} { - set mode unstage + set failed_msg [mc "Failed to unstage selected hunk."] lappend apply_cmd --reverse if {[string index $mi 0] ne {M}} { unlock_index return } } else { - set mode stage + set failed_msg [mc "Failed to stage selected hunk."] if {[string index $mi 1] ne {M}} { unlock_index return @@ -328,7 +332,7 @@ proc apply_hunk {x y} { puts -nonewline $p $current_diff_header puts -nonewline $p [$ui_diff get $s_lno $e_lno] close $p} err]} { - error_popup "Failed to $mode selected hunk.\n\n$err" + error_popup [append $failed_msg "\n\n$err"] unlock_index return } @@ -354,5 +358,152 @@ proc apply_hunk {x y} { display_file $current_diff_path $mi if {$o eq {_}} { clear_diff + } else { + set current_diff_path $current_diff_path + } +} + +proc apply_line {x y} { + global current_diff_path current_diff_header current_diff_side + global ui_diff ui_index file_states + + if {$current_diff_path eq {} || $current_diff_header eq {}} return + if {![lock_index apply_hunk]} return + + set apply_cmd {apply --cached --whitespace=nowarn} + set mi [lindex $file_states($current_diff_path) 0] + if {$current_diff_side eq $ui_index} { + set failed_msg [mc "Failed to unstage selected line."] + set to_context {+} + lappend apply_cmd --reverse + if {[string index $mi 0] ne {M}} { + unlock_index + return + } + } else { + set failed_msg [mc "Failed to stage selected line."] + set to_context {-} + if {[string index $mi 1] ne {M}} { + unlock_index + return + } + } + + set the_l [$ui_diff index @$x,$y] + + # operate only on change lines + set c1 [$ui_diff get "$the_l linestart"] + if {$c1 ne {+} && $c1 ne {-}} { + unlock_index + return } + set sign $c1 + + set i_l [$ui_diff search -backwards -regexp ^@@ $the_l 0.0] + if {$i_l eq {}} { + unlock_index + return + } + # $i_l is now at the beginning of a line + + # pick start line number from hunk header + set hh [$ui_diff get $i_l "$i_l + 1 lines"] + set hh [lindex [split $hh ,] 0] + set hln [lindex [split $hh -] 1] + + # There is a special situation to take care of. Consider this hunk: + # + # @@ -10,4 +10,4 @@ + # context before + # -old 1 + # -old 2 + # +new 1 + # +new 2 + # context after + # + # We used to keep the context lines in the order they appear in the + # hunk. But then it is not possible to correctly stage only + # "-old 1" and "+new 1" - it would result in this staged text: + # + # context before + # old 2 + # new 1 + # context after + # + # (By symmetry it is not possible to *un*stage "old 2" and "new 2".) + # + # We resolve the problem by introducing an asymmetry, namely, when + # a "+" line is *staged*, it is moved in front of the context lines + # that are generated from the "-" lines that are immediately before + # the "+" block. That is, we construct this patch: + # + # @@ -10,4 +10,5 @@ + # context before + # +new 1 + # old 1 + # old 2 + # context after + # + # But we do *not* treat "-" lines that are *un*staged in a special + # way. + # + # With this asymmetry it is possible to stage the change + # "old 1" -> "new 1" directly, and to stage the change + # "old 2" -> "new 2" by first staging the entire hunk and + # then unstaging the change "old 1" -> "new 1". + + # This is non-empty if and only if we are _staging_ changes; + # then it accumulates the consecutive "-" lines (after converting + # them to context lines) in order to be moved after the "+" change + # line. + set pre_context {} + + set n 0 + set i_l [$ui_diff index "$i_l + 1 lines"] + set patch {} + while {[$ui_diff compare $i_l < "end - 1 chars"] && + [$ui_diff get $i_l "$i_l + 2 chars"] ne {@@}} { + set next_l [$ui_diff index "$i_l + 1 lines"] + set c1 [$ui_diff get $i_l] + if {[$ui_diff compare $i_l <= $the_l] && + [$ui_diff compare $the_l < $next_l]} { + # the line to stage/unstage + set ln [$ui_diff get $i_l $next_l] + if {$c1 eq {-}} { + set n [expr $n+1] + set patch "$patch$pre_context$ln" + } else { + set patch "$patch$ln$pre_context" + } + set pre_context {} + } elseif {$c1 ne {-} && $c1 ne {+}} { + # context line + set ln [$ui_diff get $i_l $next_l] + set patch "$patch$pre_context$ln" + set n [expr $n+1] + set pre_context {} + } elseif {$c1 eq $to_context} { + # turn change line into context line + set ln [$ui_diff get "$i_l + 1 chars" $next_l] + if {$c1 eq {-}} { + set pre_context "$pre_context $ln" + } else { + set patch "$patch $ln" + } + set n [expr $n+1] + } + set i_l $next_l + } + set patch "@@ -$hln,$n +$hln,[eval expr $n $sign 1] @@\n$patch" + + if {[catch { + set p [eval git_write $apply_cmd] + fconfigure $p -translation binary -encoding binary + puts -nonewline $p $current_diff_header + puts -nonewline $p $patch + close $p} err]} { + error_popup [append $failed_msg "\n\n$err"] + } + + unlock_index }