]>
Commit | Line | Data |
---|---|---|
cb07fc2a SP |
1 | #!/bin/sh |
2 | # Tcl ignores the next line -*- tcl -*- \ | |
3 | exec wish "$0" -- "$@" | |
4 | ||
5 | # Copyright (C) 2006 Shawn Pearce, Paul Mackerras. All rights reserved. | |
6 | # This program is free software; it may be used, copied, modified | |
7 | # and distributed under the terms of the GNU General Public Licence, | |
8 | # either version 2, or (at your option) any later version. | |
9 | ||
10 | ||
11 | ###################################################################### | |
12 | ## | |
13 | ## status | |
14 | ||
15 | set status_active 0 | |
16 | ||
17 | proc update_status {} { | |
18 | global gitdir HEAD commit_type | |
19 | global ui_index ui_other ui_status_value | |
20 | global status_active file_states | |
21 | ||
22 | if {$status_active > 0} return | |
23 | ||
24 | array unset file_states | |
25 | set ui_status_value {Refreshing file status...} | |
26 | foreach w [list $ui_index $ui_other] { | |
27 | $w conf -state normal | |
28 | $w delete 0.0 end | |
29 | $w conf -state disabled | |
30 | } | |
31 | ||
32 | if {[catch {set HEAD [exec git rev-parse --verify HEAD]}]} { | |
33 | set commit_type initial | |
34 | } else { | |
35 | set commit_type normal | |
36 | } | |
37 | ||
38 | set ls_others [list | git ls-files --others -z \ | |
39 | --exclude-per-directory=.gitignore] | |
40 | set info_exclude [file join $gitdir info exclude] | |
41 | if {[file readable $info_exclude]} { | |
42 | lappend ls_others "--exclude-from=$info_exclude" | |
43 | } | |
44 | ||
45 | set fd_di [open "| git diff-index --cached -z $HEAD" r] | |
46 | set fd_df [open "| git diff-files -z" r] | |
47 | set fd_lo [open $ls_others r] | |
48 | set status_active 3 | |
49 | ||
50 | fconfigure $fd_di -blocking 0 -translation binary | |
51 | fconfigure $fd_df -blocking 0 -translation binary | |
52 | fconfigure $fd_lo -blocking 0 -translation binary | |
53 | fileevent $fd_di readable [list read_diff_index $fd_di] | |
54 | fileevent $fd_df readable [list read_diff_files $fd_df] | |
55 | fileevent $fd_lo readable [list read_ls_others $fd_lo] | |
56 | } | |
57 | ||
58 | proc read_diff_index {fd} { | |
59 | global buf_rdi | |
60 | ||
61 | append buf_rdi [read $fd] | |
62 | set pck [split $buf_rdi "\0"] | |
63 | set buf_rdi [lindex $pck end] | |
64 | foreach {m p} [lrange $pck 0 end-1] { | |
65 | if {$m != {} && $p != {}} { | |
66 | display_file $p [string index $m end]_ | |
67 | } | |
68 | } | |
69 | status_eof $fd buf_rdi | |
70 | } | |
71 | ||
72 | proc read_diff_files {fd} { | |
73 | global buf_rdf | |
74 | ||
75 | append buf_rdf [read $fd] | |
76 | set pck [split $buf_rdf "\0"] | |
77 | set buf_rdf [lindex $pck end] | |
78 | foreach {m p} [lrange $pck 0 end-1] { | |
79 | if {$m != {} && $p != {}} { | |
80 | display_file $p _[string index $m end] | |
81 | } | |
82 | } | |
83 | status_eof $fd buf_rdf | |
84 | } | |
85 | ||
86 | proc read_ls_others {fd} { | |
87 | global buf_rlo | |
88 | ||
89 | append buf_rlo [read $fd] | |
90 | set pck [split $buf_rlo "\0"] | |
91 | set buf_rlo [lindex $pck end] | |
92 | foreach p [lrange $pck 0 end-1] { | |
93 | display_file $p _O | |
94 | } | |
95 | status_eof $fd buf_rlo | |
96 | } | |
97 | ||
98 | proc status_eof {fd buf} { | |
99 | global status_active $buf | |
100 | global ui_fname_value ui_status_value | |
101 | ||
102 | if {[eof $fd]} { | |
103 | set $buf {} | |
104 | close $fd | |
105 | if {[incr status_active -1] == 0} { | |
106 | set ui_status_value {Ready.} | |
107 | if {$ui_fname_value != {}} { | |
108 | show_diff $ui_fname_value | |
109 | } | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | ###################################################################### | |
115 | ## | |
116 | ## diff | |
117 | ||
118 | set diff_active 0 | |
119 | ||
120 | proc clear_diff {} { | |
121 | global ui_diff ui_fname_value ui_fstatus_value | |
122 | ||
123 | $ui_diff conf -state normal | |
124 | $ui_diff delete 0.0 end | |
125 | $ui_diff conf -state disabled | |
126 | set ui_fname_value {} | |
127 | set ui_fstatus_value {} | |
128 | } | |
129 | ||
130 | proc show_diff {path} { | |
131 | global file_states HEAD status_active diff_3way diff_active | |
132 | global ui_diff ui_fname_value ui_fstatus_value ui_status_value | |
133 | ||
134 | if {$status_active > 0} return | |
135 | if {$diff_active} return | |
136 | ||
137 | clear_diff | |
138 | set s $file_states($path) | |
139 | set m [lindex $s 0] | |
140 | set diff_3way 0 | |
141 | set diff_active 1 | |
142 | set ui_fname_value $path | |
143 | set ui_fstatus_value [mapdesc $m $path] | |
144 | set ui_status_value "Loading diff of $path..." | |
145 | ||
146 | set cmd [list | git diff-index -p $HEAD -- $path] | |
147 | switch $m { | |
148 | AM { | |
149 | } | |
150 | MM { | |
151 | set cmd [list | git diff-index -p -c $HEAD $path] | |
152 | } | |
153 | _O { | |
154 | if {[catch { | |
155 | set fd [open $path r] | |
156 | set content [read $fd] | |
157 | close $fd | |
158 | } err ]} { | |
159 | set ui_status_value "Unable to display $path" | |
160 | error_popup "Error loading file:\n$err" | |
161 | return | |
162 | } | |
163 | $ui_diff conf -state normal | |
164 | $ui_diff insert end $content | |
165 | $ui_diff conf -state disabled | |
166 | return | |
167 | } | |
168 | } | |
169 | ||
170 | if {[catch {set fd [open $cmd r]} err]} { | |
171 | set ui_status_value "Unable to display $path" | |
172 | error_popup "Error loading diff:\n$err" | |
173 | return | |
174 | } | |
175 | ||
176 | fconfigure $fd -blocking 0 | |
177 | fileevent $fd readable [list read_diff $fd] | |
178 | } | |
179 | ||
180 | proc read_diff {fd} { | |
181 | global ui_diff ui_status_value diff_3way diff_active | |
182 | ||
183 | while {[gets $fd line] >= 0} { | |
184 | if {[string match index* $line]} { | |
185 | if {[string first , $line] >= 0} { | |
186 | set diff_3way 1 | |
187 | } | |
188 | } | |
189 | ||
190 | $ui_diff conf -state normal | |
191 | if {!$diff_3way} { | |
192 | set x [string index $line 0] | |
193 | switch -- $x { | |
194 | "@" {set tags da} | |
195 | "+" {set tags dp} | |
196 | "-" {set tags dm} | |
197 | default {set tags {}} | |
198 | } | |
199 | } else { | |
200 | set x [string range $line 0 1] | |
201 | switch -- $x { | |
202 | default {set tags {}} | |
203 | "@@" {set tags da} | |
204 | "++" {set tags dp; set x " +"} | |
205 | " +" {set tags {di bold}; set x "++"} | |
206 | "+ " {set tags dni; set x "-+"} | |
207 | "--" {set tags dm; set x " -"} | |
208 | " -" {set tags {dm bold}; set x "--"} | |
209 | "- " {set tags di; set x "+-"} | |
210 | default {set tags {}} | |
211 | } | |
212 | set line [string replace $line 0 1 $x] | |
213 | } | |
214 | $ui_diff insert end $line $tags | |
215 | $ui_diff insert end "\n" | |
216 | $ui_diff conf -state disabled | |
217 | } | |
218 | ||
219 | if {[eof $fd]} { | |
220 | close $fd | |
221 | set diff_active 0 | |
222 | set ui_status_value {Ready.} | |
223 | } | |
224 | } | |
225 | ||
226 | ###################################################################### | |
227 | ## | |
228 | ## ui helpers | |
229 | ||
230 | proc mapcol {state path} { | |
231 | global all_cols | |
232 | ||
233 | if {[catch {set r $all_cols($state)}]} { | |
234 | puts "error: no column for state={$state} $path" | |
235 | return o | |
236 | } | |
237 | return $r | |
238 | } | |
239 | ||
240 | proc mapicon {state path} { | |
241 | global all_icons | |
242 | ||
243 | if {[catch {set r $all_icons($state)}]} { | |
244 | puts "error: no icon for state={$state} $path" | |
245 | return file_plain | |
246 | } | |
247 | return $r | |
248 | } | |
249 | ||
250 | proc mapdesc {state path} { | |
251 | global all_descs | |
252 | ||
253 | if {[catch {set r $all_descs($state)}]} { | |
254 | puts "error: no desc for state={$state} $path" | |
255 | return $state | |
256 | } | |
257 | return $r | |
258 | } | |
259 | ||
260 | proc bsearch {w path} { | |
261 | set hi [expr [lindex [split [$w index end] .] 0] - 2] | |
262 | if {$hi == 0} { | |
263 | return -1 | |
264 | } | |
265 | set lo 0 | |
266 | while {$lo < $hi} { | |
267 | set mi [expr [expr $lo + $hi] / 2] | |
268 | set ti [expr $mi + 1] | |
269 | set cmp [string compare [$w get $ti.1 $ti.end] $path] | |
270 | if {$cmp < 0} { | |
271 | set lo $ti | |
272 | } elseif {$cmp == 0} { | |
273 | return $mi | |
274 | } else { | |
275 | set hi $mi | |
276 | } | |
277 | } | |
278 | return -[expr $lo + 1] | |
279 | } | |
280 | ||
281 | proc merge_state {path state} { | |
282 | global file_states | |
283 | ||
284 | if {[array names file_states -exact $path] == {}} { | |
285 | set o __ | |
286 | set s [list $o none none] | |
287 | } else { | |
288 | set s $file_states($path) | |
289 | set o [lindex $s 0] | |
290 | } | |
291 | ||
292 | set m [lindex $s 0] | |
293 | if {[string index $state 0] == "_"} { | |
294 | set state [string index $m 0][string index $state 1] | |
295 | } elseif {[string index $state 0] == "*"} { | |
296 | set state _[string index $state 1] | |
297 | } | |
298 | ||
299 | if {[string index $state 1] == "_"} { | |
300 | set state [string index $state 0][string index $m 1] | |
301 | } elseif {[string index $state 1] == "*"} { | |
302 | set state [string index $state 0]_ | |
303 | } | |
304 | ||
305 | set file_states($path) [lreplace $s 0 0 $state] | |
306 | return $o | |
307 | } | |
308 | ||
309 | proc display_file {path state} { | |
310 | global ui_index ui_other file_states | |
311 | ||
312 | set old_m [merge_state $path $state] | |
313 | set s $file_states($path) | |
314 | set m [lindex $s 0] | |
315 | ||
316 | if {[mapcol $m $path] == "o"} { | |
317 | set ii 1 | |
318 | set ai 2 | |
319 | set iw $ui_index | |
320 | set aw $ui_other | |
321 | } else { | |
322 | set ii 2 | |
323 | set ai 1 | |
324 | set iw $ui_other | |
325 | set aw $ui_index | |
326 | } | |
327 | ||
328 | set d [lindex $s $ii] | |
329 | if {$d != "none"} { | |
330 | set lno [bsearch $iw $path] | |
331 | if {$lno >= 0} { | |
332 | incr lno | |
333 | $iw conf -state normal | |
334 | $iw delete $lno.0 [expr $lno + 1].0 | |
335 | $iw conf -state disabled | |
336 | set s [lreplace $s $ii $ii none] | |
337 | } | |
338 | } | |
339 | ||
340 | set d [lindex $s $ai] | |
341 | if {$d == "none"} { | |
342 | set lno [expr abs([bsearch $aw $path] + 1) + 1] | |
343 | $aw conf -state normal | |
344 | set ico [$aw image create $lno.0 \ | |
345 | -align center -padx 5 -pady 1 \ | |
346 | -image [mapicon $m $path]] | |
347 | $aw insert $lno.1 "$path\n" | |
348 | $aw conf -state disabled | |
349 | set file_states($path) [lreplace $s $ai $ai [list $ico]] | |
350 | } elseif {[mapicon $m $path] != [mapicon $old_m $path]} { | |
351 | set ico [lindex $d 0] | |
352 | $aw image conf $ico -image [mapicon $m $path] | |
353 | } | |
354 | } | |
355 | ||
356 | proc toggle_mode {path} { | |
357 | global file_states | |
358 | ||
359 | set s $file_states($path) | |
360 | set m [lindex $s 0] | |
361 | ||
362 | switch -- $m { | |
363 | AM - | |
364 | _O { | |
365 | set new A* | |
366 | set cmd [list exec git update-index --add $path] | |
367 | } | |
368 | MM { | |
369 | set new M* | |
370 | set cmd [list exec git update-index $path] | |
371 | } | |
372 | _D { | |
373 | set new D* | |
374 | set cmd [list exec git update-index --remove $path] | |
375 | } | |
376 | default { | |
377 | return | |
378 | } | |
379 | } | |
380 | ||
381 | if {[catch {eval $cmd} err]} { | |
382 | error_popup "Error processing file:\n$err" | |
383 | return | |
384 | } | |
385 | display_file $path $new | |
386 | } | |
387 | ||
388 | ###################################################################### | |
389 | ## | |
390 | ## icons | |
391 | ||
392 | set filemask { | |
393 | #define mask_width 14 | |
394 | #define mask_height 15 | |
395 | static unsigned char mask_bits[] = { | |
396 | 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, | |
397 | 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, | |
398 | 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f}; | |
399 | } | |
400 | ||
401 | image create bitmap file_plain -background white -foreground black -data { | |
402 | #define plain_width 14 | |
403 | #define plain_height 15 | |
404 | static unsigned char plain_bits[] = { | |
405 | 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, | |
406 | 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, | |
407 | 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; | |
408 | } -maskdata $filemask | |
409 | ||
410 | image create bitmap file_mod -background white -foreground blue -data { | |
411 | #define mod_width 14 | |
412 | #define mod_height 15 | |
413 | static unsigned char mod_bits[] = { | |
414 | 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, | |
415 | 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, | |
416 | 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; | |
417 | } -maskdata $filemask | |
418 | ||
419 | image create bitmap file_tick -background white -foreground "#007000" -data { | |
420 | #define file_tick_width 14 | |
421 | #define file_tick_height 15 | |
422 | static unsigned char file_tick_bits[] = { | |
423 | 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16, | |
424 | 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10, | |
425 | 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; | |
426 | } -maskdata $filemask | |
427 | ||
428 | image create bitmap file_parttick -background white -foreground "#005050" -data { | |
429 | #define parttick_width 14 | |
430 | #define parttick_height 15 | |
431 | static unsigned char parttick_bits[] = { | |
432 | 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, | |
433 | 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10, | |
434 | 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f}; | |
435 | } -maskdata $filemask | |
436 | ||
437 | image create bitmap file_question -background white -foreground black -data { | |
438 | #define file_question_width 14 | |
439 | #define file_question_height 15 | |
440 | static unsigned char file_question_bits[] = { | |
441 | 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13, | |
442 | 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10, | |
443 | 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; | |
444 | } -maskdata $filemask | |
445 | ||
446 | image create bitmap file_removed -background white -foreground red -data { | |
447 | #define file_removed_width 14 | |
448 | #define file_removed_height 15 | |
449 | static unsigned char file_removed_bits[] = { | |
450 | 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, | |
451 | 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13, | |
452 | 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f}; | |
453 | } -maskdata $filemask | |
454 | ||
455 | image create bitmap file_merge -background white -foreground blue -data { | |
456 | #define file_merge_width 14 | |
457 | #define file_merge_height 15 | |
458 | static unsigned char file_merge_bits[] = { | |
459 | 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10, | |
460 | 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, | |
461 | 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; | |
462 | } -maskdata $filemask | |
463 | ||
464 | foreach i { | |
465 | {__ i "Unmodified" plain} | |
466 | {_M i "Modified" mod} | |
467 | {M_ i "Checked in" tick} | |
468 | {MM i "Partially checked in" parttick} | |
469 | ||
470 | {_O o "Untracked" plain} | |
471 | {A_ o "Added" tick} | |
472 | {AM o "Partially added" parttick} | |
473 | ||
474 | {_D i "Missing" question} | |
475 | {D_ i "Removed" removed} | |
476 | {DD i "Removed" removed} | |
477 | {DO i "Partially removed" removed} | |
478 | ||
479 | {UM i "Merge conflicts" merge} | |
480 | {U_ i "Merge conflicts" merge} | |
481 | } { | |
482 | set all_cols([lindex $i 0]) [lindex $i 1] | |
483 | set all_descs([lindex $i 0]) [lindex $i 2] | |
484 | set all_icons([lindex $i 0]) file_[lindex $i 3] | |
485 | } | |
486 | unset filemask i | |
487 | ||
488 | ###################################################################### | |
489 | ## | |
490 | ## util | |
491 | ||
492 | proc error_popup {msg} { | |
493 | set w .error | |
494 | toplevel $w | |
495 | wm transient $w . | |
496 | show_msg $w $w $msg | |
497 | } | |
498 | ||
499 | proc show_msg {w top msg} { | |
500 | message $w.m -text $msg -justify center -aspect 400 | |
501 | pack $w.m -side top -fill x -padx 20 -pady 20 | |
502 | button $w.ok -text OK -command "destroy $top" | |
503 | pack $w.ok -side bottom -fill x | |
504 | bind $top <Visibility> "grab $top; focus $top" | |
505 | bind $top <Key-Return> "destroy $top" | |
506 | tkwait window $top | |
507 | } | |
508 | ||
509 | ###################################################################### | |
510 | ## | |
511 | ## ui commands | |
512 | ||
513 | proc do_gitk {} { | |
514 | global tcl_platform | |
515 | ||
516 | if {$tcl_platform(platform) == "windows"} { | |
517 | exec sh -c gitk & | |
518 | } else { | |
519 | exec gitk & | |
520 | } | |
521 | } | |
522 | ||
523 | proc do_quit {} { | |
524 | destroy . | |
525 | } | |
526 | ||
527 | proc do_rescan {} { | |
528 | update_status | |
529 | } | |
530 | ||
531 | # shift == 1: left click | |
532 | # 3: right click | |
533 | proc click {w x y shift wx wy} { | |
534 | set pos [split [$w index @$x,$y] .] | |
535 | set lno [lindex $pos 0] | |
536 | set col [lindex $pos 1] | |
537 | set path [$w get $lno.1 $lno.end] | |
538 | if {$path == {}} return | |
539 | ||
540 | if {$col > 0 && $shift == 1} { | |
541 | show_diff $path | |
542 | } | |
543 | } | |
544 | ||
545 | proc unclick {w x y} { | |
546 | set pos [split [$w index @$x,$y] .] | |
547 | set lno [lindex $pos 0] | |
548 | set col [lindex $pos 1] | |
549 | set path [$w get $lno.1 $lno.end] | |
550 | if {$path == {}} return | |
551 | ||
552 | if {$col == 0} { | |
553 | toggle_mode $path | |
554 | } | |
555 | } | |
556 | ||
557 | ###################################################################### | |
558 | ## | |
559 | ## ui init | |
560 | ||
561 | set mainfont {Helvetica 10} | |
562 | set difffont {Courier 10} | |
563 | set maincursor [. cget -cursor] | |
564 | ||
565 | # -- Menu Bar | |
566 | menu .mbar -tearoff 0 | |
567 | .mbar add cascade -label Project -menu .mbar.project | |
568 | .mbar add cascade -label Commit -menu .mbar.commit | |
569 | .mbar add cascade -label Fetch -menu .mbar.fetch | |
570 | .mbar add cascade -label Pull -menu .mbar.pull | |
571 | . configure -menu .mbar | |
572 | ||
573 | # -- Project Menu | |
574 | menu .mbar.project | |
575 | .mbar.project add command -label Visulize \ | |
576 | -command do_gitk \ | |
577 | -font $mainfont | |
578 | .mbar.project add command -label Quit \ | |
579 | -command do_quit \ | |
580 | -font $mainfont | |
581 | ||
582 | # -- Commit Menu | |
583 | menu .mbar.commit | |
584 | .mbar.commit add command -label Rescan \ | |
585 | -command do_rescan \ | |
586 | -font $mainfont | |
587 | ||
588 | # -- Fetch Menu | |
589 | menu .mbar.fetch | |
590 | ||
591 | # -- Pull Menu | |
592 | menu .mbar.pull | |
593 | ||
594 | # -- Main Window Layout | |
595 | panedwindow .vpane -orient vertical | |
596 | panedwindow .vpane.files -orient horizontal | |
597 | .vpane add .vpane.files -sticky nsew | |
598 | pack .vpane -anchor n -side top -fill both -expand 1 | |
599 | ||
600 | # -- Index File List | |
601 | set ui_index .vpane.files.index.list | |
602 | frame .vpane.files.index -height 100 -width 400 | |
603 | label .vpane.files.index.title -text {Modified Files} \ | |
604 | -background green \ | |
605 | -font $mainfont | |
606 | text $ui_index -background white -borderwidth 0 \ | |
607 | -width 40 -height 10 \ | |
608 | -font $mainfont \ | |
609 | -yscrollcommand {.vpane.files.index.sb set} \ | |
610 | -cursor $maincursor \ | |
611 | -state disabled | |
612 | scrollbar .vpane.files.index.sb -command [list $ui_index yview] | |
613 | pack .vpane.files.index.title -side top -fill x | |
614 | pack .vpane.files.index.sb -side right -fill y | |
615 | pack $ui_index -side left -fill both -expand 1 | |
616 | .vpane.files add .vpane.files.index -sticky nsew | |
617 | ||
618 | # -- Other (Add) File List | |
619 | set ui_other .vpane.files.other.list | |
620 | frame .vpane.files.other -height 100 -width 100 | |
621 | label .vpane.files.other.title -text {Untracked Files} \ | |
622 | -background red \ | |
623 | -font $mainfont | |
624 | text $ui_other -background white -borderwidth 0 \ | |
625 | -width 40 -height 10 \ | |
626 | -font $mainfont \ | |
627 | -yscrollcommand {.vpane.files.other.sb set} \ | |
628 | -cursor $maincursor \ | |
629 | -state disabled | |
630 | scrollbar .vpane.files.other.sb -command [list $ui_other yview] | |
631 | pack .vpane.files.other.title -side top -fill x | |
632 | pack .vpane.files.other.sb -side right -fill y | |
633 | pack $ui_other -side left -fill both -expand 1 | |
634 | .vpane.files add .vpane.files.other -sticky nsew | |
635 | ||
636 | # -- Diff Header | |
637 | set ui_fname_value {} | |
638 | set ui_fstatus_value {} | |
639 | frame .vpane.diff -height 100 -width 100 | |
640 | frame .vpane.diff.header | |
641 | label .vpane.diff.header.l1 -text {File:} -font $mainfont | |
642 | label .vpane.diff.header.l2 -textvariable ui_fname_value \ | |
643 | -anchor w \ | |
644 | -justify left \ | |
645 | -font $mainfont | |
646 | label .vpane.diff.header.l3 -text {Status:} -font $mainfont | |
647 | label .vpane.diff.header.l4 -textvariable ui_fstatus_value \ | |
648 | -width 20 \ | |
649 | -anchor w \ | |
650 | -justify left \ | |
651 | -font $mainfont | |
652 | pack .vpane.diff.header.l1 -side left | |
653 | pack .vpane.diff.header.l2 -side left -fill x | |
654 | pack .vpane.diff.header.l4 -side right | |
655 | pack .vpane.diff.header.l3 -side right | |
656 | ||
657 | # -- Diff Body | |
658 | frame .vpane.diff.body | |
659 | set ui_diff .vpane.diff.body.t | |
660 | text $ui_diff -background white -borderwidth 0 \ | |
661 | -width 40 -height 20 \ | |
662 | -font $difffont \ | |
663 | -xscrollcommand {.vpane.diff.body.sbx set} \ | |
664 | -yscrollcommand {.vpane.diff.body.sby set} \ | |
665 | -cursor $maincursor \ | |
666 | -state disabled | |
667 | scrollbar .vpane.diff.body.sbx -orient horizontal \ | |
668 | -command [list $ui_diff xview] | |
669 | scrollbar .vpane.diff.body.sby -orient vertical \ | |
670 | -command [list $ui_diff yview] | |
671 | pack .vpane.diff.body.sbx -side bottom -fill x | |
672 | pack .vpane.diff.body.sby -side right -fill y | |
673 | pack $ui_diff -side left -fill both -expand 1 | |
674 | pack .vpane.diff.header -side top -fill x | |
675 | pack .vpane.diff.body -side bottom -fill both -expand 1 | |
676 | .vpane add .vpane.diff -stick nsew | |
677 | ||
678 | $ui_diff tag conf dm -foreground red | |
679 | $ui_diff tag conf dp -foreground blue | |
680 | $ui_diff tag conf da -font [concat $difffont bold] | |
681 | $ui_diff tag conf di -foreground "#00a000" | |
682 | $ui_diff tag conf dni -foreground "#a000a0" | |
683 | $ui_diff tag conf bold -font [concat $difffont bold] | |
684 | ||
685 | # -- Commit Area | |
686 | frame .vpane.commarea -height 50 | |
687 | .vpane add .vpane.commarea -stick nsew | |
688 | ||
689 | # -- Commit Area Buttons | |
690 | frame .vpane.commarea.buttons | |
691 | label .vpane.commarea.buttons.l -text {} \ | |
692 | -anchor w \ | |
693 | -justify left \ | |
694 | -font $mainfont | |
695 | pack .vpane.commarea.buttons.l -side top -fill x | |
696 | button .vpane.commarea.buttons.rescan -text {Rescan} \ | |
697 | -command do_rescan \ | |
698 | -font $mainfont | |
699 | pack .vpane.commarea.buttons.rescan -side top -fill x | |
700 | button .vpane.commarea.buttons.ciall -text {Check-in All} \ | |
701 | -command do_checkin_all \ | |
702 | -font $mainfont | |
703 | pack .vpane.commarea.buttons.ciall -side top -fill x | |
704 | button .vpane.commarea.buttons.commit -text {Commit} \ | |
705 | -command do_commit \ | |
706 | -font $mainfont | |
707 | pack .vpane.commarea.buttons.commit -side top -fill x | |
708 | pack .vpane.commarea.buttons -side left -fill y | |
709 | ||
710 | # -- Commit Message Buffer | |
711 | frame .vpane.commarea.buffer | |
712 | set ui_comm .vpane.commarea.buffer.t | |
713 | label .vpane.commarea.buffer.l -text {Commit Message:} \ | |
714 | -anchor w \ | |
715 | -justify left \ | |
716 | -font $mainfont | |
717 | text $ui_comm -background white -borderwidth 1 \ | |
718 | -relief sunken \ | |
719 | -width 75 -height 10 -wrap none \ | |
720 | -font $difffont \ | |
721 | -yscrollcommand {.vpane.commarea.buffer.sby set} \ | |
722 | -cursor $maincursor | |
723 | scrollbar .vpane.commarea.buffer.sby -command [list $ui_comm yview] | |
724 | pack .vpane.commarea.buffer.l -side top -fill x | |
725 | pack .vpane.commarea.buffer.sby -side right -fill y | |
726 | pack $ui_comm -side left -fill y | |
727 | pack .vpane.commarea.buffer -side left -fill y | |
728 | ||
729 | # -- Status Bar | |
730 | set ui_status_value {Initializing...} | |
731 | label .status -textvariable ui_status_value \ | |
732 | -anchor w \ | |
733 | -justify left \ | |
734 | -borderwidth 1 \ | |
735 | -relief sunken \ | |
736 | -font $mainfont | |
737 | pack .status -anchor w -side bottom -fill x | |
738 | ||
739 | # -- Key Bindings | |
740 | bind . <Destroy> do_quit | |
741 | bind . <Key-F5> do_rescan | |
742 | bind . <M1-Key-r> do_rescan | |
743 | bind . <M1-Key-R> do_rescan | |
744 | bind . <M1-Key-q> do_quit | |
745 | bind . <M1-Key-Q> do_quit | |
746 | foreach i [list $ui_index $ui_other] { | |
747 | bind $i <Button-1> {click %W %x %y 1 %X %Y; break} | |
748 | bind $i <Button-3> {click %W %x %y 3 %X %Y; break} | |
749 | bind $i <ButtonRelease-1> {unclick %W %x %y; break} | |
750 | } | |
751 | unset i | |
752 | ||
753 | ###################################################################### | |
754 | ## | |
755 | ## main | |
756 | ||
757 | if {[catch {set gitdir [exec git rev-parse --git-dir]} err]} { | |
758 | show_msg {} . "Cannot find the git directory: $err" | |
759 | exit 1 | |
760 | } | |
761 | ||
762 | wm title . "git-ui ([file normalize [file dirname $gitdir]])" | |
763 | focus -force $ui_comm | |
764 | update_status |