summaryrefslogtreecommitdiff
path: root/git-gui
diff options
context:
space:
mode:
Diffstat (limited to 'git-gui')
-rwxr-xr-xgit-gui/git-gui.sh111
-rw-r--r--git-gui/lib/choose_repository.tcl8
-rw-r--r--git-gui/lib/diff.tcl87
3 files changed, 173 insertions, 33 deletions
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 9df49710e1..d89f156fd5 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -122,6 +122,14 @@ set _reponame {}
set _iscygwin {}
set _search_path {}
+set _trace [lsearch -exact $argv --trace]
+if {$_trace >= 0} {
+ set argv [lreplace $argv $_trace $_trace]
+ set _trace 1
+} else {
+ set _trace 0
+}
+
proc appname {} {
global _appname
return $_appname
@@ -245,6 +253,21 @@ proc get_config {name} {
##
## handy utils
+proc _trace_exec {cmd} {
+ if {!$::_trace} return
+ set d {}
+ foreach v $cmd {
+ if {$d ne {}} {
+ append d { }
+ }
+ if {[regexp {[ \t\r\n'"$?*]} $v]} {
+ set v [sq $v]
+ }
+ append d $v
+ }
+ puts stderr $d
+}
+
proc _git_cmd {name} {
global _git_cmd_path
@@ -339,7 +362,7 @@ proc _lappend_nice {cmd_var} {
}
proc git {args} {
- set opt [list exec]
+ set opt [list]
while {1} {
switch -- [lindex $args 0] {
@@ -359,12 +382,18 @@ proc git {args} {
set cmdp [_git_cmd [lindex $args 0]]
set args [lrange $args 1 end]
- return [eval $opt $cmdp $args]
+ _trace_exec [concat $opt $cmdp $args]
+ set result [eval exec $opt $cmdp $args]
+ if {$::_trace} {
+ puts stderr "< $result"
+ }
+ return $result
}
proc _open_stdout_stderr {cmd} {
+ _trace_exec $cmd
if {[catch {
- set fd [open $cmd r]
+ set fd [open [concat [list | ] $cmd] r]
} err]} {
if { [lindex $cmd end] eq {2>@1}
&& $err eq {can not find channel named "1"}
@@ -375,6 +404,7 @@ proc _open_stdout_stderr {cmd} {
# to try to start it a second time.
#
set fd [open [concat \
+ [list | ] \
[lrange $cmd 0 end-1] \
[list |& cat] \
] r]
@@ -387,7 +417,7 @@ proc _open_stdout_stderr {cmd} {
}
proc git_read {args} {
- set opt [list |]
+ set opt [list]
while {1} {
switch -- [lindex $args 0] {
@@ -415,7 +445,7 @@ proc git_read {args} {
}
proc git_write {args} {
- set opt [list |]
+ set opt [list]
while {1} {
switch -- [lindex $args 0] {
@@ -435,7 +465,8 @@ proc git_write {args} {
set cmdp [_git_cmd [lindex $args 0]]
set args [lrange $args 1 end]
- return [open [concat $opt $cmdp $args] w]
+ _trace_exec [concat $opt $cmdp $args]
+ return [open [concat [list | ] $opt $cmdp $args] w]
}
proc githook_read {hook_name args} {
@@ -455,12 +486,12 @@ proc githook_read {hook_name args} {
}
set scr {if test -x "$1";then exec "$@";fi}
- set sh_c [list | $interp -c $scr $interp $pchook]
+ set sh_c [list $interp -c $scr $interp $pchook]
return [_open_stdout_stderr [concat $sh_c $args]]
}
if {[file executable $pchook]} {
- return [_open_stdout_stderr [concat [list | $pchook] $args]]
+ return [_open_stdout_stderr [concat [list $pchook] $args]]
}
return {}
@@ -1096,27 +1127,18 @@ proc rescan {after {honor_trustmtime 1}} {
}
if {[is_Cygwin]} {
- set is_git_info_link {}
set is_git_info_exclude {}
proc have_info_exclude {} {
- global is_git_info_link is_git_info_exclude
-
- if {$is_git_info_link eq {}} {
- set is_git_info_link [file isfile [gitdir info.lnk]]
- }
+ global is_git_info_exclude
- if {$is_git_info_link} {
- if {$is_git_info_exclude eq {}} {
- if {[catch {exec test -f [gitdir info exclude]}]} {
- set is_git_info_exclude 0
- } else {
- set is_git_info_exclude 1
- }
+ if {$is_git_info_exclude eq {}} {
+ if {[catch {exec test -f [gitdir info exclude]}]} {
+ set is_git_info_exclude 0
+ } else {
+ set is_git_info_exclude 1
}
- return $is_git_info_exclude
- } else {
- return [file readable [gitdir info exclude]]
}
+ return $is_git_info_exclude
}
} else {
proc have_info_exclude {} {
@@ -1752,6 +1774,11 @@ proc do_commit {} {
commit_tree
}
+proc next_diff {} {
+ global next_diff_p next_diff_w next_diff_i
+ show_diff $next_diff_p $next_diff_w $next_diff_i
+}
+
proc toggle_or_diff {w x y} {
global file_states file_lists current_diff_path ui_index ui_workdir
global last_clicked selected_paths
@@ -1770,12 +1797,34 @@ proc toggle_or_diff {w x y} {
$ui_index tag remove in_sel 0.0 end
$ui_workdir tag remove in_sel 0.0 end
- if {$col == 0} {
- if {$current_diff_path eq $path} {
+ if {$col == 0 && $y > 1} {
+ set i [expr {$lno-1}]
+ set ll [expr {[llength $file_lists($w)]-1}]
+
+ if {$i == $ll && $i == 0} {
set after {reshow_diff;}
} else {
- set after {}
+ global next_diff_p next_diff_w next_diff_i
+
+ set next_diff_w $w
+
+ if {$i < $ll} {
+ set i [expr {$i + 1}]
+ set next_diff_i $i
+ } else {
+ set next_diff_i $i
+ set i [expr {$i - 1}]
+ }
+
+ set next_diff_p [lindex $file_lists($w) $i]
+
+ if {$next_diff_p ne {} && $current_diff_path ne {}} {
+ set after {next_diff;}
+ } else {
+ set after {}
+ }
}
+
if {$w eq $ui_index} {
update_indexinfo \
"Unstaging [short_path $path] from commit" \
@@ -2617,6 +2666,11 @@ $ctxm add command \
-command {apply_hunk $cursorX $cursorY}
set ui_diff_applyhunk [$ctxm index last]
lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
+$ctxm add command \
+ -label [mc "Apply/Reverse Line"] \
+ -command {apply_line $cursorX $cursorY; do_rescan}
+set ui_diff_applyline [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
$ctxm add separator
$ctxm add command \
-label [mc "Show Less Context"] \
@@ -2665,8 +2719,10 @@ proc popup_diff_menu {ctxm x y X Y} {
set ::cursorY $y
if {$::ui_index eq $::current_diff_side} {
set l [mc "Unstage Hunk From Commit"]
+ set t [mc "Unstage Line From Commit"]
} else {
set l [mc "Stage Hunk For Commit"]
+ set t [mc "Stage Line For Commit"]
}
if {$::is_3way_diff
|| $current_diff_path eq {}
@@ -2677,6 +2733,7 @@ proc popup_diff_menu {ctxm x y X Y} {
set s normal
}
$ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
+ $ctxm entryconf $::ui_diff_applyline -state $s -label $t
tk_popup $ctxm $X $Y
}
bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl
index ae4a4cd0a8..3180786158 100644
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -388,9 +388,7 @@ method _do_new {} {
-command [cb _new_local_path]
set w_localpath $w_body.where.t
- pack $w_body.where.b -side right
- pack $w_body.where.l -side left
- pack $w_body.where.t -fill x
+ grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
pack $w_body.where -fill x
trace add variable @local_path write [cb _write_local_path]
@@ -987,9 +985,7 @@ method _do_open {} {
-text [mc "Browse"] \
-command [cb _open_local_path]
- pack $w_body.where.b -side right
- pack $w_body.where.l -side left
- pack $w_body.where.t -fill x
+ grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
pack $w_body.where -fill x
trace add variable @local_path write [cb _write_local_path]
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index d04f6dbde2..96ba94906c 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -362,3 +362,90 @@ proc apply_hunk {x y} {
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]
+
+ 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]
+ set patch "$patch$ln"
+ } elseif {$c1 ne {-} && $c1 ne {+}} {
+ # context line
+ set ln [$ui_diff get $i_l $next_l]
+ set patch "$patch$ln"
+ set n [expr $n+1]
+ } elseif {$c1 eq $to_context} {
+ # turn change line into context line
+ set ln [$ui_diff get "$i_l + 1 chars" $next_l]
+ 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
+}