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 |
Pratyush Yadav | 5f0a516 | 2019-08-26 01:35:27 +0530 | [diff] [blame] | 58 | |
Alexander Gavrilov | 3fe0162 | 2008-09-18 01:07:34 +0400 | [diff] [blame] | 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 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 273 | proc start_show_diff {cont_info {add_opts {}}} { |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 274 | global file_states file_lists |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 275 | global is_3way_diff is_submodule_diff diff_active repo_config |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 276 | global ui_diff ui_index ui_workdir |
| 277 | global current_diff_path current_diff_side current_diff_header |
| 278 | |
| 279 | set path $current_diff_path |
| 280 | set w $current_diff_side |
| 281 | |
| 282 | set s $file_states($path) |
| 283 | set m [lindex $s 0] |
| 284 | set is_3way_diff 0 |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 285 | set is_submodule_diff 0 |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 286 | set diff_active 1 |
| 287 | set current_diff_header {} |
Bert Wesarg | c3b57dc | 2019-09-30 21:54:52 +0200 | [diff] [blame] | 288 | set conflict_size [gitattr $path conflict-marker-size 7] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 289 | |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 290 | set cmd [list] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 291 | if {$w eq $ui_index} { |
| 292 | lappend cmd diff-index |
| 293 | lappend cmd --cached |
Jens Lehmann | e0db1dd | 2014-04-08 21:30:51 +0200 | [diff] [blame] | 294 | if {[git-version >= "1.7.2"]} { |
| 295 | lappend cmd --ignore-submodules=dirty |
| 296 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 297 | } elseif {$w eq $ui_workdir} { |
Alexander Gavrilov | ff515d8 | 2008-08-31 01:00:49 +0400 | [diff] [blame] | 298 | if {[string first {U} $m] >= 0} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 299 | lappend cmd diff |
| 300 | } else { |
| 301 | lappend cmd diff-files |
| 302 | } |
| 303 | } |
Clément Poulain | 1fbacca | 2010-07-30 09:11:02 +0100 | [diff] [blame] | 304 | if {![is_config_false gui.textconv] && [git-version >= 1.6.1]} { |
| 305 | lappend cmd --textconv |
| 306 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 307 | |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 308 | if {[string match {160000 *} [lindex $s 2]] |
| 309 | || [string match {160000 *} [lindex $s 3]]} { |
| 310 | set is_submodule_diff 1 |
| 311 | |
| 312 | if {[git-version >= "1.6.6"]} { |
| 313 | lappend cmd --submodule |
| 314 | } |
| 315 | } |
| 316 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 317 | lappend cmd -p |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 318 | lappend cmd --color |
Tilman Vogel | 54531e7 | 2011-01-21 11:59:45 +0100 | [diff] [blame] | 319 | set cmd [concat $cmd $repo_config(gui.diffopts)] |
Clemens Buchacher | 55ba8a3 | 2008-08-30 18:45:27 +0200 | [diff] [blame] | 320 | if {$repo_config(gui.diffcontext) >= 1} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 321 | lappend cmd "-U$repo_config(gui.diffcontext)" |
| 322 | } |
| 323 | if {$w eq $ui_index} { |
| 324 | lappend cmd [PARENT] |
| 325 | } |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 326 | if {$add_opts ne {}} { |
| 327 | eval lappend cmd $add_opts |
| 328 | } else { |
| 329 | lappend cmd -- |
| 330 | lappend cmd $path |
| 331 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 332 | |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 333 | if {$is_submodule_diff && [git-version < "1.6.6"]} { |
Jens Lehmann | af413de | 2009-08-26 22:25:15 +0200 | [diff] [blame] | 334 | if {$w eq $ui_index} { |
Shawn O. Pearce | 118d938 | 2009-08-26 17:39:45 -0700 | [diff] [blame] | 335 | set cmd [list submodule summary --cached -- $path] |
Jens Lehmann | af413de | 2009-08-26 22:25:15 +0200 | [diff] [blame] | 336 | } else { |
Shawn O. Pearce | 118d938 | 2009-08-26 17:39:45 -0700 | [diff] [blame] | 337 | set cmd [list submodule summary --files -- $path] |
Jens Lehmann | af413de | 2009-08-26 22:25:15 +0200 | [diff] [blame] | 338 | } |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 339 | } |
| 340 | |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 341 | if {[catch {set fd [eval git_read --nice $cmd]} err]} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 342 | set diff_active 0 |
| 343 | unlock_index |
Michele Ballabio | c8c4854 | 2007-09-13 15:19:05 +0200 | [diff] [blame] | 344 | ui_status [mc "Unable to display %s" [escape_path $path]] |
Shawn O. Pearce | 31bb1d1 | 2007-09-14 01:50:09 -0400 | [diff] [blame] | 345 | error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 346 | return |
| 347 | } |
| 348 | |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 349 | set ::current_diff_inheader 1 |
Bert Wesarg | b436825 | 2019-10-02 09:36:02 +0200 | [diff] [blame] | 350 | # Detect pre-image lines of the diff3 conflict-style. They are just |
| 351 | # '++' lines which is not bijective. Thus, we need to maintain a state |
| 352 | # across lines. |
| 353 | set ::conflict_in_pre_image 0 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 354 | fconfigure $fd \ |
| 355 | -blocking 0 \ |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 356 | -encoding [get_path_encoding $path] \ |
Shawn O. Pearce | 1ffca60 | 2008-01-23 00:37:10 -0500 | [diff] [blame] | 357 | -translation lf |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 358 | fileevent $fd readable [list read_diff $fd $conflict_size $cont_info] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 359 | } |
| 360 | |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 361 | proc parse_color_line {line} { |
| 362 | set start 0 |
| 363 | set result "" |
| 364 | set markup [list] |
| 365 | set regexp {\033\[((?:\d+;)*\d+)?m} |
Bert Wesarg | 46a0431 | 2010-11-15 11:00:33 +0100 | [diff] [blame] | 366 | set need_reset 0 |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 367 | while {[regexp -indices -start $start $regexp $line match code]} { |
| 368 | foreach {begin end} $match break |
| 369 | append result [string range $line $start [expr {$begin - 1}]] |
Bert Wesarg | 46a0431 | 2010-11-15 11:00:33 +0100 | [diff] [blame] | 370 | set pos [string length $result] |
| 371 | set col [eval [linsert $code 0 string range $line]] |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 372 | set start [incr end] |
Bert Wesarg | 46a0431 | 2010-11-15 11:00:33 +0100 | [diff] [blame] | 373 | if {$col eq "0" || $col eq ""} { |
| 374 | if {!$need_reset} continue |
| 375 | set need_reset 0 |
| 376 | } else { |
| 377 | set need_reset 1 |
| 378 | } |
| 379 | lappend markup $pos $col |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 380 | } |
| 381 | append result [string range $line $start end] |
| 382 | if {[llength $markup] < 4} {set markup {}} |
| 383 | return [list $result $markup] |
| 384 | } |
| 385 | |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 386 | proc read_diff {fd conflict_size cont_info} { |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 387 | global ui_diff diff_active is_submodule_diff |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 388 | global is_3way_diff is_conflict_diff current_diff_header |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 389 | global current_diff_queue |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 390 | global diff_empty_count |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 391 | |
| 392 | $ui_diff conf -state normal |
| 393 | while {[gets $fd line] >= 0} { |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 394 | foreach {line markup} [parse_color_line $line] break |
| 395 | set line [string map {\033 ^} $line] |
| 396 | |
Bert Wesarg | 6459d7c | 2010-12-09 21:47:57 +0100 | [diff] [blame] | 397 | set tags {} |
| 398 | |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 399 | # -- Check for start of diff header. |
| 400 | if { [string match {diff --git *} $line] |
| 401 | || [string match {diff --cc *} $line] |
| 402 | || [string match {diff --combined *} $line]} { |
| 403 | set ::current_diff_inheader 1 |
| 404 | } |
| 405 | |
| 406 | # -- 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] | 407 | # |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 408 | if {[regexp {^@@+ } $line]} {set ::current_diff_inheader 0} |
| 409 | |
Bert Wesarg | 963ceab | 2010-12-09 21:47:56 +0100 | [diff] [blame] | 410 | # -- Automatically detect if this is a 3 way diff. |
| 411 | # |
Michael Lutz | a43c5f5 | 2012-02-12 16:55:17 +0100 | [diff] [blame] | 412 | if {[string match {@@@ *} $line]} { |
| 413 | set is_3way_diff 1 |
| 414 | apply_tab_size 1 |
| 415 | } |
Bert Wesarg | 963ceab | 2010-12-09 21:47:56 +0100 | [diff] [blame] | 416 | |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 417 | if {$::current_diff_inheader} { |
Bert Wesarg | d1c7f8a | 2010-12-09 21:47:58 +0100 | [diff] [blame] | 418 | |
| 419 | # -- These two lines stop a diff header and shouldn't be in there |
| 420 | if { [string match {Binary files * and * differ} $line] |
| 421 | || [regexp {^\* Unmerged path } $line]} { |
| 422 | set ::current_diff_inheader 0 |
| 423 | } else { |
| 424 | append current_diff_header $line "\n" |
| 425 | } |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 426 | |
| 427 | # -- Cleanup uninteresting diff header lines. |
| 428 | # |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 429 | if { [string match {diff --git *} $line] |
| 430 | || [string match {diff --cc *} $line] |
| 431 | || [string match {diff --combined *} $line] |
| 432 | || [string match {--- *} $line] |
Bert Wesarg | ebd143f | 2010-12-09 21:47:53 +0100 | [diff] [blame] | 433 | || [string match {+++ *} $line] |
| 434 | || [string match {index *} $line]} { |
Shawn O. Pearce | ca53c3f | 2008-09-04 21:46:56 -0700 | [diff] [blame] | 435 | continue |
| 436 | } |
Bert Wesarg | 97b8ee1 | 2010-12-09 21:47:54 +0100 | [diff] [blame] | 437 | |
| 438 | # -- Name it symlink, not 120000 |
| 439 | # Note, that the original line is in $current_diff_header |
| 440 | regsub {^(deleted|new) file mode 120000} $line {\1 symlink} line |
Bert Wesarg | c976bbf | 2010-12-09 21:47:52 +0100 | [diff] [blame] | 441 | |
Bert Wesarg | bf59439 | 2010-12-09 21:47:59 +0100 | [diff] [blame] | 442 | } elseif { $line eq {\ No newline at end of file}} { |
| 443 | # -- Handle some special lines |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 444 | } elseif {$is_3way_diff} { |
| 445 | set op [string range $line 0 1] |
| 446 | switch -- $op { |
| 447 | { } {set tags {}} |
| 448 | {@@} {set tags d_@} |
| 449 | { +} {set tags d_s+} |
| 450 | { -} {set tags d_s-} |
| 451 | {+ } {set tags d_+s} |
| 452 | {- } {set tags d_-s} |
| 453 | {--} {set tags d_--} |
| 454 | {++} { |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 455 | set regexp [string map [list %conflict_size $conflict_size]\ |
Bert Wesarg | b436825 | 2019-10-02 09:36:02 +0200 | [diff] [blame] | 456 | {^\+\+([<>=|]){%conflict_size}(?: |$)}] |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 457 | if {[regexp $regexp $line _g op]} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 458 | set is_conflict_diff 1 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 459 | set line [string replace $line 0 1 { }] |
| 460 | set tags d$op |
Bert Wesarg | b436825 | 2019-10-02 09:36:02 +0200 | [diff] [blame] | 461 | |
| 462 | # The ||| conflict-marker marks the start of the pre-image. |
| 463 | # All those lines are also prefixed with '++'. Thus we need |
| 464 | # to maintain this state. |
| 465 | set ::conflict_in_pre_image [expr {$op eq {|}}] |
| 466 | } elseif {$::conflict_in_pre_image} { |
| 467 | # This is a pre-image line. It is the one which both sides |
| 468 | # are based on. As it has also the '++' line start, it is |
| 469 | # normally shown as 'added'. Invert this to '--' to make |
| 470 | # it a 'removed' line. |
| 471 | set line [string replace $line 0 1 {--}] |
| 472 | set tags d_-- |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 473 | } else { |
| 474 | set tags d_++ |
| 475 | } |
| 476 | } |
| 477 | default { |
| 478 | puts "error: Unhandled 3 way diff marker: {$op}" |
| 479 | set tags {} |
| 480 | } |
| 481 | } |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 482 | } elseif {$is_submodule_diff} { |
| 483 | if {$line == ""} continue |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 484 | if {[regexp {^Submodule } $line]} { |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 485 | set tags d_info |
Jens Lehmann | a9ae14a | 2010-01-23 23:04:12 +0100 | [diff] [blame] | 486 | } elseif {[regexp {^\* } $line]} { |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 487 | set line [string replace $line 0 1 {Submodule }] |
Bert Wesarg | 88b21c2 | 2010-12-06 22:01:01 +0000 | [diff] [blame] | 488 | set tags d_info |
Jens Lehmann | 246295b | 2009-07-21 19:32:31 +0200 | [diff] [blame] | 489 | } else { |
| 490 | set op [string range $line 0 2] |
| 491 | switch -- $op { |
| 492 | { <} {set tags d_-} |
| 493 | { >} {set tags d_+} |
| 494 | { W} {set tags {}} |
| 495 | default { |
| 496 | puts "error: Unhandled submodule diff marker: {$op}" |
| 497 | set tags {} |
| 498 | } |
| 499 | } |
| 500 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 501 | } else { |
| 502 | set op [string index $line 0] |
| 503 | switch -- $op { |
| 504 | { } {set tags {}} |
| 505 | {@} {set tags d_@} |
| 506 | {-} {set tags d_-} |
| 507 | {+} { |
Bert Wesarg | 4590307 | 2010-11-16 10:21:52 +0100 | [diff] [blame] | 508 | set regexp [string map [list %conflict_size $conflict_size]\ |
| 509 | {^\+([<>=]){%conflict_size}(?: |$)}] |
| 510 | if {[regexp $regexp $line _g op]} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 511 | set is_conflict_diff 1 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 512 | set tags d$op |
| 513 | } else { |
| 514 | set tags d_+ |
| 515 | } |
| 516 | } |
| 517 | default { |
| 518 | puts "error: Unhandled 2 way diff marker: {$op}" |
| 519 | set tags {} |
| 520 | } |
| 521 | } |
| 522 | } |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 523 | set mark [$ui_diff index "end - 1 line linestart"] |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 524 | $ui_diff insert end $line $tags |
| 525 | if {[string index $line end] eq "\r"} { |
| 526 | $ui_diff tag add d_cr {end - 2c} |
| 527 | } |
| 528 | $ui_diff insert end "\n" $tags |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 529 | |
| 530 | foreach {posbegin colbegin posend colend} $markup { |
| 531 | set prefix clr |
Pat Thoyts | 3f2fb17 | 2010-11-19 22:22:20 +0000 | [diff] [blame] | 532 | foreach style [lsort -integer [split $colbegin ";"]] { |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 533 | if {$style eq "7"} {append prefix i; continue} |
Pat Thoyts | 9af6413 | 2010-11-19 10:00:49 +0000 | [diff] [blame] | 534 | if {$style != 4 && ($style < 30 || $style > 47)} {continue} |
Pat Thoyts | 8f85599 | 2010-10-22 16:14:38 +0100 | [diff] [blame] | 535 | set a "$mark linestart + $posbegin chars" |
| 536 | set b "$mark linestart + $posend chars" |
| 537 | catch {$ui_diff tag add $prefix$style $a $b} |
| 538 | } |
| 539 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 540 | } |
| 541 | $ui_diff conf -state disabled |
| 542 | |
| 543 | if {[eof $fd]} { |
| 544 | close $fd |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 545 | |
| 546 | if {$current_diff_queue ne {}} { |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 547 | advance_diff_queue $cont_info |
Alexander Gavrilov | b2ca414 | 2008-08-31 01:05:22 +0400 | [diff] [blame] | 548 | return |
| 549 | } |
| 550 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 551 | set diff_active 0 |
| 552 | unlock_index |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 553 | set scroll_pos [lindex $cont_info 0] |
Alexander Gavrilov | 25b8fb1 | 2008-07-27 10:35:38 +0400 | [diff] [blame] | 554 | if {$scroll_pos ne {}} { |
| 555 | update |
| 556 | $ui_diff yview moveto $scroll_pos |
| 557 | } |
Shawn O. Pearce | 699d560 | 2007-07-05 23:16:13 -0400 | [diff] [blame] | 558 | ui_ready |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 559 | |
| 560 | if {[$ui_diff index end] eq {2.0}} { |
| 561 | handle_empty_diff |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 562 | } else { |
| 563 | set diff_empty_count 0 |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 564 | } |
Alexander Gavrilov | 584fa9c | 2009-02-07 19:24:01 +0300 | [diff] [blame] | 565 | |
Alexander Gavrilov | 3e34838 | 2008-09-20 12:19:18 +0400 | [diff] [blame] | 566 | set callback [lindex $cont_info 1] |
| 567 | if {$callback ne {}} { |
| 568 | eval $callback |
| 569 | } |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 570 | } |
| 571 | } |
| 572 | |
Pratyush Yadav | 62bd999 | 2019-08-18 00:01:43 +0530 | [diff] [blame] | 573 | proc apply_or_revert_hunk {x y revert} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 574 | global current_diff_path current_diff_header current_diff_side |
Pratyush Yadav | a4fa2f0 | 2019-08-26 01:43:23 +0530 | [diff] [blame] | 575 | global ui_diff ui_index file_states last_revert last_revert_enc |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 576 | |
| 577 | if {$current_diff_path eq {} || $current_diff_header eq {}} return |
| 578 | if {![lock_index apply_hunk]} return |
| 579 | |
Pratyush Yadav | 62bd999 | 2019-08-18 00:01:43 +0530 | [diff] [blame] | 580 | set apply_cmd {apply --whitespace=nowarn} |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 581 | set mi [lindex $file_states($current_diff_path) 0] |
| 582 | if {$current_diff_side eq $ui_index} { |
Christian Stimming | 1ac1795 | 2007-07-21 14:21:34 +0200 | [diff] [blame] | 583 | set failed_msg [mc "Failed to unstage selected hunk."] |
Pratyush Yadav | 62bd999 | 2019-08-18 00:01:43 +0530 | [diff] [blame] | 584 | lappend apply_cmd --reverse --cached |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 585 | if {[string index $mi 0] ne {M}} { |
| 586 | unlock_index |
| 587 | return |
| 588 | } |
| 589 | } else { |
Pratyush Yadav | 62bd999 | 2019-08-18 00:01:43 +0530 | [diff] [blame] | 590 | if {$revert} { |
| 591 | set failed_msg [mc "Failed to revert selected hunk."] |
| 592 | lappend apply_cmd --reverse |
| 593 | } else { |
| 594 | set failed_msg [mc "Failed to stage selected hunk."] |
| 595 | lappend apply_cmd --cached |
| 596 | } |
| 597 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 598 | if {[string index $mi 1] ne {M}} { |
| 599 | unlock_index |
| 600 | return |
| 601 | } |
| 602 | } |
| 603 | |
| 604 | set s_lno [lindex [split [$ui_diff index @$x,$y] .] 0] |
| 605 | set s_lno [$ui_diff search -backwards -regexp ^@@ $s_lno.0 0.0] |
| 606 | if {$s_lno eq {}} { |
| 607 | unlock_index |
| 608 | return |
| 609 | } |
| 610 | |
| 611 | set e_lno [$ui_diff search -forwards -regexp ^@@ "$s_lno + 1 lines" end] |
| 612 | if {$e_lno eq {}} { |
| 613 | set e_lno end |
| 614 | } |
| 615 | |
Pratyush Yadav | a4fa2f0 | 2019-08-26 01:43:23 +0530 | [diff] [blame] | 616 | set wholepatch "$current_diff_header[$ui_diff get $s_lno $e_lno]" |
| 617 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 618 | if {[catch { |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 619 | set enc [get_path_encoding $current_diff_path] |
Shawn O. Pearce | 0b81261 | 2007-07-09 01:17:09 -0400 | [diff] [blame] | 620 | set p [eval git_write $apply_cmd] |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 621 | fconfigure $p -translation binary -encoding $enc |
Pratyush Yadav | a4fa2f0 | 2019-08-26 01:43:23 +0530 | [diff] [blame] | 622 | puts -nonewline $p $wholepatch |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 623 | close $p} err]} { |
Vasco Almeida | a3d97af | 2016-05-08 10:52:57 +0000 | [diff] [blame] | 624 | error_popup "$failed_msg\n\n$err" |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 625 | unlock_index |
| 626 | return |
| 627 | } |
| 628 | |
Pratyush Yadav | a4fa2f0 | 2019-08-26 01:43:23 +0530 | [diff] [blame] | 629 | if {$revert} { |
| 630 | # Save a copy of this patch for undoing reverts. |
| 631 | set last_revert $wholepatch |
| 632 | set last_revert_enc $enc |
| 633 | } |
| 634 | |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 635 | $ui_diff conf -state normal |
| 636 | $ui_diff delete $s_lno $e_lno |
| 637 | $ui_diff conf -state disabled |
| 638 | |
Pratyush Yadav | 62bd999 | 2019-08-18 00:01:43 +0530 | [diff] [blame] | 639 | # Check if the hunk was the last one in the file. |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 640 | if {[$ui_diff get 1.0 end] eq "\n"} { |
| 641 | set o _ |
| 642 | } else { |
| 643 | set o ? |
| 644 | } |
| 645 | |
Pratyush Yadav | 62bd999 | 2019-08-18 00:01:43 +0530 | [diff] [blame] | 646 | # Update the status flags. |
| 647 | if {$revert} { |
| 648 | set mi [string index $mi 0]$o |
| 649 | } elseif {$current_diff_side eq $ui_index} { |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 650 | set mi ${o}M |
| 651 | } elseif {[string index $mi 0] eq {_}} { |
| 652 | set mi M$o |
| 653 | } else { |
| 654 | set mi ?$o |
| 655 | } |
| 656 | unlock_index |
| 657 | display_file $current_diff_path $mi |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 658 | # This should trigger shift to the next changed file |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 659 | if {$o eq {_}} { |
Alexander Gavrilov | 29853b9 | 2008-08-31 01:02:56 +0400 | [diff] [blame] | 660 | reshow_diff |
Shawn O. Pearce | f522c9b | 2007-05-07 23:35:48 -0400 | [diff] [blame] | 661 | } |
| 662 | } |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 663 | |
Pratyush Yadav | 5f0a516 | 2019-08-26 01:35:27 +0530 | [diff] [blame] | 664 | proc apply_or_revert_range_or_line {x y revert} { |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 665 | global current_diff_path current_diff_header current_diff_side |
Pratyush Yadav | a4fa2f0 | 2019-08-26 01:43:23 +0530 | [diff] [blame] | 666 | global ui_diff ui_index file_states last_revert |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 667 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 668 | set selected [$ui_diff tag nextrange sel 0.0] |
| 669 | |
| 670 | if {$selected == {}} { |
| 671 | set first [$ui_diff index "@$x,$y"] |
| 672 | set last $first |
| 673 | } else { |
| 674 | set first [lindex $selected 0] |
| 675 | set last [lindex $selected 1] |
| 676 | } |
| 677 | |
| 678 | set first_l [$ui_diff index "$first linestart"] |
| 679 | set last_l [$ui_diff index "$last lineend"] |
| 680 | |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 681 | if {$current_diff_path eq {} || $current_diff_header eq {}} return |
| 682 | if {![lock_index apply_hunk]} return |
| 683 | |
Pratyush Yadav | 5f0a516 | 2019-08-26 01:35:27 +0530 | [diff] [blame] | 684 | set apply_cmd {apply --whitespace=nowarn} |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 685 | set mi [lindex $file_states($current_diff_path) 0] |
| 686 | if {$current_diff_side eq $ui_index} { |
| 687 | set failed_msg [mc "Failed to unstage selected line."] |
| 688 | set to_context {+} |
Pratyush Yadav | 5f0a516 | 2019-08-26 01:35:27 +0530 | [diff] [blame] | 689 | lappend apply_cmd --reverse --cached |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 690 | if {[string index $mi 0] ne {M}} { |
| 691 | unlock_index |
| 692 | return |
| 693 | } |
| 694 | } else { |
Pratyush Yadav | 5f0a516 | 2019-08-26 01:35:27 +0530 | [diff] [blame] | 695 | if {$revert} { |
| 696 | set failed_msg [mc "Failed to revert selected line."] |
| 697 | set to_context {+} |
| 698 | lappend apply_cmd --reverse |
| 699 | } else { |
| 700 | set failed_msg [mc "Failed to stage selected line."] |
| 701 | set to_context {-} |
| 702 | lappend apply_cmd --cached |
| 703 | } |
| 704 | |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 705 | if {[string index $mi 1] ne {M}} { |
| 706 | unlock_index |
| 707 | return |
| 708 | } |
| 709 | } |
| 710 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 711 | set wholepatch {} |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 712 | |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 713 | while {$first_l < $last_l} { |
| 714 | set i_l [$ui_diff search -backwards -regexp ^@@ $first_l 0.0] |
| 715 | if {$i_l eq {}} { |
| 716 | # If there's not a @@ above, then the selected range |
| 717 | # must have come before the first_l @@ |
| 718 | set i_l [$ui_diff search -regexp ^@@ $first_l $last_l] |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 719 | } |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 720 | if {$i_l eq {}} { |
| 721 | unlock_index |
| 722 | return |
| 723 | } |
| 724 | # $i_l is now at the beginning of a line |
| 725 | |
| 726 | # pick start line number from hunk header |
| 727 | set hh [$ui_diff get $i_l "$i_l + 1 lines"] |
| 728 | set hh [lindex [split $hh ,] 0] |
| 729 | set hln [lindex [split $hh -] 1] |
Johannes Schindelin | 6d02c1e | 2018-01-09 15:32:54 +0100 | [diff] [blame] | 730 | set hln [lindex [split $hln " "] 0] |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 731 | |
| 732 | # There is a special situation to take care of. Consider this |
| 733 | # hunk: |
| 734 | # |
| 735 | # @@ -10,4 +10,4 @@ |
| 736 | # context before |
| 737 | # -old 1 |
| 738 | # -old 2 |
| 739 | # +new 1 |
| 740 | # +new 2 |
| 741 | # context after |
| 742 | # |
| 743 | # We used to keep the context lines in the order they appear in |
| 744 | # the hunk. But then it is not possible to correctly stage only |
| 745 | # "-old 1" and "+new 1" - it would result in this staged text: |
| 746 | # |
| 747 | # context before |
| 748 | # old 2 |
| 749 | # new 1 |
| 750 | # context after |
| 751 | # |
| 752 | # (By symmetry it is not possible to *un*stage "old 2" and "new |
| 753 | # 2".) |
| 754 | # |
| 755 | # We resolve the problem by introducing an asymmetry, namely, |
| 756 | # when a "+" line is *staged*, it is moved in front of the |
| 757 | # context lines that are generated from the "-" lines that are |
| 758 | # immediately before the "+" block. That is, we construct this |
| 759 | # patch: |
| 760 | # |
| 761 | # @@ -10,4 +10,5 @@ |
| 762 | # context before |
| 763 | # +new 1 |
| 764 | # old 1 |
| 765 | # old 2 |
| 766 | # context after |
| 767 | # |
| 768 | # But we do *not* treat "-" lines that are *un*staged in a |
| 769 | # special way. |
| 770 | # |
| 771 | # With this asymmetry it is possible to stage the change "old |
| 772 | # 1" -> "new 1" directly, and to stage the change "old 2" -> |
| 773 | # "new 2" by first staging the entire hunk and then unstaging |
| 774 | # the change "old 1" -> "new 1". |
| 775 | # |
| 776 | # Applying multiple lines adds complexity to the special |
| 777 | # situation. The pre_context must be moved after the entire |
| 778 | # first block of consecutive staged "+" lines, so that |
| 779 | # staging both additions gives the following patch: |
| 780 | # |
| 781 | # @@ -10,4 +10,6 @@ |
| 782 | # context before |
| 783 | # +new 1 |
| 784 | # +new 2 |
| 785 | # old 1 |
| 786 | # old 2 |
| 787 | # context after |
| 788 | |
| 789 | # This is non-empty if and only if we are _staging_ changes; |
| 790 | # then it accumulates the consecutive "-" lines (after |
| 791 | # converting them to context lines) in order to be moved after |
| 792 | # "+" change lines. |
| 793 | set pre_context {} |
| 794 | |
| 795 | set n 0 |
| 796 | set m 0 |
| 797 | set i_l [$ui_diff index "$i_l + 1 lines"] |
| 798 | set patch {} |
| 799 | while {[$ui_diff compare $i_l < "end - 1 chars"] && |
| 800 | [$ui_diff get $i_l "$i_l + 2 chars"] ne {@@}} { |
| 801 | set next_l [$ui_diff index "$i_l + 1 lines"] |
| 802 | set c1 [$ui_diff get $i_l] |
| 803 | if {[$ui_diff compare $first_l <= $i_l] && |
| 804 | [$ui_diff compare $i_l < $last_l] && |
| 805 | ($c1 eq {-} || $c1 eq {+})} { |
| 806 | # a line to stage/unstage |
| 807 | set ln [$ui_diff get $i_l $next_l] |
| 808 | if {$c1 eq {-}} { |
| 809 | set n [expr $n+1] |
| 810 | set patch "$patch$pre_context$ln" |
| 811 | set pre_context {} |
| 812 | } else { |
| 813 | set m [expr $m+1] |
| 814 | set patch "$patch$ln" |
| 815 | } |
| 816 | } elseif {$c1 ne {-} && $c1 ne {+}} { |
| 817 | # context line |
| 818 | set ln [$ui_diff get $i_l $next_l] |
| 819 | set patch "$patch$pre_context$ln" |
Heiko Voigt | 1fcd24d | 2013-05-09 18:30:02 +0200 | [diff] [blame] | 820 | # Skip the "\ No newline at end of |
| 821 | # file". Depending on the locale setting |
| 822 | # we don't know what this line looks |
| 823 | # like exactly. The only thing we do |
| 824 | # know is that it starts with "\ " |
| 825 | if {![string match {\\ *} $ln]} { |
| 826 | set n [expr $n+1] |
| 827 | set m [expr $m+1] |
| 828 | } |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 829 | set pre_context {} |
| 830 | } elseif {$c1 eq $to_context} { |
| 831 | # turn change line into context line |
| 832 | set ln [$ui_diff get "$i_l + 1 chars" $next_l] |
| 833 | if {$c1 eq {-}} { |
| 834 | set pre_context "$pre_context $ln" |
| 835 | } else { |
| 836 | set patch "$patch $ln" |
| 837 | } |
| 838 | set n [expr $n+1] |
| 839 | set m [expr $m+1] |
| 840 | } else { |
| 841 | # a change in the opposite direction of |
| 842 | # to_context which is outside the range of |
| 843 | # lines to apply. |
| 844 | set patch "$patch$pre_context" |
| 845 | set pre_context {} |
| 846 | } |
| 847 | set i_l $next_l |
| 848 | } |
| 849 | set patch "$patch$pre_context" |
| 850 | set wholepatch "$wholepatch@@ -$hln,$n +$hln,$m @@\n$patch" |
| 851 | set first_l [$ui_diff index "$next_l + 1 lines"] |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 852 | } |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 853 | |
| 854 | if {[catch { |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 855 | set enc [get_path_encoding $current_diff_path] |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 856 | set p [eval git_write $apply_cmd] |
Alexander Gavrilov | 72e6b00 | 2008-09-18 01:07:32 +0400 | [diff] [blame] | 857 | fconfigure $p -translation binary -encoding $enc |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 858 | puts -nonewline $p $current_diff_header |
Jeff Epler | ff07c3b | 2009-12-07 18:22:43 -0600 | [diff] [blame] | 859 | puts -nonewline $p $wholepatch |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 860 | close $p} err]} { |
Vasco Almeida | a3d97af | 2016-05-08 10:52:57 +0000 | [diff] [blame] | 861 | error_popup "$failed_msg\n\n$err" |
Pratyush Yadav | 2ccdfb1 | 2019-08-26 04:23:13 +0530 | [diff] [blame] | 862 | unlock_index |
| 863 | return |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 864 | } |
| 865 | |
Pratyush Yadav | a4fa2f0 | 2019-08-26 01:43:23 +0530 | [diff] [blame] | 866 | if {$revert} { |
| 867 | # Save a copy of this patch for undoing reverts. |
| 868 | set last_revert $current_diff_header$wholepatch |
| 869 | set last_revert_enc $enc |
| 870 | } |
| 871 | |
| 872 | unlock_index |
| 873 | } |
| 874 | |
| 875 | # Undo the last line/hunk reverted. When hunks and lines are reverted, a copy |
| 876 | # of the diff applied is saved. Re-apply that diff to undo the revert. |
| 877 | # |
| 878 | # Right now, we only use a single variable to hold the copy, and not a |
| 879 | # stack/deque for simplicity, so multiple undos are not possible. Maybe this |
| 880 | # can be added if the need for something like this is felt in the future. |
| 881 | proc undo_last_revert {} { |
| 882 | global last_revert current_diff_path current_diff_header |
| 883 | global last_revert_enc |
| 884 | |
| 885 | if {$last_revert eq {}} return |
| 886 | if {![lock_index apply_hunk]} return |
| 887 | |
| 888 | set apply_cmd {apply --whitespace=nowarn} |
| 889 | set failed_msg [mc "Failed to undo last revert."] |
| 890 | |
| 891 | if {[catch { |
| 892 | set enc $last_revert_enc |
| 893 | set p [eval git_write $apply_cmd] |
| 894 | fconfigure $p -translation binary -encoding $enc |
| 895 | puts -nonewline $p $last_revert |
| 896 | close $p} err]} { |
| 897 | error_popup "$failed_msg\n\n$err" |
| 898 | unlock_index |
| 899 | return |
| 900 | } |
| 901 | |
| 902 | set last_revert {} |
| 903 | |
Johannes Sixt | 5821988 | 2008-06-27 09:22:01 +0200 | [diff] [blame] | 904 | unlock_index |
| 905 | } |