Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 1 | # git-gui diff viewer |
| 2 | # Copyright (C) 2006, 2007 Shawn Pearce |
| 3 | |
Michael Lutz | a43c5f5 | 2012-02-12 16:55:17 +0100 | [diff] [blame] | 4 | proc apply_tab_size {{firsttab {}}} { |
| 5 | global have_tk85 repo_config ui_diff |
| 6 | |
| 7 | set w [font measure font_diff "0"] |
| 8 | if {$have_tk85 && $firsttab != 0} { |
| 9 | $ui_diff configure -tabs [list [expr {$firsttab * $w}] [expr {($firsttab + $repo_config(gui.tabsize)) * $w}]] |
| 10 | } elseif {$have_tk85 || $repo_config(gui.tabsize) != 8} { |
| 11 | $ui_diff configure -tabs [expr {$repo_config(gui.tabsize) * $w}] |
| 12 | } else { |
| 13 | $ui_diff configure -tabs {} |
| 14 | } |
| 15 | } |
| 16 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 17 | proc clear_diff {} { |
| 18 | global ui_diff current_diff_path current_diff_header |
| 19 | global ui_index ui_workdir |
| 20 | |
| 21 | $ui_diff conf -state normal |
| 22 | $ui_diff delete 0.0 end |
| 23 | $ui_diff conf -state disabled |
| 24 | |
| 25 | set current_diff_path {} |
| 26 | set current_diff_header {} |
| 27 | |
| 28 | $ui_index tag remove in_diff 0.0 end |
| 29 | $ui_workdir tag remove in_diff 0.0 end |
| 30 | } |
| 31 | |
Alexander Gavrilov | 7cf4566 | 2008-11-16 21:46:48 +0300 | [diff] [blame] | 32 | proc reshow_diff {{after {}}} { |
Shawn O. Pearce | 699d560 | 2007-07-05 23:16:13 -0400 | [diff] [blame] | 33 | global file_states file_lists |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 34 | global current_diff_path current_diff_side |
Alexander Gavrilov | 25b8fb1 | 2008-07-27 10:35:38 +0400 | [diff] [blame] | 35 | global ui_diff |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 36 | |
| 37 | set p $current_diff_path |
| 38 | if {$p eq {}} { |
| 39 | # No diff is being shown. |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 40 | } elseif {$current_diff_side eq {}} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 41 | clear_diff |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 42 | } elseif {[catch {set s $file_states($p)}] |
| 43 | || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { |
| 44 | |
| 45 | if {[find_next_diff $current_diff_side $p {} {[^O]}]} { |
Alexander Gavrilov | 7cf4566 | 2008-11-16 21:46:48 +0300 | [diff] [blame] | 46 | next_diff $after |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 47 | } else { |
| 48 | clear_diff |
| 49 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 50 | } else { |
Alexander Gavrilov | 25b8fb1 | 2008-07-27 10:35:38 +0400 | [diff] [blame] | 51 | set save_pos [lindex [$ui_diff yview] 0] |
Alexander Gavrilov | 7cf4566 | 2008-11-16 21:46:48 +0300 | [diff] [blame] | 52 | show_diff $p $current_diff_side {} $save_pos $after |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 53 | } |
| 54 | } |
| 55 | |
Alexander Gavrilov | 3fe0162 | 2008-09-18 01:07:34 +0400 | [diff] [blame] | 56 | proc force_diff_encoding {enc} { |
| 57 | global current_diff_path |
| 58 | |
| 59 | if {$current_diff_path ne {}} { |
| 60 | force_path_encoding $current_diff_path $enc |
| 61 | reshow_diff |
| 62 | } |
| 63 | } |
| 64 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 65 | proc handle_empty_diff {} { |
| 66 | global current_diff_path file_states file_lists |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 67 | global diff_empty_count |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 68 | |
| 69 | set path $current_diff_path |
| 70 | set s $file_states($path) |
Clément Poulain | 1fbacca | 2010-07-30 09:11:02 +0100 | [diff] [blame] | 71 | if {[lindex $s 0] ne {_M} || [has_textconv $path]} return |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 72 | |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 73 | # Prevent infinite rescan loops |
| 74 | incr diff_empty_count |
| 75 | if {$diff_empty_count > 1} return |
| 76 | |
Christian Stimming | 1ac1795 | 2007-07-21 14:21:34 +0200 | [diff] [blame] | 77 | info_popup [mc "No differences detected. |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 78 | |
Christian Stimming | 1ac1795 | 2007-07-21 14:21:34 +0200 | [diff] [blame] | 79 | %s has no changes. |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 80 | |
| 81 | The modification date of this file was updated by another application, but the content within the file was not changed. |
| 82 | |
Christian Stimming | 1ac1795 | 2007-07-21 14:21:34 +0200 | [diff] [blame] | 83 | A rescan will be automatically started to find other files which may have the same state." [short_path $path]] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 84 | |
| 85 | clear_diff |
| 86 | display_file $path __ |
Shawn O. Pearce | 699d560 | 2007-07-05 23:16:13 -0400 | [diff] [blame] | 87 | rescan ui_ready 0 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 88 | } |
| 89 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 90 | proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 91 | global file_states file_lists |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 92 | global is_3way_diff is_conflict_diff diff_active repo_config |
Shawn O. Pearce | 699d560 | 2007-07-05 23:16:13 -0400 | [diff] [blame] | 93 | global ui_diff ui_index ui_workdir |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 94 | global current_diff_path current_diff_side current_diff_header |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 95 | global current_diff_queue |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 96 | |
| 97 | if {$diff_active || ![lock_index read]} return |
| 98 | |
| 99 | clear_diff |
| 100 | if {$lno == {}} { |
| 101 | set lno [lsearch -sorted -exact $file_lists($w) $path] |
| 102 | if {$lno >= 0} { |
| 103 | incr lno |
| 104 | } |
| 105 | } |
| 106 | if {$lno >= 1} { |
| 107 | $w tag add in_diff $lno.0 [expr {$lno + 1}].0 |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 108 | $w see $lno.0 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | set s $file_states($path) |
| 112 | set m [lindex $s 0] |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 113 | set is_conflict_diff 0 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 114 | set current_diff_path $path |
| 115 | set current_diff_side $w |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 116 | set current_diff_queue {} |
Michele Ballabio | c8c4854 | 2007-09-13 15:19:05 +0200 | [diff] [blame] | 117 | ui_status [mc "Loading diff of %s..." [escape_path $path]] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 118 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 119 | set cont_info [list $scroll_pos $callback] |
| 120 | |
Michael Lutz | a43c5f5 | 2012-02-12 16:55:17 +0100 | [diff] [blame] | 121 | apply_tab_size 0 |
| 122 | |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 123 | if {[string first {U} $m] >= 0} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 124 | merge_load_stages $path [list show_unmerged_diff $cont_info] |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 125 | } elseif {$m eq {_O}} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 126 | show_other_diff $path $w $m $cont_info |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 127 | } else { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 128 | start_show_diff $cont_info |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 129 | } |
Alex Riesen | a0a0c68 | 2016-06-28 10:59:25 +0200 | [diff] [blame] | 130 | |
| 131 | global current_diff_path selected_paths |
| 132 | set selected_paths($current_diff_path) 1 |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 133 | } |
| 134 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 135 | proc show_unmerged_diff {cont_info} { |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 136 | global current_diff_path current_diff_side |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 137 | global merge_stages ui_diff is_conflict_diff |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 138 | global current_diff_queue |
| 139 | |
| 140 | if {$merge_stages(2) eq {}} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 141 | set is_conflict_diff 1 |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 142 | lappend current_diff_queue \ |
Bert Wesarg | c7ec31a | 2010-11-29 09:21:57 +0100 | [diff] [blame] | 143 | [list [mc "LOCAL: deleted\nREMOTE:\n"] d= \ |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 144 | [list ":1:$current_diff_path" ":3:$current_diff_path"]] |
| 145 | } elseif {$merge_stages(3) eq {}} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 146 | set is_conflict_diff 1 |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 147 | lappend current_diff_queue \ |
Bert Wesarg | c7ec31a | 2010-11-29 09:21:57 +0100 | [diff] [blame] | 148 | [list [mc "REMOTE: deleted\nLOCAL:\n"] d= \ |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 149 | [list ":1:$current_diff_path" ":2:$current_diff_path"]] |
| 150 | } elseif {[lindex $merge_stages(1) 0] eq {120000} |
| 151 | || [lindex $merge_stages(2) 0] eq {120000} |
| 152 | || [lindex $merge_stages(3) 0] eq {120000}} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 153 | set is_conflict_diff 1 |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 154 | lappend current_diff_queue \ |
Bert Wesarg | c7ec31a | 2010-11-29 09:21:57 +0100 | [diff] [blame] | 155 | [list [mc "LOCAL:\n"] d= \ |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 156 | [list ":1:$current_diff_path" ":2:$current_diff_path"]] |
| 157 | lappend current_diff_queue \ |
Bert Wesarg | c7ec31a | 2010-11-29 09:21:57 +0100 | [diff] [blame] | 158 | [list [mc "REMOTE:\n"] d= \ |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 159 | [list ":1:$current_diff_path" ":3:$current_diff_path"]] |
| 160 | } else { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 161 | start_show_diff $cont_info |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 162 | return |
| 163 | } |
| 164 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 165 | advance_diff_queue $cont_info |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 166 | } |
| 167 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 168 | proc advance_diff_queue {cont_info} { |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 169 | global current_diff_queue ui_diff |
| 170 | |
| 171 | set item [lindex $current_diff_queue 0] |
| 172 | set current_diff_queue [lrange $current_diff_queue 1 end] |
| 173 | |
| 174 | $ui_diff conf -state normal |
| 175 | $ui_diff insert end [lindex $item 0] [lindex $item 1] |
| 176 | $ui_diff conf -state disabled |
| 177 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 178 | start_show_diff $cont_info [lindex $item 2] |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 179 | } |
| 180 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 181 | proc show_other_diff {path w m cont_info} { |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 182 | global file_states file_lists |
| 183 | global is_3way_diff diff_active repo_config |
| 184 | global ui_diff ui_index ui_workdir |
| 185 | global current_diff_path current_diff_side current_diff_header |
| 186 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 187 | # - Git won't give us the diff, there's nothing to compare to! |
| 188 | # |
| 189 | if {$m eq {_O}} { |
Johannes Sixt | f2df8a5 | 2008-10-03 10:28:49 +0200 | [diff] [blame] | 190 | set max_sz 100000 |
Shawn O. Pearce | 3b9dfde | 2007-09-09 20:13:10 -0400 | [diff] [blame] | 191 | set type unknown |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 192 | if {[catch { |
Shawn O. Pearce | 3b9dfde | 2007-09-09 20:13:10 -0400 | [diff] [blame] | 193 | set type [file type $path] |
| 194 | switch -- $type { |
| 195 | directory { |
| 196 | set type submodule |
| 197 | set content {} |
| 198 | set sz 0 |
| 199 | } |
| 200 | link { |
Michele Ballabio | 2d19f8e | 2007-09-09 21:04:45 +0200 | [diff] [blame] | 201 | set content [file readlink $path] |
| 202 | set sz [string length $content] |
Shawn O. Pearce | 3b9dfde | 2007-09-09 20:13:10 -0400 | [diff] [blame] | 203 | } |
| 204 | file { |
Michele Ballabio | 2d19f8e | 2007-09-09 21:04:45 +0200 | [diff] [blame] | 205 | set fd [open $path r] |
Shawn O. Pearce | 1ffca60 | 2008-01-23 00:37:10 -0500 | [diff] [blame] | 206 | fconfigure $fd \ |
| 207 | -eofchar {} \ |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 208 | -encoding [get_path_encoding $path] |
Michele Ballabio | 2d19f8e | 2007-09-09 21:04:45 +0200 | [diff] [blame] | 209 | set content [read $fd $max_sz] |
| 210 | close $fd |
| 211 | set sz [file size $path] |
| 212 | } |
Shawn O. Pearce | 3b9dfde | 2007-09-09 20:13:10 -0400 | [diff] [blame] | 213 | default { |
| 214 | error "'$type' not supported" |
| 215 | } |
| 216 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 217 | } err ]} { |
| 218 | set diff_active 0 |
| 219 | unlock_index |
Michele Ballabio | c8c4854 | 2007-09-13 15:19:05 +0200 | [diff] [blame] | 220 | ui_status [mc "Unable to display %s" [escape_path $path]] |
Shawn O. Pearce | 31bb1d1 | 2007-09-14 01:50:09 -0400 | [diff] [blame] | 221 | error_popup [strcat [mc "Error loading file:"] "\n\n$err"] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 222 | return |
| 223 | } |
| 224 | $ui_diff conf -state normal |
Shawn O. Pearce | 3b9dfde | 2007-09-09 20:13:10 -0400 | [diff] [blame] | 225 | if {$type eq {submodule}} { |
Vasco Almeida | a3d97af | 2016-05-08 10:52:57 +0000 | [diff] [blame] | 226 | $ui_diff insert end \ |
| 227 | "* [mc "Git Repository (subproject)"]\n" \ |
| 228 | d_info |
Shawn O. Pearce | 3b9dfde | 2007-09-09 20:13:10 -0400 | [diff] [blame] | 229 | } elseif {![catch {set type [exec file $path]}]} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 230 | set n [string length $path] |
| 231 | if {[string equal -length $n $path $type]} { |
| 232 | set type [string range $type $n end] |
| 233 | regsub {^:?\s*} $type {} type |
| 234 | } |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 235 | $ui_diff insert end "* $type\n" d_info |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 236 | } |
| 237 | if {[string first "\0" $content] != -1} { |
| 238 | $ui_diff insert end \ |
Michele Ballabio | c8c4854 | 2007-09-13 15:19:05 +0200 | [diff] [blame] | 239 | [mc "* Binary file (not showing content)."] \ |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 240 | d_info |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 241 | } else { |
| 242 | if {$sz > $max_sz} { |
Johannes Sixt | 7f15b00 | 2008-10-03 13:13:42 +0200 | [diff] [blame] | 243 | $ui_diff insert end [mc \ |
| 244 | "* Untracked file is %d bytes. |
| 245 | * Showing only first %d bytes. |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 246 | " $sz $max_sz] d_info |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 247 | } |
| 248 | $ui_diff insert end $content |
| 249 | if {$sz > $max_sz} { |
Johannes Sixt | 7f15b00 | 2008-10-03 13:13:42 +0200 | [diff] [blame] | 250 | $ui_diff insert end [mc " |
| 251 | * Untracked file clipped here by %s. |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 252 | * To see the entire file, use an external editor. |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 253 | " [appname]] d_info |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 254 | } |
| 255 | } |
| 256 | $ui_diff conf -state disabled |
| 257 | set diff_active 0 |
| 258 | unlock_index |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 259 | set scroll_pos [lindex $cont_info 0] |
Alexander Gavrilov | 25b8fb1 | 2008-07-27 10:35:38 +0400 | [diff] [blame] | 260 | if {$scroll_pos ne {}} { |
| 261 | update |
| 262 | $ui_diff yview moveto $scroll_pos |
| 263 | } |
Shawn O. Pearce | 699d560 | 2007-07-05 23:16:13 -0400 | [diff] [blame] | 264 | ui_ready |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 265 | set callback [lindex $cont_info 1] |
| 266 | if {$callback ne {}} { |
| 267 | eval $callback |
| 268 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 269 | return |
| 270 | } |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 271 | } |
| 272 | |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 273 | proc get_conflict_marker_size {path} { |
| 274 | set size 7 |
| 275 | catch { |
| 276 | set fd_rc [eval [list git_read check-attr "conflict-marker-size" -- $path]] |
| 277 | set ret [gets $fd_rc line] |
| 278 | close $fd_rc |
| 279 | if {$ret > 0} { |
| 280 | regexp {.*: conflict-marker-size: (\d+)$} $line line size |
| 281 | } |
| 282 | } |
| 283 | return $size |
| 284 | } |
| 285 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 286 | proc start_show_diff {cont_info {add_opts {}}} { |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 287 | global file_states file_lists |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 288 | global is_3way_diff is_submodule_diff diff_active repo_config |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 289 | global ui_diff ui_index ui_workdir |
| 290 | global current_diff_path current_diff_side current_diff_header |
| 291 | |
| 292 | set path $current_diff_path |
| 293 | set w $current_diff_side |
| 294 | |
| 295 | set s $file_states($path) |
| 296 | set m [lindex $s 0] |
| 297 | set is_3way_diff 0 |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 298 | set is_submodule_diff 0 |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 299 | set diff_active 1 |
| 300 | set current_diff_header {} |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 301 | set conflict_size [get_conflict_marker_size $path] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 302 | |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 303 | set cmd [list] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 304 | if {$w eq $ui_index} { |
| 305 | lappend cmd diff-index |
| 306 | lappend cmd --cached |
Jens Lehmann | e0db1dd | 2014-04-08 21:30:51 +0200 | [diff] [blame] | 307 | if {[git-version >= "1.7.2"]} { |
| 308 | lappend cmd --ignore-submodules=dirty |
| 309 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 310 | } elseif {$w eq $ui_workdir} { |
Alexander Gavrilov | ff515d8 | 2008-08-31 01:00:49 +0400 | [diff] [blame] | 311 | if {[string first {U} $m] >= 0} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 312 | lappend cmd diff |
| 313 | } else { |
| 314 | lappend cmd diff-files |
| 315 | } |
| 316 | } |
Clément Poulain | 1fbacca | 2010-07-30 09:11:02 +0100 | [diff] [blame] | 317 | if {![is_config_false gui.textconv] && [git-version >= 1.6.1]} { |
| 318 | lappend cmd --textconv |
| 319 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 320 | |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 321 | if {[string match {160000 *} [lindex $s 2]] |
| 322 | || [string match {160000 *} [lindex $s 3]]} { |
| 323 | set is_submodule_diff 1 |
| 324 | |
| 325 | if {[git-version >= "1.6.6"]} { |
| 326 | lappend cmd --submodule |
| 327 | } |
| 328 | } |
| 329 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 330 | lappend cmd -p |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 331 | lappend cmd --color |
Tilman Vogel | 54531e7 | 2011-01-21 11:59:45 +0100 | [diff] [blame] | 332 | set cmd [concat $cmd $repo_config(gui.diffopts)] |
Clemens Buchacher | 55ba8a3 | 2008-08-30 18:45:27 +0200 | [diff] [blame] | 333 | if {$repo_config(gui.diffcontext) >= 1} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 334 | lappend cmd "-U$repo_config(gui.diffcontext)" |
| 335 | } |
| 336 | if {$w eq $ui_index} { |
| 337 | lappend cmd [PARENT] |
| 338 | } |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 339 | if {$add_opts ne {}} { |
| 340 | eval lappend cmd $add_opts |
| 341 | } else { |
| 342 | lappend cmd -- |
| 343 | lappend cmd $path |
| 344 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 345 | |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 346 | if {$is_submodule_diff && [git-version < "1.6.6"]} { |
Jens Lehmann | af413de | 2009-08-26 22:25:15 +0200 | [diff] [blame] | 347 | if {$w eq $ui_index} { |
Shawn O. Pearce | 118d938 | 2009-08-26 17:39:45 -0700 | [diff] [blame] | 348 | set cmd [list submodule summary --cached -- $path] |
Jens Lehmann | af413de | 2009-08-26 22:25:15 +0200 | [diff] [blame] | 349 | } else { |
Shawn O. Pearce | 118d938 | 2009-08-26 17:39:45 -0700 | [diff] [blame] | 350 | set cmd [list submodule summary --files -- $path] |
Jens Lehmann | af413de | 2009-08-26 22:25:15 +0200 | [diff] [blame] | 351 | } |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 352 | } |
| 353 | |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 354 | if {[catch {set fd [eval git_read --nice $cmd]} err]} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 355 | set diff_active 0 |
| 356 | unlock_index |
Michele Ballabio | c8c4854 | 2007-09-13 15:19:05 +0200 | [diff] [blame] | 357 | ui_status [mc "Unable to display %s" [escape_path $path]] |
Shawn O. Pearce | 31bb1d1 | 2007-09-14 01:50:09 -0400 | [diff] [blame] | 358 | error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 359 | return |
| 360 | } |
| 361 | |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 362 | set ::current_diff_inheader 1 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 363 | fconfigure $fd \ |
| 364 | -blocking 0 \ |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 365 | -encoding [get_path_encoding $path] \ |
Shawn O. Pearce | 1ffca60 | 2008-01-23 00:37:10 -0500 | [diff] [blame] | 366 | -translation lf |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 367 | fileevent $fd readable [list read_diff $fd $conflict_size $cont_info] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 368 | } |
| 369 | |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 370 | proc parse_color_line {line} { |
| 371 | set start 0 |
| 372 | set result "" |
| 373 | set markup [list] |
| 374 | set regexp {\033\[((?:\d+;)*\d+)?m} |
Bert Wesarg | 46a0431 | 2010-11-15 11:00:33 +0100 | [diff] [blame] | 375 | set need_reset 0 |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 376 | while {[regexp -indices -start $start $regexp $line match code]} { |
| 377 | foreach {begin end} $match break |
| 378 | append result [string range $line $start [expr {$begin - 1}]] |
Bert Wesarg | 46a0431 | 2010-11-15 11:00:33 +0100 | [diff] [blame] | 379 | set pos [string length $result] |
| 380 | set col [eval [linsert $code 0 string range $line]] |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 381 | set start [incr end] |
Bert Wesarg | 46a0431 | 2010-11-15 11:00:33 +0100 | [diff] [blame] | 382 | if {$col eq "0" || $col eq ""} { |
| 383 | if {!$need_reset} continue |
| 384 | set need_reset 0 |
| 385 | } else { |
| 386 | set need_reset 1 |
| 387 | } |
| 388 | lappend markup $pos $col |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 389 | } |
| 390 | append result [string range $line $start end] |
| 391 | if {[llength $markup] < 4} {set markup {}} |
| 392 | return [list $result $markup] |
| 393 | } |
| 394 | |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 395 | proc read_diff {fd conflict_size cont_info} { |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 396 | global ui_diff diff_active is_submodule_diff |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 397 | global is_3way_diff is_conflict_diff current_diff_header |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 398 | global current_diff_queue |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 399 | global diff_empty_count |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 400 | |
| 401 | $ui_diff conf -state normal |
| 402 | while {[gets $fd line] >= 0} { |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 403 | foreach {line markup} [parse_color_line $line] break |
| 404 | set line [string map {\033 ^} $line] |
| 405 | |
Bert Wesarg | 6459d7c | 2010-12-09 21:47:57 +0100 | [diff] [blame] | 406 | set tags {} |
| 407 | |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 408 | # -- Check for start of diff header. |
| 409 | if { [string match {diff --git *} $line] |
| 410 | || [string match {diff --cc *} $line] |
| 411 | || [string match {diff --combined *} $line]} { |
| 412 | set ::current_diff_inheader 1 |
| 413 | } |
| 414 | |
| 415 | # -- Check for end of diff header (any hunk line will do this). |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 416 | # |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 417 | if {[regexp {^@@+ } $line]} {set ::current_diff_inheader 0} |
| 418 | |
Bert Wesarg | 963ceab | 2010-12-09 21:47:56 +0100 | [diff] [blame] | 419 | # -- Automatically detect if this is a 3 way diff. |
| 420 | # |
Michael Lutz | a43c5f5 | 2012-02-12 16:55:17 +0100 | [diff] [blame] | 421 | if {[string match {@@@ *} $line]} { |
| 422 | set is_3way_diff 1 |
| 423 | apply_tab_size 1 |
| 424 | } |
Bert Wesarg | 963ceab | 2010-12-09 21:47:56 +0100 | [diff] [blame] | 425 | |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 426 | if {$::current_diff_inheader} { |
Bert Wesarg | d1c7f8a | 2010-12-09 21:47:58 +0100 | [diff] [blame] | 427 | |
| 428 | # -- These two lines stop a diff header and shouldn't be in there |
| 429 | if { [string match {Binary files * and * differ} $line] |
| 430 | || [regexp {^\* Unmerged path } $line]} { |
| 431 | set ::current_diff_inheader 0 |
| 432 | } else { |
| 433 | append current_diff_header $line "\n" |
| 434 | } |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 435 | |
| 436 | # -- Cleanup uninteresting diff header lines. |
| 437 | # |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 438 | if { [string match {diff --git *} $line] |
| 439 | || [string match {diff --cc *} $line] |
| 440 | || [string match {diff --combined *} $line] |
| 441 | || [string match {--- *} $line] |
Bert Wesarg | ebd143f | 2010-12-09 21:47:53 +0100 | [diff] [blame] | 442 | || [string match {+++ *} $line] |
| 443 | || [string match {index *} $line]} { |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 444 | continue |
| 445 | } |
Bert Wesarg | 97b8ee1 | 2010-12-09 21:47:54 +0100 | [diff] [blame] | 446 | |
| 447 | # -- Name it symlink, not 120000 |
| 448 | # Note, that the original line is in $current_diff_header |
| 449 | regsub {^(deleted|new) file mode 120000} $line {\1 symlink} line |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 450 | |
Bert Wesarg | bf59439 | 2010-12-09 21:47:59 +0100 | [diff] [blame] | 451 | } elseif { $line eq {\ No newline at end of file}} { |
| 452 | # -- Handle some special lines |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 453 | } elseif {$is_3way_diff} { |
| 454 | set op [string range $line 0 1] |
| 455 | switch -- $op { |
| 456 | { } {set tags {}} |
| 457 | {@@} {set tags d_@} |
| 458 | { +} {set tags d_s+} |
| 459 | { -} {set tags d_s-} |
| 460 | {+ } {set tags d_+s} |
| 461 | {- } {set tags d_-s} |
| 462 | {--} {set tags d_--} |
| 463 | {++} { |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 464 | set regexp [string map [list %conflict_size $conflict_size]\ |
| 465 | {^\+\+([<>=]){%conflict_size}(?: |$)}] |
| 466 | if {[regexp $regexp $line _g op]} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 467 | set is_conflict_diff 1 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 468 | set line [string replace $line 0 1 { }] |
| 469 | set tags d$op |
| 470 | } else { |
| 471 | set tags d_++ |
| 472 | } |
| 473 | } |
| 474 | default { |
| 475 | puts "error: Unhandled 3 way diff marker: {$op}" |
| 476 | set tags {} |
| 477 | } |
| 478 | } |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 479 | } elseif {$is_submodule_diff} { |
| 480 | if {$line == ""} continue |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 481 | if {[regexp {^Submodule } $line]} { |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 482 | set tags d_info |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 483 | } elseif {[regexp {^\* } $line]} { |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 484 | set line [string replace $line 0 1 {Submodule }] |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 485 | set tags d_info |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 486 | } else { |
| 487 | set op [string range $line 0 2] |
| 488 | switch -- $op { |
| 489 | { <} {set tags d_-} |
| 490 | { >} {set tags d_+} |
| 491 | { W} {set tags {}} |
| 492 | default { |
| 493 | puts "error: Unhandled submodule diff marker: {$op}" |
| 494 | set tags {} |
| 495 | } |
| 496 | } |
| 497 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 498 | } else { |
| 499 | set op [string index $line 0] |
| 500 | switch -- $op { |
| 501 | { } {set tags {}} |
| 502 | {@} {set tags d_@} |
| 503 | {-} {set tags d_-} |
| 504 | {+} { |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 505 | set regexp [string map [list %conflict_size $conflict_size]\ |
| 506 | {^\+([<>=]){%conflict_size}(?: |$)}] |
| 507 | if {[regexp $regexp $line _g op]} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 508 | set is_conflict_diff 1 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 509 | set tags d$op |
| 510 | } else { |
| 511 | set tags d_+ |
| 512 | } |
| 513 | } |
| 514 | default { |
| 515 | puts "error: Unhandled 2 way diff marker: {$op}" |
| 516 | set tags {} |
| 517 | } |
| 518 | } |
| 519 | } |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 520 | set mark [$ui_diff index "end - 1 line linestart"] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 521 | $ui_diff insert end $line $tags |
| 522 | if {[string index $line end] eq "\r"} { |
| 523 | $ui_diff tag add d_cr {end - 2c} |
| 524 | } |
| 525 | $ui_diff insert end "\n" $tags |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 526 | |
| 527 | foreach {posbegin colbegin posend colend} $markup { |
| 528 | set prefix clr |
Pat Thoyts | 3f2fb17 | 2010-11-19 22:22:20 +0000 | [diff] [blame] | 529 | foreach style [lsort -integer [split $colbegin ";"]] { |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 530 | if {$style eq "7"} {append prefix i; continue} |
Pat Thoyts | 9af6413 | 2010-11-19 10:00:49 +0000 | [diff] [blame] | 531 | if {$style != 4 && ($style < 30 || $style > 47)} {continue} |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 532 | set a "$mark linestart + $posbegin chars" |
| 533 | set b "$mark linestart + $posend chars" |
| 534 | catch {$ui_diff tag add $prefix$style $a $b} |
| 535 | } |
| 536 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 537 | } |
| 538 | $ui_diff conf -state disabled |
| 539 | |
| 540 | if {[eof $fd]} { |
| 541 | close $fd |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 542 | |
| 543 | if {$current_diff_queue ne {}} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 544 | advance_diff_queue $cont_info |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 545 | return |
| 546 | } |
| 547 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 548 | set diff_active 0 |
| 549 | unlock_index |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 550 | set scroll_pos [lindex $cont_info 0] |
Alexander Gavrilov | 25b8fb1 | 2008-07-27 10:35:38 +0400 | [diff] [blame] | 551 | if {$scroll_pos ne {}} { |
| 552 | update |
| 553 | $ui_diff yview moveto $scroll_pos |
| 554 | } |
Shawn O. Pearce | 699d560 | 2007-07-05 23:16:13 -0400 | [diff] [blame] | 555 | ui_ready |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 556 | |
| 557 | if {[$ui_diff index end] eq {2.0}} { |
| 558 | handle_empty_diff |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 559 | } else { |
| 560 | set diff_empty_count 0 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 561 | } |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 562 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 563 | set callback [lindex $cont_info 1] |
| 564 | if {$callback ne {}} { |
| 565 | eval $callback |
| 566 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 567 | } |
| 568 | } |
| 569 | |
| 570 | proc apply_hunk {x y} { |
| 571 | global current_diff_path current_diff_header current_diff_side |
| 572 | global ui_diff ui_index file_states |
| 573 | |
| 574 | if {$current_diff_path eq {} || $current_diff_header eq {}} return |
| 575 | if {![lock_index apply_hunk]} return |
| 576 | |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 577 | set apply_cmd {apply --cached --whitespace=nowarn} |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 578 | set mi [lindex $file_states($current_diff_path) 0] |
| 579 | if {$current_diff_side eq $ui_index} { |
Christian Stimming | 1ac1795 | 2007-07-21 14:21:34 +0200 | [diff] [blame] | 580 | set failed_msg [mc "Failed to unstage selected hunk."] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 581 | lappend apply_cmd --reverse |
| 582 | if {[string index $mi 0] ne {M}} { |
| 583 | unlock_index |
| 584 | return |
| 585 | } |
| 586 | } else { |
Christian Stimming | 1ac1795 | 2007-07-21 14:21:34 +0200 | [diff] [blame] | 587 | set failed_msg [mc "Failed to stage selected hunk."] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 588 | if {[string index $mi 1] ne {M}} { |
| 589 | unlock_index |
| 590 | return |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | set s_lno [lindex [split [$ui_diff index @$x,$y] .] 0] |
| 595 | set s_lno [$ui_diff search -backwards -regexp ^@@ $s_lno.0 0.0] |
| 596 | if {$s_lno eq {}} { |
| 597 | unlock_index |
| 598 | return |
| 599 | } |
| 600 | |
| 601 | set e_lno [$ui_diff search -forwards -regexp ^@@ "$s_lno + 1 lines" end] |
| 602 | if {$e_lno eq {}} { |
| 603 | set e_lno end |
| 604 | } |
| 605 | |
| 606 | if {[catch { |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 607 | set enc [get_path_encoding $current_diff_path] |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 608 | set p [eval git_write $apply_cmd] |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 609 | fconfigure $p -translation binary -encoding $enc |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 610 | puts -nonewline $p $current_diff_header |
| 611 | puts -nonewline $p [$ui_diff get $s_lno $e_lno] |
| 612 | close $p} err]} { |
Vasco Almeida | a3d97af | 2016-05-08 10:52:57 +0000 | [diff] [blame] | 613 | error_popup "$failed_msg\n\n$err" |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 614 | unlock_index |
| 615 | return |
| 616 | } |
| 617 | |
| 618 | $ui_diff conf -state normal |
| 619 | $ui_diff delete $s_lno $e_lno |
| 620 | $ui_diff conf -state disabled |
| 621 | |
| 622 | if {[$ui_diff get 1.0 end] eq "\n"} { |
| 623 | set o _ |
| 624 | } else { |
| 625 | set o ? |
| 626 | } |
| 627 | |
| 628 | if {$current_diff_side eq $ui_index} { |
| 629 | set mi ${o}M |
| 630 | } elseif {[string index $mi 0] eq {_}} { |
| 631 | set mi M$o |
| 632 | } else { |
| 633 | set mi ?$o |
| 634 | } |
| 635 | unlock_index |
| 636 | display_file $current_diff_path $mi |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 637 | # This should trigger shift to the next changed file |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 638 | if {$o eq {_}} { |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 639 | reshow_diff |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 640 | } |
| 641 | } |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 642 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 643 | proc apply_range_or_line {x y} { |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 644 | global current_diff_path current_diff_header current_diff_side |
| 645 | global ui_diff ui_index file_states |
| 646 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 647 | set selected [$ui_diff tag nextrange sel 0.0] |
| 648 | |
| 649 | if {$selected == {}} { |
| 650 | set first [$ui_diff index "@$x,$y"] |
| 651 | set last $first |
| 652 | } else { |
| 653 | set first [lindex $selected 0] |
| 654 | set last [lindex $selected 1] |
| 655 | } |
| 656 | |
| 657 | set first_l [$ui_diff index "$first linestart"] |
| 658 | set last_l [$ui_diff index "$last lineend"] |
| 659 | |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 660 | if {$current_diff_path eq {} || $current_diff_header eq {}} return |
| 661 | if {![lock_index apply_hunk]} return |
| 662 | |
| 663 | set apply_cmd {apply --cached --whitespace=nowarn} |
| 664 | set mi [lindex $file_states($current_diff_path) 0] |
| 665 | if {$current_diff_side eq $ui_index} { |
| 666 | set failed_msg [mc "Failed to unstage selected line."] |
| 667 | set to_context {+} |
| 668 | lappend apply_cmd --reverse |
| 669 | if {[string index $mi 0] ne {M}} { |
| 670 | unlock_index |
| 671 | return |
| 672 | } |
| 673 | } else { |
| 674 | set failed_msg [mc "Failed to stage selected line."] |
| 675 | set to_context {-} |
| 676 | if {[string index $mi 1] ne {M}} { |
| 677 | unlock_index |
| 678 | return |
| 679 | } |
| 680 | } |
| 681 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 682 | set wholepatch {} |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 683 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 684 | while {$first_l < $last_l} { |
| 685 | set i_l [$ui_diff search -backwards -regexp ^@@ $first_l 0.0] |
| 686 | if {$i_l eq {}} { |
| 687 | # If there's not a @@ above, then the selected range |
| 688 | # must have come before the first_l @@ |
| 689 | set i_l [$ui_diff search -regexp ^@@ $first_l $last_l] |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 690 | } |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 691 | if {$i_l eq {}} { |
| 692 | unlock_index |
| 693 | return |
| 694 | } |
| 695 | # $i_l is now at the beginning of a line |
| 696 | |
| 697 | # pick start line number from hunk header |
| 698 | set hh [$ui_diff get $i_l "$i_l + 1 lines"] |
| 699 | set hh [lindex [split $hh ,] 0] |
| 700 | set hln [lindex [split $hh -] 1] |
| 701 | |
| 702 | # There is a special situation to take care of. Consider this |
| 703 | # hunk: |
| 704 | # |
| 705 | # @@ -10,4 +10,4 @@ |
| 706 | # context before |
| 707 | # -old 1 |
| 708 | # -old 2 |
| 709 | # +new 1 |
| 710 | # +new 2 |
| 711 | # context after |
| 712 | # |
| 713 | # We used to keep the context lines in the order they appear in |
| 714 | # the hunk. But then it is not possible to correctly stage only |
| 715 | # "-old 1" and "+new 1" - it would result in this staged text: |
| 716 | # |
| 717 | # context before |
| 718 | # old 2 |
| 719 | # new 1 |
| 720 | # context after |
| 721 | # |
| 722 | # (By symmetry it is not possible to *un*stage "old 2" and "new |
| 723 | # 2".) |
| 724 | # |
| 725 | # We resolve the problem by introducing an asymmetry, namely, |
| 726 | # when a "+" line is *staged*, it is moved in front of the |
| 727 | # context lines that are generated from the "-" lines that are |
| 728 | # immediately before the "+" block. That is, we construct this |
| 729 | # patch: |
| 730 | # |
| 731 | # @@ -10,4 +10,5 @@ |
| 732 | # context before |
| 733 | # +new 1 |
| 734 | # old 1 |
| 735 | # old 2 |
| 736 | # context after |
| 737 | # |
| 738 | # But we do *not* treat "-" lines that are *un*staged in a |
| 739 | # special way. |
| 740 | # |
| 741 | # With this asymmetry it is possible to stage the change "old |
| 742 | # 1" -> "new 1" directly, and to stage the change "old 2" -> |
| 743 | # "new 2" by first staging the entire hunk and then unstaging |
| 744 | # the change "old 1" -> "new 1". |
| 745 | # |
| 746 | # Applying multiple lines adds complexity to the special |
| 747 | # situation. The pre_context must be moved after the entire |
| 748 | # first block of consecutive staged "+" lines, so that |
| 749 | # staging both additions gives the following patch: |
| 750 | # |
| 751 | # @@ -10,4 +10,6 @@ |
| 752 | # context before |
| 753 | # +new 1 |
| 754 | # +new 2 |
| 755 | # old 1 |
| 756 | # old 2 |
| 757 | # context after |
| 758 | |
| 759 | # This is non-empty if and only if we are _staging_ changes; |
| 760 | # then it accumulates the consecutive "-" lines (after |
| 761 | # converting them to context lines) in order to be moved after |
| 762 | # "+" change lines. |
| 763 | set pre_context {} |
| 764 | |
| 765 | set n 0 |
| 766 | set m 0 |
| 767 | set i_l [$ui_diff index "$i_l + 1 lines"] |
| 768 | set patch {} |
| 769 | while {[$ui_diff compare $i_l < "end - 1 chars"] && |
| 770 | [$ui_diff get $i_l "$i_l + 2 chars"] ne {@@}} { |
| 771 | set next_l [$ui_diff index "$i_l + 1 lines"] |
| 772 | set c1 [$ui_diff get $i_l] |
| 773 | if {[$ui_diff compare $first_l <= $i_l] && |
| 774 | [$ui_diff compare $i_l < $last_l] && |
| 775 | ($c1 eq {-} || $c1 eq {+})} { |
| 776 | # a line to stage/unstage |
| 777 | set ln [$ui_diff get $i_l $next_l] |
| 778 | if {$c1 eq {-}} { |
| 779 | set n [expr $n+1] |
| 780 | set patch "$patch$pre_context$ln" |
| 781 | set pre_context {} |
| 782 | } else { |
| 783 | set m [expr $m+1] |
| 784 | set patch "$patch$ln" |
| 785 | } |
| 786 | } elseif {$c1 ne {-} && $c1 ne {+}} { |
| 787 | # context line |
| 788 | set ln [$ui_diff get $i_l $next_l] |
| 789 | set patch "$patch$pre_context$ln" |
Heiko Voigt | 1fcd24d | 2013-05-09 18:30:02 +0200 | [diff] [blame] | 790 | # Skip the "\ No newline at end of |
| 791 | # file". Depending on the locale setting |
| 792 | # we don't know what this line looks |
| 793 | # like exactly. The only thing we do |
| 794 | # know is that it starts with "\ " |
| 795 | if {![string match {\\ *} $ln]} { |
| 796 | set n [expr $n+1] |
| 797 | set m [expr $m+1] |
| 798 | } |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 799 | set pre_context {} |
| 800 | } elseif {$c1 eq $to_context} { |
| 801 | # turn change line into context line |
| 802 | set ln [$ui_diff get "$i_l + 1 chars" $next_l] |
| 803 | if {$c1 eq {-}} { |
| 804 | set pre_context "$pre_context $ln" |
| 805 | } else { |
| 806 | set patch "$patch $ln" |
| 807 | } |
| 808 | set n [expr $n+1] |
| 809 | set m [expr $m+1] |
| 810 | } else { |
| 811 | # a change in the opposite direction of |
| 812 | # to_context which is outside the range of |
| 813 | # lines to apply. |
| 814 | set patch "$patch$pre_context" |
| 815 | set pre_context {} |
| 816 | } |
| 817 | set i_l $next_l |
| 818 | } |
| 819 | set patch "$patch$pre_context" |
| 820 | set wholepatch "$wholepatch@@ -$hln,$n +$hln,$m @@\n$patch" |
| 821 | set first_l [$ui_diff index "$next_l + 1 lines"] |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 822 | } |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 823 | |
| 824 | if {[catch { |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 825 | set enc [get_path_encoding $current_diff_path] |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 826 | set p [eval git_write $apply_cmd] |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 827 | fconfigure $p -translation binary -encoding $enc |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 828 | puts -nonewline $p $current_diff_header |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 829 | puts -nonewline $p $wholepatch |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 830 | close $p} err]} { |
Vasco Almeida | a3d97af | 2016-05-08 10:52:57 +0000 | [diff] [blame] | 831 | error_popup "$failed_msg\n\n$err" |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 832 | } |
| 833 | |
| 834 | unlock_index |
| 835 | } |