git-gui: Narrow the no differences information message.
[git/git.git] / git-gui
CommitLineData
cb07fc2a
SP
1#!/bin/sh
2# Tcl ignores the next line -*- tcl -*- \
3exec 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
da5239dc
SP
10set appname [lindex [file split $argv0] end]
11set gitdir {}
12
2d19516d
SP
13######################################################################
14##
15## config
16
51f4d16b
SP
17proc is_many_config {name} {
18 switch -glob -- $name {
19 remote.*.fetch -
20 remote.*.push
21 {return 1}
22 *
23 {return 0}
24 }
25}
2d19516d 26
6bbd1cb9 27proc load_config {include_global} {
51f4d16b
SP
28 global repo_config global_config default_config
29
30 array unset global_config
6bbd1cb9
SP
31 if {$include_global} {
32 catch {
33 set fd_rc [open "| git repo-config --global --list" r]
34 while {[gets $fd_rc line] >= 0} {
35 if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
36 if {[is_many_config $name]} {
37 lappend global_config($name) $value
38 } else {
39 set global_config($name) $value
40 }
51f4d16b
SP
41 }
42 }
6bbd1cb9 43 close $fd_rc
51f4d16b 44 }
51f4d16b 45 }
6bbd1cb9
SP
46
47 array unset repo_config
2d19516d
SP
48 catch {
49 set fd_rc [open "| git repo-config --list" r]
50 while {[gets $fd_rc line] >= 0} {
51 if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
51f4d16b
SP
52 if {[is_many_config $name]} {
53 lappend repo_config($name) $value
54 } else {
55 set repo_config($name) $value
56 }
2d19516d
SP
57 }
58 }
59 close $fd_rc
60 }
61
51f4d16b
SP
62 foreach name [array names default_config] {
63 if {[catch {set v $global_config($name)}]} {
64 set global_config($name) $default_config($name)
65 }
66 if {[catch {set v $repo_config($name)}]} {
67 set repo_config($name) $default_config($name)
68 }
2d19516d
SP
69 }
70}
71
51f4d16b 72proc save_config {} {
92148d80
SP
73 global default_config font_descs
74 global repo_config global_config
51f4d16b 75 global repo_config_new global_config_new
2d19516d 76
92148d80
SP
77 foreach option $font_descs {
78 set name [lindex $option 0]
79 set font [lindex $option 1]
80 font configure $font \
81 -family $global_config_new(gui.$font^^family) \
82 -size $global_config_new(gui.$font^^size)
83 font configure ${font}bold \
84 -family $global_config_new(gui.$font^^family) \
85 -size $global_config_new(gui.$font^^size)
86 set global_config_new(gui.$name) [font configure $font]
87 unset global_config_new(gui.$font^^family)
88 unset global_config_new(gui.$font^^size)
89 }
90
91 foreach name [array names default_config] {
51f4d16b 92 set value $global_config_new($name)
043f7011
SP
93 if {$value ne $global_config($name)} {
94 if {$value eq $default_config($name)} {
51f4d16b
SP
95 catch {exec git repo-config --global --unset $name}
96 } else {
7b64d0b7
SP
97 regsub -all "\[{}\]" $value {"} value
98 exec git repo-config --global $name $value
51f4d16b
SP
99 }
100 set global_config($name) $value
043f7011 101 if {$value eq $repo_config($name)} {
51f4d16b
SP
102 catch {exec git repo-config --unset $name}
103 set repo_config($name) $value
104 }
105 }
2d19516d
SP
106 }
107
92148d80 108 foreach name [array names default_config] {
51f4d16b 109 set value $repo_config_new($name)
043f7011
SP
110 if {$value ne $repo_config($name)} {
111 if {$value eq $global_config($name)} {
51f4d16b
SP
112 catch {exec git repo-config --unset $name}
113 } else {
7b64d0b7
SP
114 regsub -all "\[{}\]" $value {"} value
115 exec git repo-config $name $value
51f4d16b
SP
116 }
117 set repo_config($name) $value
118 }
2d19516d
SP
119 }
120}
121
da5239dc
SP
122proc error_popup {msg} {
123 global gitdir appname
124
125 set title $appname
043f7011 126 if {$gitdir ne {}} {
da5239dc
SP
127 append title { (}
128 append title [lindex \
129 [file split [file normalize [file dirname $gitdir]]] \
130 end]
131 append title {)}
132 }
44be340e
SP
133 tk_messageBox \
134 -parent . \
da5239dc
SP
135 -icon error \
136 -type ok \
137 -title "$title: error" \
138 -message $msg
139}
140
16403d0b
SP
141proc info_popup {msg} {
142 global gitdir appname
143
144 set title $appname
043f7011 145 if {$gitdir ne {}} {
16403d0b
SP
146 append title { (}
147 append title [lindex \
148 [file split [file normalize [file dirname $gitdir]]] \
149 end]
150 append title {)}
151 }
152 tk_messageBox \
153 -parent . \
154 -icon error \
155 -type ok \
156 -title $title \
157 -message $msg
158}
159
2d19516d
SP
160######################################################################
161##
162## repository setup
163
44be340e
SP
164if { [catch {set cdup [exec git rev-parse --show-cdup]} err]
165 || [catch {set gitdir [exec git rev-parse --git-dir]} err]} {
166 catch {wm withdraw .}
167 error_popup "Cannot find the git directory:\n\n$err"
2d19516d
SP
168 exit 1
169}
043f7011 170if {$cdup ne ""} {
2d19516d
SP
171 cd $cdup
172}
173unset cdup
174
4ccdab02 175set single_commit 0
043f7011 176if {$appname eq {git-citool}} {
2d19516d
SP
177 set single_commit 1
178}
179
cb07fc2a
SP
180######################################################################
181##
e210e674 182## task management
cb07fc2a
SP
183
184set status_active 0
131f503b 185set diff_active 0
131f503b 186
e210e674
SP
187set disable_on_lock [list]
188set index_lock_type none
189
e57ca85e
SP
190set HEAD {}
191set PARENT {}
192set commit_type {}
193
e210e674
SP
194proc lock_index {type} {
195 global index_lock_type disable_on_lock
131f503b 196
043f7011 197 if {$index_lock_type eq {none}} {
e210e674
SP
198 set index_lock_type $type
199 foreach w $disable_on_lock {
200 uplevel #0 $w disabled
201 }
202 return 1
043f7011 203 } elseif {$index_lock_type eq {begin-update} && $type eq {update}} {
e210e674 204 set index_lock_type $type
131f503b
SP
205 return 1
206 }
207 return 0
208}
cb07fc2a 209
e210e674
SP
210proc unlock_index {} {
211 global index_lock_type disable_on_lock
212
213 set index_lock_type none
214 foreach w $disable_on_lock {
215 uplevel #0 $w normal
216 }
217}
218
219######################################################################
220##
221## status
222
ec6b424a
SP
223proc repository_state {hdvar ctvar} {
224 global gitdir
225 upvar $hdvar hd $ctvar ct
226
227 if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
228 set ct initial
229 } elseif {[file exists [file join $gitdir MERGE_HEAD]]} {
230 set ct merge
231 } else {
232 set ct normal
233 }
234}
235
e57ca85e
SP
236proc update_status {{final Ready.}} {
237 global HEAD PARENT commit_type
131f503b 238 global ui_index ui_other ui_status_value ui_comm
7f1df79b 239 global status_active file_states
51f4d16b 240 global repo_config
cb07fc2a 241
e210e674 242 if {$status_active || ![lock_index read]} return
cb07fc2a 243
e57ca85e 244 repository_state new_HEAD new_type
043f7011
SP
245 if {$commit_type eq {amend}
246 && $new_type eq {normal}
247 && $new_HEAD eq $HEAD} {
e57ca85e
SP
248 } else {
249 set HEAD $new_HEAD
250 set PARENT $new_HEAD
251 set commit_type $new_type
252 }
253
cb07fc2a 254 array unset file_states
cb07fc2a 255
131f503b 256 if {![$ui_comm edit modified]
043f7011 257 || [string trim [$ui_comm get 0.0 end]] eq {}} {
131f503b
SP
258 if {[load_message GITGUI_MSG]} {
259 } elseif {[load_message MERGE_MSG]} {
260 } elseif {[load_message SQUASH_MSG]} {
261 }
262 $ui_comm edit modified false
b2c6fcf1 263 $ui_comm edit reset
131f503b
SP
264 }
265
043f7011 266 if {$repo_config(gui.trustmtime) eq {true}} {
e534f3a8
SP
267 update_status_stage2 {} $final
268 } else {
269 set status_active 1
270 set ui_status_value {Refreshing file status...}
16403d0b
SP
271 set cmd [list git update-index]
272 lappend cmd -q
273 lappend cmd --unmerged
274 lappend cmd --ignore-missing
275 lappend cmd --refresh
276 set fd_rf [open "| $cmd" r]
e534f3a8 277 fconfigure $fd_rf -blocking 0 -translation binary
390adaea
SP
278 fileevent $fd_rf readable \
279 [list update_status_stage2 $fd_rf $final]
e534f3a8 280 }
131f503b
SP
281}
282
e534f3a8 283proc update_status_stage2 {fd final} {
e57ca85e 284 global gitdir PARENT commit_type
131f503b 285 global ui_index ui_other ui_status_value ui_comm
03e4ec53 286 global status_active
868c8752 287 global buf_rdi buf_rdf buf_rlo
131f503b 288
043f7011 289 if {$fd ne {}} {
e534f3a8
SP
290 read $fd
291 if {![eof $fd]} return
292 close $fd
293 }
131f503b 294
cb07fc2a
SP
295 set ls_others [list | git ls-files --others -z \
296 --exclude-per-directory=.gitignore]
297 set info_exclude [file join $gitdir info exclude]
298 if {[file readable $info_exclude]} {
299 lappend ls_others "--exclude-from=$info_exclude"
300 }
301
868c8752
SP
302 set buf_rdi {}
303 set buf_rdf {}
304 set buf_rlo {}
305
131f503b
SP
306 set status_active 3
307 set ui_status_value {Scanning for modified files ...}
e57ca85e 308 set fd_di [open "| git diff-index --cached -z $PARENT" r]
cb07fc2a
SP
309 set fd_df [open "| git diff-files -z" r]
310 set fd_lo [open $ls_others r]
cb07fc2a
SP
311
312 fconfigure $fd_di -blocking 0 -translation binary
313 fconfigure $fd_df -blocking 0 -translation binary
314 fconfigure $fd_lo -blocking 0 -translation binary
e57ca85e
SP
315 fileevent $fd_di readable [list read_diff_index $fd_di $final]
316 fileevent $fd_df readable [list read_diff_files $fd_df $final]
317 fileevent $fd_lo readable [list read_ls_others $fd_lo $final]
cb07fc2a
SP
318}
319
131f503b
SP
320proc load_message {file} {
321 global gitdir ui_comm
322
323 set f [file join $gitdir $file]
e57ca85e 324 if {[file isfile $f]} {
131f503b
SP
325 if {[catch {set fd [open $f r]}]} {
326 return 0
327 }
e57ca85e 328 set content [string trim [read $fd]]
131f503b
SP
329 close $fd
330 $ui_comm delete 0.0 end
331 $ui_comm insert end $content
332 return 1
333 }
334 return 0
335}
336
e57ca85e 337proc read_diff_index {fd final} {
cb07fc2a
SP
338 global buf_rdi
339
340 append buf_rdi [read $fd]
868c8752
SP
341 set c 0
342 set n [string length $buf_rdi]
343 while {$c < $n} {
344 set z1 [string first "\0" $buf_rdi $c]
345 if {$z1 == -1} break
346 incr z1
347 set z2 [string first "\0" $buf_rdi $z1]
348 if {$z2 == -1} break
349
350 set c $z2
351 incr z2 -1
352 display_file \
353 [string range $buf_rdi $z1 $z2] \
354 [string index $buf_rdi [expr $z1 - 2]]_
355 incr c
cb07fc2a 356 }
868c8752
SP
357 if {$c < $n} {
358 set buf_rdi [string range $buf_rdi $c end]
359 } else {
360 set buf_rdi {}
361 }
362
e57ca85e 363 status_eof $fd buf_rdi $final
cb07fc2a
SP
364}
365
e57ca85e 366proc read_diff_files {fd final} {
cb07fc2a
SP
367 global buf_rdf
368
369 append buf_rdf [read $fd]
868c8752
SP
370 set c 0
371 set n [string length $buf_rdf]
372 while {$c < $n} {
373 set z1 [string first "\0" $buf_rdf $c]
374 if {$z1 == -1} break
375 incr z1
376 set z2 [string first "\0" $buf_rdf $z1]
377 if {$z2 == -1} break
378
379 set c $z2
380 incr z2 -1
381 display_file \
382 [string range $buf_rdf $z1 $z2] \
383 _[string index $buf_rdf [expr $z1 - 2]]
384 incr c
385 }
386 if {$c < $n} {
387 set buf_rdf [string range $buf_rdf $c end]
388 } else {
389 set buf_rdf {}
cb07fc2a 390 }
868c8752 391
e57ca85e 392 status_eof $fd buf_rdf $final
cb07fc2a
SP
393}
394
e57ca85e 395proc read_ls_others {fd final} {
cb07fc2a
SP
396 global buf_rlo
397
398 append buf_rlo [read $fd]
399 set pck [split $buf_rlo "\0"]
400 set buf_rlo [lindex $pck end]
401 foreach p [lrange $pck 0 end-1] {
402 display_file $p _O
403 }
e57ca85e 404 status_eof $fd buf_rlo $final
cb07fc2a
SP
405}
406
e57ca85e 407proc status_eof {fd buf final} {
7f1df79b 408 global status_active ui_status_value
f7f8d322 409 global file_states repo_config
7f1df79b 410 upvar $buf to_clear
cb07fc2a 411
f7f8d322
SP
412 if {![eof $fd]} return
413 set to_clear {}
414 close $fd
415 if {[incr status_active -1] > 0} return
93f654df 416
f7f8d322
SP
417 unlock_index
418 display_all_files
419
420 if {$repo_config(gui.partialinclude) ne {true}} {
421 set pathList [list]
422 foreach path [array names file_states] {
423 switch -- [lindex $file_states($path) 0] {
424 AM -
425 MM {lappend pathList $path}
426 }
427 }
428 if {$pathList ne {}} {
429 update_index $pathList
430 return
cb07fc2a
SP
431 }
432 }
f7f8d322
SP
433
434 reshow_diff
435 set ui_status_value $final
cb07fc2a
SP
436}
437
438######################################################################
439##
440## diff
441
cb07fc2a 442proc clear_diff {} {
03e4ec53 443 global ui_diff ui_fname_value ui_fstatus_value ui_index ui_other
cb07fc2a
SP
444
445 $ui_diff conf -state normal
446 $ui_diff delete 0.0 end
447 $ui_diff conf -state disabled
03e4ec53 448
cb07fc2a
SP
449 set ui_fname_value {}
450 set ui_fstatus_value {}
03e4ec53
SP
451
452 $ui_index tag remove in_diff 0.0 end
453 $ui_other tag remove in_diff 0.0 end
cb07fc2a
SP
454}
455
7f1df79b
SP
456proc reshow_diff {} {
457 global ui_fname_value ui_status_value file_states
458
043f7011 459 if {$ui_fname_value eq {}
73ad179b 460 || [catch {set s $file_states($ui_fname_value)}]} {
7f1df79b 461 clear_diff
73ad179b
SP
462 } else {
463 show_diff $ui_fname_value
7f1df79b
SP
464 }
465}
466
16403d0b
SP
467proc handle_empty_diff {} {
468 global ui_fname_value file_states file_lists
469
470 set path $ui_fname_value
471 set s $file_states($path)
043f7011 472 if {[lindex $s 0] ne {_M}} return
16403d0b
SP
473
474 info_popup "No differences detected.
475
476[short_path $path] has no changes.
477
a37eee44
SP
478The modification date of this file was updated
479by another application and you currently have
480the Trust File Modification Timestamps option
481enabled, so Git did not automatically detect
482that there are no content differences in this
483file.
484
485This file will now be removed from the modified
486files list, to prevent possible confusion.
16403d0b
SP
487"
488 if {[catch {exec git update-index -- $path} err]} {
489 error_popup "Failed to refresh index:\n\n$err"
490 }
491
492 clear_diff
493 set old_w [mapcol [lindex $file_states($path) 0] $path]
494 set lno [lsearch -sorted $file_lists($old_w) $path]
495 if {$lno >= 0} {
496 set file_lists($old_w) \
497 [lreplace $file_lists($old_w) $lno $lno]
498 incr lno
499 $old_w conf -state normal
500 $old_w delete $lno.0 [expr $lno + 1].0
501 $old_w conf -state disabled
502 }
503}
504
03e4ec53
SP
505proc show_diff {path {w {}} {lno {}}} {
506 global file_states file_lists
fd2656fd 507 global PARENT diff_3way diff_active repo_config
cb07fc2a
SP
508 global ui_diff ui_fname_value ui_fstatus_value ui_status_value
509
e210e674 510 if {$diff_active || ![lock_index read]} return
cb07fc2a
SP
511
512 clear_diff
043f7011 513 if {$w eq {} || $lno == {}} {
03e4ec53
SP
514 foreach w [array names file_lists] {
515 set lno [lsearch -sorted $file_lists($w) $path]
516 if {$lno >= 0} {
517 incr lno
518 break
519 }
520 }
521 }
043f7011 522 if {$w ne {} && $lno >= 1} {
03e4ec53
SP
523 $w tag add in_diff $lno.0 [expr $lno + 1].0
524 }
525
cb07fc2a
SP
526 set s $file_states($path)
527 set m [lindex $s 0]
528 set diff_3way 0
529 set diff_active 1
c11b5f20 530 set ui_fname_value $path
cb07fc2a 531 set ui_fstatus_value [mapdesc $m $path]
68e009de 532 set ui_status_value "Loading diff of [escape_path $path]..."
cb07fc2a 533
fd2656fd
SP
534 set cmd [list | git diff-index]
535 lappend cmd --no-color
358d8de8
SP
536 if {$repo_config(gui.diffcontext) > 0} {
537 lappend cmd "-U$repo_config(gui.diffcontext)"
538 }
fd2656fd
SP
539 lappend cmd -p
540
cb07fc2a 541 switch $m {
cb07fc2a 542 MM {
fd2656fd 543 lappend cmd -c
cb07fc2a
SP
544 }
545 _O {
546 if {[catch {
547 set fd [open $path r]
548 set content [read $fd]
549 close $fd
550 } err ]} {
131f503b 551 set diff_active 0
e210e674 552 unlock_index
68e009de 553 set ui_status_value "Unable to display [escape_path $path]"
44be340e 554 error_popup "Error loading file:\n\n$err"
cb07fc2a
SP
555 return
556 }
557 $ui_diff conf -state normal
558 $ui_diff insert end $content
559 $ui_diff conf -state disabled
bd1e2b40
SP
560 set diff_active 0
561 unlock_index
562 set ui_status_value {Ready.}
cb07fc2a
SP
563 return
564 }
565 }
566
fd2656fd
SP
567 lappend cmd $PARENT
568 lappend cmd --
569 lappend cmd $path
570
cb07fc2a 571 if {[catch {set fd [open $cmd r]} err]} {
131f503b 572 set diff_active 0
e210e674 573 unlock_index
68e009de 574 set ui_status_value "Unable to display [escape_path $path]"
44be340e 575 error_popup "Error loading diff:\n\n$err"
cb07fc2a
SP
576 return
577 }
578
6f6eed28 579 fconfigure $fd -blocking 0 -translation auto
cb07fc2a
SP
580 fileevent $fd readable [list read_diff $fd]
581}
582
583proc read_diff {fd} {
584 global ui_diff ui_status_value diff_3way diff_active
51f4d16b 585 global repo_config
cb07fc2a
SP
586
587 while {[gets $fd line] >= 0} {
6f6eed28
SP
588 if {[string match {diff --git *} $line]} continue
589 if {[string match {diff --combined *} $line]} continue
590 if {[string match {--- *} $line]} continue
591 if {[string match {+++ *} $line]} continue
cb07fc2a
SP
592 if {[string match index* $line]} {
593 if {[string first , $line] >= 0} {
594 set diff_3way 1
595 }
596 }
597
598 $ui_diff conf -state normal
599 if {!$diff_3way} {
600 set x [string index $line 0]
601 switch -- $x {
602 "@" {set tags da}
603 "+" {set tags dp}
604 "-" {set tags dm}
605 default {set tags {}}
606 }
607 } else {
608 set x [string range $line 0 1]
609 switch -- $x {
610 default {set tags {}}
611 "@@" {set tags da}
612 "++" {set tags dp; set x " +"}
613 " +" {set tags {di bold}; set x "++"}
614 "+ " {set tags dni; set x "-+"}
615 "--" {set tags dm; set x " -"}
616 " -" {set tags {dm bold}; set x "--"}
617 "- " {set tags di; set x "+-"}
618 default {set tags {}}
619 }
620 set line [string replace $line 0 1 $x]
621 }
622 $ui_diff insert end $line $tags
623 $ui_diff insert end "\n"
624 $ui_diff conf -state disabled
625 }
626
627 if {[eof $fd]} {
628 close $fd
629 set diff_active 0
e210e674 630 unlock_index
cb07fc2a 631 set ui_status_value {Ready.}
16403d0b 632
043f7011
SP
633 if {$repo_config(gui.trustmtime) eq {true}
634 && [$ui_diff index end] eq {2.0}} {
16403d0b
SP
635 handle_empty_diff
636 }
cb07fc2a
SP
637 }
638}
639
ec6b424a
SP
640######################################################################
641##
642## commit
643
e57ca85e
SP
644proc load_last_commit {} {
645 global HEAD PARENT commit_type ui_comm
646
043f7011
SP
647 if {$commit_type eq {amend}} return
648 if {$commit_type ne {normal}} {
e57ca85e
SP
649 error_popup "Can't amend a $commit_type commit."
650 return
651 }
652
653 set msg {}
654 set parent {}
655 set parent_count 0
656 if {[catch {
657 set fd [open "| git cat-file commit $HEAD" r]
658 while {[gets $fd line] > 0} {
659 if {[string match {parent *} $line]} {
660 set parent [string range $line 7 end]
661 incr parent_count
662 }
663 }
664 set msg [string trim [read $fd]]
665 close $fd
666 } err]} {
44be340e 667 error_popup "Error loading commit data for amend:\n\n$err"
e57ca85e
SP
668 return
669 }
670
671 if {$parent_count == 0} {
672 set commit_type amend
673 set HEAD {}
674 set PARENT {}
675 update_status
676 } elseif {$parent_count == 1} {
677 set commit_type amend
678 set PARENT $parent
679 $ui_comm delete 0.0 end
680 $ui_comm insert end $msg
681 $ui_comm edit modified false
b2c6fcf1 682 $ui_comm edit reset
e57ca85e
SP
683 update_status
684 } else {
685 error_popup {You can't amend a merge commit.}
686 return
687 }
688}
689
ec6b424a
SP
690proc commit_tree {} {
691 global tcl_platform HEAD gitdir commit_type file_states
333b0c74 692 global pch_error
4658b56f 693 global ui_status_value ui_comm
ec6b424a 694
333b0c74 695 if {![lock_index update]} return
ec6b424a
SP
696
697 # -- Our in memory state should match the repository.
698 #
699 repository_state curHEAD cur_type
043f7011
SP
700 if {$commit_type eq {amend}
701 && $cur_type eq {normal}
702 && $curHEAD eq $HEAD} {
703 } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
ec6b424a
SP
704 error_popup {Last scanned state does not match repository state.
705
706Its highly likely that another Git program modified the
707repository since our last scan. A rescan is required
708before committing.
709}
710 unlock_index
711 update_status
712 return
713 }
714
715 # -- At least one file should differ in the index.
716 #
717 set files_ready 0
718 foreach path [array names file_states] {
719 set s $file_states($path)
720 switch -glob -- [lindex $s 0] {
7f1df79b
SP
721 _? {continue}
722 A? -
723 D? -
724 M? {set files_ready 1; break}
725 U? {
ec6b424a
SP
726 error_popup "Unmerged files cannot be committed.
727
16403d0b 728File [short_path $path] has merge conflicts.
7fe7e733 729You must resolve them and include the file before committing.
ec6b424a
SP
730"
731 unlock_index
732 return
733 }
734 default {
735 error_popup "Unknown file state [lindex $s 0] detected.
736
16403d0b 737File [short_path $path] cannot be committed by this program.
ec6b424a
SP
738"
739 }
740 }
741 }
742 if {!$files_ready} {
7fe7e733 743 error_popup {No included files to commit.
ec6b424a 744
7fe7e733 745You must include at least 1 file before you can commit.
ec6b424a
SP
746}
747 unlock_index
748 return
749 }
750
751 # -- A message is required.
752 #
753 set msg [string trim [$ui_comm get 1.0 end]]
043f7011 754 if {$msg eq {}} {
ec6b424a
SP
755 error_popup {Please supply a commit message.
756
757A good commit message has the following format:
758
759- First line: Describe in one sentance what you did.
760- Second line: Blank
761- Remaining lines: Describe why this change is good.
762}
763 unlock_index
764 return
765 }
766
767 # -- Ask the pre-commit hook for the go-ahead.
768 #
769 set pchook [file join $gitdir hooks pre-commit]
043f7011 770 if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
4658b56f
SP
771 set pchook [list sh -c [concat \
772 "if test -x \"$pchook\";" \
773 "then exec \"$pchook\" 2>&1;" \
774 "fi"]]
ec6b424a 775 } elseif {[file executable $pchook]} {
4658b56f 776 set pchook [list $pchook |& cat]
ec6b424a
SP
777 } else {
778 set pchook {}
779 }
043f7011 780 if {$pchook ne {}} {
4658b56f
SP
781 set ui_status_value {Calling pre-commit hook...}
782 set pch_error {}
783 set fd_ph [open "| $pchook" r]
784 fconfigure $fd_ph -blocking 0 -translation binary
785 fileevent $fd_ph readable \
786 [list commit_stage1 $fd_ph $curHEAD $msg]
787 } else {
788 commit_stage2 $curHEAD $msg
789 }
790}
791
792proc commit_stage1 {fd_ph curHEAD msg} {
333b0c74 793 global pch_error ui_status_value
4658b56f
SP
794
795 append pch_error [read $fd_ph]
796 fconfigure $fd_ph -blocking 1
797 if {[eof $fd_ph]} {
798 if {[catch {close $fd_ph}]} {
799 set ui_status_value {Commit declined by pre-commit hook.}
800 hook_failed_popup pre-commit $pch_error
801 unlock_index
333b0c74
SP
802 } else {
803 commit_stage2 $curHEAD $msg
4658b56f 804 }
333b0c74
SP
805 set pch_error {}
806 } else {
807 fconfigure $fd_ph -blocking 0
ec6b424a 808 }
4658b56f
SP
809}
810
811proc commit_stage2 {curHEAD msg} {
812 global ui_status_value
ec6b424a
SP
813
814 # -- Write the tree in the background.
815 #
ec6b424a 816 set ui_status_value {Committing changes...}
ec6b424a 817 set fd_wt [open "| git write-tree" r]
4658b56f 818 fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg]
ec6b424a
SP
819}
820
4658b56f 821proc commit_stage3 {fd_wt curHEAD msg} {
c8ebafd8 822 global single_commit gitdir HEAD PARENT commit_type tcl_platform
333b0c74 823 global ui_status_value ui_comm
7f1df79b 824 global file_states
ec6b424a
SP
825
826 gets $fd_wt tree_id
043f7011 827 if {$tree_id eq {} || [catch {close $fd_wt} err]} {
44be340e 828 error_popup "write-tree failed:\n\n$err"
ec6b424a
SP
829 set ui_status_value {Commit failed.}
830 unlock_index
831 return
832 }
833
834 # -- Create the commit.
835 #
836 set cmd [list git commit-tree $tree_id]
043f7011 837 if {$PARENT ne {}} {
e57ca85e 838 lappend cmd -p $PARENT
ec6b424a 839 }
043f7011 840 if {$commit_type eq {merge}} {
ec6b424a
SP
841 if {[catch {
842 set fd_mh [open [file join $gitdir MERGE_HEAD] r]
bd1e2b40
SP
843 while {[gets $fd_mh merge_head] >= 0} {
844 lappend cmd -p $merge_head
ec6b424a
SP
845 }
846 close $fd_mh
847 } err]} {
44be340e 848 error_popup "Loading MERGE_HEAD failed:\n\n$err"
ec6b424a
SP
849 set ui_status_value {Commit failed.}
850 unlock_index
851 return
852 }
853 }
043f7011 854 if {$PARENT eq {}} {
ec6b424a
SP
855 # git commit-tree writes to stderr during initial commit.
856 lappend cmd 2>/dev/null
857 }
858 lappend cmd << $msg
859 if {[catch {set cmt_id [eval exec $cmd]} err]} {
44be340e 860 error_popup "commit-tree failed:\n\n$err"
ec6b424a
SP
861 set ui_status_value {Commit failed.}
862 unlock_index
863 return
864 }
865
866 # -- Update the HEAD ref.
867 #
868 set reflogm commit
043f7011 869 if {$commit_type ne {normal}} {
ec6b424a
SP
870 append reflogm " ($commit_type)"
871 }
872 set i [string first "\n" $msg]
873 if {$i >= 0} {
874 append reflogm {: } [string range $msg 0 [expr $i - 1]]
875 } else {
876 append reflogm {: } $msg
877 }
e57ca85e 878 set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD]
ec6b424a 879 if {[catch {eval exec $cmd} err]} {
44be340e 880 error_popup "update-ref failed:\n\n$err"
ec6b424a
SP
881 set ui_status_value {Commit failed.}
882 unlock_index
883 return
884 }
885
886 # -- Cleanup after ourselves.
887 #
888 catch {file delete [file join $gitdir MERGE_HEAD]}
889 catch {file delete [file join $gitdir MERGE_MSG]}
890 catch {file delete [file join $gitdir SQUASH_MSG]}
891 catch {file delete [file join $gitdir GITGUI_MSG]}
892
893 # -- Let rerere do its thing.
894 #
895 if {[file isdirectory [file join $gitdir rr-cache]]} {
896 catch {exec git rerere}
897 }
898
c8ebafd8
SP
899 # -- Run the post-commit hook.
900 #
901 set pchook [file join $gitdir hooks post-commit]
043f7011 902 if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
c8ebafd8
SP
903 set pchook [list sh -c [concat \
904 "if test -x \"$pchook\";" \
905 "then exec \"$pchook\";" \
906 "fi"]]
907 } elseif {![file executable $pchook]} {
908 set pchook {}
909 }
043f7011 910 if {$pchook ne {}} {
c8ebafd8
SP
911 catch {exec $pchook &}
912 }
913
e57ca85e
SP
914 $ui_comm delete 0.0 end
915 $ui_comm edit modified false
b2c6fcf1 916 $ui_comm edit reset
ec6b424a
SP
917
918 if {$single_commit} do_quit
919
7f1df79b
SP
920 # -- Update status without invoking any git commands.
921 #
7f1df79b 922 set commit_type normal
bd1e2b40
SP
923 set HEAD $cmt_id
924 set PARENT $cmt_id
7f1df79b
SP
925
926 foreach path [array names file_states] {
927 set s $file_states($path)
928 set m [lindex $s 0]
929 switch -glob -- $m {
930 A? -
931 M? -
932 D? {set m _[string index $m 1]}
933 }
934
043f7011 935 if {$m eq {__}} {
7f1df79b
SP
936 unset file_states($path)
937 } else {
938 lset file_states($path) 0 $m
939 }
940 }
941
942 display_all_files
ec6b424a 943 unlock_index
7f1df79b
SP
944 reshow_diff
945 set ui_status_value \
946 "Changes committed as [string range $cmt_id 0 7]."
ec6b424a
SP
947}
948
8c0ce436
SP
949######################################################################
950##
951## fetch pull push
952
953proc fetch_from {remote} {
954 set w [new_console "fetch $remote" \
955 "Fetching new changes from $remote"]
cc4b1c02 956 set cmd [list git fetch]
8c0ce436 957 lappend cmd $remote
cc4b1c02 958 console_exec $w $cmd
8c0ce436
SP
959}
960
d33ba5fa 961proc pull_remote {remote branch} {
ebf336b9 962 global HEAD commit_type file_states repo_config
ec39d83a 963
988b8a7d 964 if {![lock_index update]} return
ec39d83a
SP
965
966 # -- Our in memory state should match the repository.
967 #
968 repository_state curHEAD cur_type
043f7011 969 if {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
ec39d83a
SP
970 error_popup {Last scanned state does not match repository state.
971
972Its highly likely that another Git program modified the
973repository since our last scan. A rescan is required
974before a pull can be started.
975}
976 unlock_index
977 update_status
978 return
979 }
980
981 # -- No differences should exist before a pull.
982 #
983 if {[array size file_states] != 0} {
984 error_popup {Uncommitted but modified files are present.
985
986You should not perform a pull with unmodified files in your working
987directory as Git would be unable to recover from an incorrect merge.
988
989Commit or throw away all changes before starting a pull operation.
990}
991 unlock_index
992 return
993 }
994
d33ba5fa
SP
995 set w [new_console "pull $remote $branch" \
996 "Pulling new changes from branch $branch in $remote"]
997 set cmd [list git pull]
043f7011 998 if {$repo_config(gui.pullsummary) eq {false}} {
ebf336b9
SP
999 lappend cmd --no-summary
1000 }
d33ba5fa
SP
1001 lappend cmd $remote
1002 lappend cmd $branch
1003 console_exec $w $cmd [list post_pull_remote $remote $branch]
1004}
1005
1006proc post_pull_remote {remote branch success} {
ec39d83a
SP
1007 global HEAD PARENT commit_type
1008 global ui_status_value
1009
988b8a7d 1010 unlock_index
d33ba5fa 1011 if {$success} {
ec39d83a
SP
1012 repository_state HEAD commit_type
1013 set PARENT $HEAD
1014 set $ui_status_value {Ready.}
d33ba5fa 1015 } else {
390adaea
SP
1016 update_status \
1017 "Conflicts detected while pulling $branch from $remote."
d33ba5fa
SP
1018 }
1019}
1020
8c0ce436
SP
1021proc push_to {remote} {
1022 set w [new_console "push $remote" \
1023 "Pushing changes to $remote"]
cc4b1c02 1024 set cmd [list git push]
8c0ce436 1025 lappend cmd $remote
cc4b1c02 1026 console_exec $w $cmd
8c0ce436
SP
1027}
1028
cb07fc2a
SP
1029######################################################################
1030##
1031## ui helpers
1032
1033proc mapcol {state path} {
6b292675 1034 global all_cols ui_other
cb07fc2a
SP
1035
1036 if {[catch {set r $all_cols($state)}]} {
1037 puts "error: no column for state={$state} $path"
6b292675 1038 return $ui_other
cb07fc2a
SP
1039 }
1040 return $r
1041}
1042
1043proc mapicon {state path} {
1044 global all_icons
1045
1046 if {[catch {set r $all_icons($state)}]} {
1047 puts "error: no icon for state={$state} $path"
1048 return file_plain
1049 }
1050 return $r
1051}
1052
1053proc mapdesc {state path} {
1054 global all_descs
1055
1056 if {[catch {set r $all_descs($state)}]} {
1057 puts "error: no desc for state={$state} $path"
1058 return $state
1059 }
1060 return $r
1061}
1062
68e009de
SP
1063proc escape_path {path} {
1064 regsub -all "\n" $path "\\n" path
1065 return $path
1066}
1067
16403d0b
SP
1068proc short_path {path} {
1069 return [escape_path [lindex [file split $path] end]]
1070}
1071
93f654df
SP
1072set next_icon_id 0
1073
6b292675 1074proc merge_state {path new_state} {
93f654df 1075 global file_states next_icon_id
cb07fc2a 1076
6b292675
SP
1077 set s0 [string index $new_state 0]
1078 set s1 [string index $new_state 1]
1079
1080 if {[catch {set info $file_states($path)}]} {
1081 set state __
1082 set icon n[incr next_icon_id]
cb07fc2a 1083 } else {
6b292675
SP
1084 set state [lindex $info 0]
1085 set icon [lindex $info 1]
cb07fc2a
SP
1086 }
1087
043f7011 1088 if {$s0 eq {_}} {
6b292675 1089 set s0 [string index $state 0]
043f7011 1090 } elseif {$s0 eq {*}} {
6b292675 1091 set s0 _
cb07fc2a
SP
1092 }
1093
043f7011 1094 if {$s1 eq {_}} {
6b292675 1095 set s1 [string index $state 1]
043f7011 1096 } elseif {$s1 eq {*}} {
6b292675 1097 set s1 _
cb07fc2a
SP
1098 }
1099
6b292675
SP
1100 set file_states($path) [list $s0$s1 $icon]
1101 return $state
cb07fc2a
SP
1102}
1103
1104proc display_file {path state} {
03e4ec53 1105 global file_states file_lists status_active
cb07fc2a
SP
1106
1107 set old_m [merge_state $path $state]
93f654df
SP
1108 if {$status_active} return
1109
cb07fc2a 1110 set s $file_states($path)
93f654df 1111 set new_m [lindex $s 0]
0fb8f9ce
SP
1112 set new_w [mapcol $new_m $path]
1113 set old_w [mapcol $old_m $path]
1114 set new_icon [mapicon $new_m $path]
cb07fc2a 1115
043f7011 1116 if {$new_w ne $old_w} {
03e4ec53 1117 set lno [lsearch -sorted $file_lists($old_w) $path]
cb07fc2a
SP
1118 if {$lno >= 0} {
1119 incr lno
93f654df
SP
1120 $old_w conf -state normal
1121 $old_w delete $lno.0 [expr $lno + 1].0
1122 $old_w conf -state disabled
cb07fc2a 1123 }
93f654df 1124
03e4ec53
SP
1125 lappend file_lists($new_w) $path
1126 set file_lists($new_w) [lsort $file_lists($new_w)]
1127 set lno [lsearch -sorted $file_lists($new_w) $path]
1128 incr lno
93f654df
SP
1129 $new_w conf -state normal
1130 $new_w image create $lno.0 \
1131 -align center -padx 5 -pady 1 \
1132 -name [lindex $s 1] \
e4ee9af4 1133 -image $new_icon
68e009de 1134 $new_w insert $lno.1 "[escape_path $path]\n"
93f654df 1135 $new_w conf -state disabled
043f7011 1136 } elseif {$new_icon ne [mapicon $old_m $path]} {
93f654df
SP
1137 $new_w conf -state normal
1138 $new_w image conf [lindex $s 1] -image $new_icon
1139 $new_w conf -state disabled
cb07fc2a 1140 }
93f654df 1141}
cb07fc2a 1142
93f654df 1143proc display_all_files {} {
03e4ec53 1144 global ui_index ui_other file_states file_lists
93f654df
SP
1145
1146 $ui_index conf -state normal
1147 $ui_other conf -state normal
1148
7f1df79b
SP
1149 $ui_index delete 0.0 end
1150 $ui_other delete 0.0 end
1151
62aac80b
SP
1152 set file_lists($ui_index) [list]
1153 set file_lists($ui_other) [list]
1154
93f654df
SP
1155 foreach path [lsort [array names file_states]] {
1156 set s $file_states($path)
1157 set m [lindex $s 0]
6b292675 1158 set w [mapcol $m $path]
03e4ec53 1159 lappend file_lists($w) $path
6b292675 1160 $w image create end \
cb07fc2a 1161 -align center -padx 5 -pady 1 \
93f654df
SP
1162 -name [lindex $s 1] \
1163 -image [mapicon $m $path]
68e009de 1164 $w insert end "[escape_path $path]\n"
cb07fc2a 1165 }
93f654df
SP
1166
1167 $ui_index conf -state disabled
1168 $ui_other conf -state disabled
cb07fc2a
SP
1169}
1170
74e6b12f 1171proc update_index {pathList} {
2cbe5577 1172 global update_index_cp update_index_rsd ui_status_value
131f503b 1173
74e6b12f 1174 if {![lock_index update]} return
131f503b 1175
74e6b12f 1176 set update_index_cp 0
2cbe5577 1177 set update_index_rsd 0
aaf1085a 1178 set pathList [lsort $pathList]
74e6b12f
SP
1179 set totalCnt [llength $pathList]
1180 set batch [expr {int($totalCnt * .01) + 1}]
1181 if {$batch > 25} {set batch 25}
1182
74e6b12f
SP
1183 set ui_status_value [format \
1184 "Including files ... %i/%i files (%.2f%%)" \
1185 $update_index_cp \
1186 $totalCnt \
1187 0.0]
1188 set fd [open "| git update-index --add --remove -z --stdin" w]
7f09cfaf
SP
1189 fconfigure $fd \
1190 -blocking 0 \
1191 -buffering full \
1192 -buffersize 512 \
1193 -translation binary
74e6b12f
SP
1194 fileevent $fd writable [list \
1195 write_update_index \
1196 $fd \
1197 $pathList \
1198 $totalCnt \
1199 $batch \
1200 ]
1201}
1202
1203proc write_update_index {fd pathList totalCnt batch} {
2cbe5577 1204 global update_index_cp update_index_rsd ui_status_value
74e6b12f 1205 global file_states ui_fname_value
131f503b 1206
74e6b12f
SP
1207 if {$update_index_cp >= $totalCnt} {
1208 close $fd
1209 unlock_index
f7f8d322 1210 set ui_status_value {Ready.}
2cbe5577 1211 if {$update_index_rsd} {
fd2656fd 1212 reshow_diff
2cbe5577 1213 }
74e6b12f 1214 return
131f503b 1215 }
131f503b 1216
74e6b12f
SP
1217 for {set i $batch} \
1218 {$update_index_cp < $totalCnt && $i > 0} \
1219 {incr i -1} {
1220 set path [lindex $pathList $update_index_cp]
1221 incr update_index_cp
1222
1223 switch -- [lindex $file_states($path) 0] {
1224 AM -
1225 _O {set new A*}
1226 _M -
1227 MM {set new M*}
1228 AD -
1229 _D {set new D*}
1230 default {continue}
1231 }
cb07fc2a 1232
74e6b12f
SP
1233 puts -nonewline $fd $path
1234 puts -nonewline $fd "\0"
1235 display_file $path $new
043f7011 1236 if {$ui_fname_value eq $path} {
2cbe5577 1237 set update_index_rsd 1
74e6b12f 1238 }
cb07fc2a
SP
1239 }
1240
74e6b12f
SP
1241 set ui_status_value [format \
1242 "Including files ... %i/%i files (%.2f%%)" \
1243 $update_index_cp \
1244 $totalCnt \
1245 [expr {100.0 * $update_index_cp / $totalCnt}]]
cb07fc2a
SP
1246}
1247
8c0ce436
SP
1248######################################################################
1249##
2d19516d 1250## remote management
0d4f3eb5 1251
8c0ce436 1252proc load_all_remotes {} {
0d4f3eb5 1253 global gitdir all_remotes repo_config
8c0ce436
SP
1254
1255 set all_remotes [list]
1256 set rm_dir [file join $gitdir remotes]
1257 if {[file isdirectory $rm_dir]} {
d47ae541
SP
1258 set all_remotes [concat $all_remotes [glob \
1259 -types f \
1260 -tails \
1261 -nocomplain \
1262 -directory $rm_dir *]]
8c0ce436
SP
1263 }
1264
0d4f3eb5
SP
1265 foreach line [array names repo_config remote.*.url] {
1266 if {[regexp ^remote\.(.*)\.url\$ $line line name]} {
8c0ce436
SP
1267 lappend all_remotes $name
1268 }
1269 }
8c0ce436
SP
1270
1271 set all_remotes [lsort -unique $all_remotes]
1272}
1273
1274proc populate_remote_menu {m pfx op} {
b4946930 1275 global all_remotes
8c0ce436
SP
1276
1277 foreach remote $all_remotes {
1278 $m add command -label "$pfx $remote..." \
1279 -command [list $op $remote] \
b4946930 1280 -font font_ui
8c0ce436
SP
1281 }
1282}
1283
d33ba5fa 1284proc populate_pull_menu {m} {
b4946930 1285 global gitdir repo_config all_remotes disable_on_lock
d33ba5fa
SP
1286
1287 foreach remote $all_remotes {
1288 set rb {}
043f7011
SP
1289 if {[array get repo_config remote.$remote.url] ne {}} {
1290 if {[array get repo_config remote.$remote.fetch] ne {}} {
d33ba5fa
SP
1291 regexp {^([^:]+):} \
1292 [lindex $repo_config(remote.$remote.fetch) 0] \
1293 line rb
1294 }
1295 } else {
1296 catch {
1297 set fd [open [file join $gitdir remotes $remote] r]
1298 while {[gets $fd line] >= 0} {
1299 if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} {
1300 break
1301 }
1302 }
1303 close $fd
1304 }
1305 }
1306
1307 set rb_short $rb
1308 regsub ^refs/heads/ $rb {} rb_short
043f7011 1309 if {$rb_short ne {}} {
d33ba5fa
SP
1310 $m add command \
1311 -label "Branch $rb_short from $remote..." \
1312 -command [list pull_remote $remote $rb] \
b4946930 1313 -font font_ui
0a462d67
SP
1314 lappend disable_on_lock \
1315 [list $m entryconf [$m index last] -state]
d33ba5fa
SP
1316 }
1317 }
1318}
1319
cb07fc2a
SP
1320######################################################################
1321##
1322## icons
1323
1324set filemask {
1325#define mask_width 14
1326#define mask_height 15
1327static unsigned char mask_bits[] = {
1328 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1329 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1330 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1331}
1332
1333image create bitmap file_plain -background white -foreground black -data {
1334#define plain_width 14
1335#define plain_height 15
1336static unsigned char plain_bits[] = {
1337 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1338 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1339 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1340} -maskdata $filemask
1341
1342image create bitmap file_mod -background white -foreground blue -data {
1343#define mod_width 14
1344#define mod_height 15
1345static unsigned char mod_bits[] = {
1346 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1347 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1348 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1349} -maskdata $filemask
1350
131f503b
SP
1351image create bitmap file_fulltick -background white -foreground "#007000" -data {
1352#define file_fulltick_width 14
1353#define file_fulltick_height 15
1354static unsigned char file_fulltick_bits[] = {
cb07fc2a
SP
1355 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1356 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1357 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1358} -maskdata $filemask
1359
1360image create bitmap file_parttick -background white -foreground "#005050" -data {
1361#define parttick_width 14
1362#define parttick_height 15
1363static unsigned char parttick_bits[] = {
1364 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1365 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1366 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1367} -maskdata $filemask
1368
1369image create bitmap file_question -background white -foreground black -data {
1370#define file_question_width 14
1371#define file_question_height 15
1372static unsigned char file_question_bits[] = {
1373 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1374 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1375 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1376} -maskdata $filemask
1377
1378image create bitmap file_removed -background white -foreground red -data {
1379#define file_removed_width 14
1380#define file_removed_height 15
1381static unsigned char file_removed_bits[] = {
1382 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1383 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1384 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1385} -maskdata $filemask
1386
1387image create bitmap file_merge -background white -foreground blue -data {
1388#define file_merge_width 14
1389#define file_merge_height 15
1390static unsigned char file_merge_bits[] = {
1391 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1392 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1393 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1394} -maskdata $filemask
1395
6b292675
SP
1396set ui_index .vpane.files.index.list
1397set ui_other .vpane.files.other.list
131f503b 1398set max_status_desc 0
cb07fc2a 1399foreach i {
131f503b
SP
1400 {__ i plain "Unmodified"}
1401 {_M i mod "Modified"}
135f76ed 1402 {M_ i fulltick "Included in commit"}
7fe7e733 1403 {MM i parttick "Partially included"}
131f503b
SP
1404
1405 {_O o plain "Untracked"}
135f76ed 1406 {A_ o fulltick "Added by commit"}
131f503b 1407 {AM o parttick "Partially added"}
6b292675 1408 {AD o question "Added (but now gone)"}
131f503b
SP
1409
1410 {_D i question "Missing"}
135f76ed
SP
1411 {D_ i removed "Removed by commit"}
1412 {DD i removed "Removed by commit"}
131f503b
SP
1413 {DO i removed "Removed (still exists)"}
1414
1415 {UM i merge "Merge conflicts"}
1416 {U_ i merge "Merge conflicts"}
cb07fc2a 1417 } {
131f503b
SP
1418 if {$max_status_desc < [string length [lindex $i 3]]} {
1419 set max_status_desc [string length [lindex $i 3]]
1420 }
043f7011 1421 if {[lindex $i 1] eq {i}} {
6b292675
SP
1422 set all_cols([lindex $i 0]) $ui_index
1423 } else {
1424 set all_cols([lindex $i 0]) $ui_other
1425 }
131f503b
SP
1426 set all_icons([lindex $i 0]) file_[lindex $i 2]
1427 set all_descs([lindex $i 0]) [lindex $i 3]
cb07fc2a
SP
1428}
1429unset filemask i
1430
1431######################################################################
1432##
1433## util
1434
16fccd7a
SP
1435proc is_MacOSX {} {
1436 global tcl_platform tk_library
043f7011
SP
1437 if {$tcl_platform(platform) eq {unix}
1438 && $tcl_platform(os) eq {Darwin}
16fccd7a
SP
1439 && [string match /Library/Frameworks/* $tk_library]} {
1440 return 1
1441 }
1442 return 0
1443}
1444
1445proc bind_button3 {w cmd} {
1446 bind $w <Any-Button-3> $cmd
1447 if {[is_MacOSX]} {
1448 bind $w <Control-Button-1> $cmd
1449 }
1450}
1451
b4946930
SP
1452proc incr_font_size {font {amt 1}} {
1453 set sz [font configure $font -size]
1454 incr sz $amt
1455 font configure $font -size $sz
1456 font configure ${font}bold -size $sz
1457}
1458
6e27d826 1459proc hook_failed_popup {hook msg} {
b4946930 1460 global gitdir appname
6e27d826
SP
1461
1462 set w .hookfail
1463 toplevel $w
6e27d826
SP
1464
1465 frame $w.m
1466 label $w.m.l1 -text "$hook hook failed:" \
1467 -anchor w \
1468 -justify left \
b4946930 1469 -font font_uibold
6e27d826
SP
1470 text $w.m.t \
1471 -background white -borderwidth 1 \
1472 -relief sunken \
1473 -width 80 -height 10 \
b4946930 1474 -font font_diff \
6e27d826
SP
1475 -yscrollcommand [list $w.m.sby set]
1476 label $w.m.l2 \
1477 -text {You must correct the above errors before committing.} \
1478 -anchor w \
1479 -justify left \
b4946930 1480 -font font_uibold
6e27d826
SP
1481 scrollbar $w.m.sby -command [list $w.m.t yview]
1482 pack $w.m.l1 -side top -fill x
1483 pack $w.m.l2 -side bottom -fill x
1484 pack $w.m.sby -side right -fill y
1485 pack $w.m.t -side left -fill both -expand 1
1486 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
1487
1488 $w.m.t insert 1.0 $msg
1489 $w.m.t conf -state disabled
1490
1491 button $w.ok -text OK \
1492 -width 15 \
b4946930 1493 -font font_ui \
6e27d826 1494 -command "destroy $w"
1e5c18fb 1495 pack $w.ok -side bottom -anchor e -pady 10 -padx 10
6e27d826
SP
1496
1497 bind $w <Visibility> "grab $w; focus $w"
1498 bind $w <Key-Return> "destroy $w"
d33ba5fa
SP
1499 wm title $w "$appname ([lindex [file split \
1500 [file normalize [file dirname $gitdir]]] \
1501 end]): error"
6e27d826
SP
1502 tkwait window $w
1503}
1504
8c0ce436
SP
1505set next_console_id 0
1506
1507proc new_console {short_title long_title} {
37af79d1
SP
1508 global next_console_id console_data
1509 set w .console[incr next_console_id]
1510 set console_data($w) [list $short_title $long_title]
1511 return [console_init $w]
1512}
1513
1514proc console_init {w} {
1515 global console_cr console_data
b4946930 1516 global gitdir appname M1B
8c0ce436 1517
ee3dc935 1518 set console_cr($w) 1.0
8c0ce436
SP
1519 toplevel $w
1520 frame $w.m
37af79d1 1521 label $w.m.l1 -text "[lindex $console_data($w) 1]:" \
8c0ce436
SP
1522 -anchor w \
1523 -justify left \
b4946930 1524 -font font_uibold
8c0ce436
SP
1525 text $w.m.t \
1526 -background white -borderwidth 1 \
1527 -relief sunken \
1528 -width 80 -height 10 \
b4946930 1529 -font font_diff \
8c0ce436
SP
1530 -state disabled \
1531 -yscrollcommand [list $w.m.sby set]
1e5c18fb
SP
1532 label $w.m.s -text {Working... please wait...} \
1533 -anchor w \
07123f40 1534 -justify left \
b4946930 1535 -font font_uibold
8c0ce436
SP
1536 scrollbar $w.m.sby -command [list $w.m.t yview]
1537 pack $w.m.l1 -side top -fill x
07123f40 1538 pack $w.m.s -side bottom -fill x
8c0ce436
SP
1539 pack $w.m.sby -side right -fill y
1540 pack $w.m.t -side left -fill both -expand 1
1541 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
1542
0e794311
SP
1543 menu $w.ctxm -tearoff 0
1544 $w.ctxm add command -label "Copy" \
b4946930 1545 -font font_ui \
0e794311
SP
1546 -command "tk_textCopy $w.m.t"
1547 $w.ctxm add command -label "Select All" \
b4946930 1548 -font font_ui \
0e794311
SP
1549 -command "$w.m.t tag add sel 0.0 end"
1550 $w.ctxm add command -label "Copy All" \
b4946930 1551 -font font_ui \
0e794311
SP
1552 -command "
1553 $w.m.t tag add sel 0.0 end
1554 tk_textCopy $w.m.t
1555 $w.m.t tag remove sel 0.0 end
1556 "
1557
1e5c18fb 1558 button $w.ok -text {Close} \
b4946930 1559 -font font_ui \
8c0ce436
SP
1560 -state disabled \
1561 -command "destroy $w"
1e5c18fb 1562 pack $w.ok -side bottom -anchor e -pady 10 -padx 10
8c0ce436 1563
16fccd7a 1564 bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y"
62aac80b
SP
1565 bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break"
1566 bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break"
8c0ce436 1567 bind $w <Visibility> "focus $w"
d33ba5fa
SP
1568 wm title $w "$appname ([lindex [file split \
1569 [file normalize [file dirname $gitdir]]] \
1570 end]): [lindex $console_data($w) 0]"
8c0ce436
SP
1571 return $w
1572}
1573
d33ba5fa 1574proc console_exec {w cmd {after {}}} {
cc4b1c02
SP
1575 global tcl_platform
1576
1577 # -- Windows tosses the enviroment when we exec our child.
1578 # But most users need that so we have to relogin. :-(
1579 #
043f7011 1580 if {$tcl_platform(platform) eq {windows}} {
cc4b1c02
SP
1581 set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"]
1582 }
1583
1584 # -- Tcl won't let us redirect both stdout and stderr to
1585 # the same pipe. So pass it through cat...
1586 #
1587 set cmd [concat | $cmd |& cat]
1588
1589 set fd_f [open $cmd r]
ee3dc935 1590 fconfigure $fd_f -blocking 0 -translation binary
d33ba5fa 1591 fileevent $fd_f readable [list console_read $w $fd_f $after]
cc4b1c02
SP
1592}
1593
d33ba5fa 1594proc console_read {w fd after} {
37af79d1 1595 global console_cr console_data
ee3dc935 1596
ee3dc935 1597 set buf [read $fd]
043f7011 1598 if {$buf ne {}} {
37af79d1
SP
1599 if {![winfo exists $w]} {console_init $w}
1600 $w.m.t conf -state normal
1601 set c 0
1602 set n [string length $buf]
1603 while {$c < $n} {
1604 set cr [string first "\r" $buf $c]
1605 set lf [string first "\n" $buf $c]
1606 if {$cr < 0} {set cr [expr $n + 1]}
1607 if {$lf < 0} {set lf [expr $n + 1]}
1608
1609 if {$lf < $cr} {
1610 $w.m.t insert end [string range $buf $c $lf]
1611 set console_cr($w) [$w.m.t index {end -1c}]
1612 set c $lf
1613 incr c
1614 } else {
1615 $w.m.t delete $console_cr($w) end
1616 $w.m.t insert end "\n"
1617 $w.m.t insert end [string range $buf $c $cr]
1618 set c $cr
1619 incr c
1620 }
ee3dc935 1621 }
37af79d1
SP
1622 $w.m.t conf -state disabled
1623 $w.m.t see end
8c0ce436 1624 }
8c0ce436 1625
07123f40 1626 fconfigure $fd -blocking 1
8c0ce436 1627 if {[eof $fd]} {
07123f40 1628 if {[catch {close $fd}]} {
37af79d1 1629 if {![winfo exists $w]} {console_init $w}
07123f40 1630 $w.m.s conf -background red -text {Error: Command Failed}
37af79d1 1631 $w.ok conf -state normal
d33ba5fa 1632 set ok 0
37af79d1 1633 } elseif {[winfo exists $w]} {
07123f40 1634 $w.m.s conf -background green -text {Success}
37af79d1 1635 $w.ok conf -state normal
d33ba5fa 1636 set ok 1
07123f40 1637 }
ee3dc935 1638 array unset console_cr $w
37af79d1 1639 array unset console_data $w
043f7011 1640 if {$after ne {}} {
d33ba5fa
SP
1641 uplevel #0 $after $ok
1642 }
07123f40 1643 return
8c0ce436 1644 }
07123f40 1645 fconfigure $fd -blocking 0
8c0ce436
SP
1646}
1647
cb07fc2a
SP
1648######################################################################
1649##
1650## ui commands
1651
e210e674 1652set starting_gitk_msg {Please wait... Starting gitk...}
cc4b1c02 1653
cb07fc2a 1654proc do_gitk {} {
e210e674
SP
1655 global tcl_platform ui_status_value starting_gitk_msg
1656
1657 set ui_status_value $starting_gitk_msg
e57ca85e 1658 after 10000 {
043f7011 1659 if {$ui_status_value eq $starting_gitk_msg} {
e210e674
SP
1660 set ui_status_value {Ready.}
1661 }
1662 }
cb07fc2a 1663
043f7011 1664 if {$tcl_platform(platform) eq {windows}} {
cb07fc2a
SP
1665 exec sh -c gitk &
1666 } else {
1667 exec gitk &
1668 }
1669}
1670
d1536c48
SP
1671proc do_repack {} {
1672 set w [new_console "repack" "Repacking the object database"]
1673 set cmd [list git repack]
1674 lappend cmd -a
1675 lappend cmd -d
1676 console_exec $w $cmd
1677}
1678
b5834d70 1679set is_quitting 0
c4fe7728 1680
cb07fc2a 1681proc do_quit {} {
51f4d16b 1682 global gitdir ui_comm is_quitting repo_config
c4fe7728 1683
b5834d70
SP
1684 if {$is_quitting} return
1685 set is_quitting 1
131f503b 1686
51f4d16b
SP
1687 # -- Stash our current commit buffer.
1688 #
131f503b 1689 set save [file join $gitdir GITGUI_MSG]
ec6b424a 1690 set msg [string trim [$ui_comm get 0.0 end]]
043f7011 1691 if {[$ui_comm edit modified] && $msg ne {}} {
131f503b
SP
1692 catch {
1693 set fd [open $save w]
1694 puts $fd [string trim [$ui_comm get 0.0 end]]
1695 close $fd
1696 }
043f7011 1697 } elseif {$msg eq {} && [file exists $save]} {
131f503b
SP
1698 file delete $save
1699 }
1700
51f4d16b
SP
1701 # -- Stash our current window geometry into this repository.
1702 #
1703 set cfg_geometry [list]
1704 lappend cfg_geometry [wm geometry .]
1705 lappend cfg_geometry [lindex [.vpane sash coord 0] 1]
1706 lappend cfg_geometry [lindex [.vpane.files sash coord 0] 0]
1707 if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
1708 set rc_geometry {}
1709 }
043f7011 1710 if {$cfg_geometry ne $rc_geometry} {
51f4d16b
SP
1711 catch {exec git repo-config gui.geometry $cfg_geometry}
1712 }
1713
cb07fc2a
SP
1714 destroy .
1715}
1716
1717proc do_rescan {} {
1718 update_status
1719}
1720
7fe7e733 1721proc do_include_all {} {
74e6b12f
SP
1722 global file_states
1723
1724 if {![lock_index begin-update]} return
1725
1726 set pathList [list]
1727 foreach path [array names file_states] {
1728 set s $file_states($path)
1729 set m [lindex $s 0]
1730 switch -- $m {
1731 AM -
1732 MM -
1733 _M -
1734 _D {lappend pathList $path}
131f503b 1735 }
74e6b12f 1736 }
043f7011 1737 if {$pathList eq {}} {
74e6b12f
SP
1738 unlock_index
1739 } else {
1740 update_index $pathList
131f503b
SP
1741 }
1742}
1743
da5239dc
SP
1744set GIT_COMMITTER_IDENT {}
1745
131f503b 1746proc do_signoff {} {
97bf01c4 1747 global ui_comm GIT_COMMITTER_IDENT
131f503b 1748
043f7011 1749 if {$GIT_COMMITTER_IDENT eq {}} {
97bf01c4 1750 if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
44be340e 1751 error_popup "Unable to obtain your identity:\n\n$err"
97bf01c4 1752 return
131f503b 1753 }
97bf01c4
SP
1754 if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \
1755 $me me GIT_COMMITTER_IDENT]} {
44be340e 1756 error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me"
97bf01c4
SP
1757 return
1758 }
1759 }
1760
1daf1d0c
SP
1761 set sob "Signed-off-by: $GIT_COMMITTER_IDENT"
1762 set last [$ui_comm get {end -1c linestart} {end -1c}]
043f7011 1763 if {$last ne $sob} {
b2c6fcf1 1764 $ui_comm edit separator
043f7011 1765 if {$last ne {}
1daf1d0c
SP
1766 && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} {
1767 $ui_comm insert end "\n"
1768 }
1769 $ui_comm insert end "\n$sob"
b2c6fcf1 1770 $ui_comm edit separator
97bf01c4 1771 $ui_comm see end
131f503b
SP
1772 }
1773}
1774
e57ca85e
SP
1775proc do_amend_last {} {
1776 load_last_commit
1777}
1778
6e27d826 1779proc do_commit {} {
ec6b424a 1780 commit_tree
6e27d826
SP
1781}
1782
51f4d16b 1783proc do_options {} {
92148d80 1784 global appname gitdir font_descs
51f4d16b
SP
1785 global repo_config global_config
1786 global repo_config_new global_config_new
1787
51f4d16b
SP
1788 array unset repo_config_new
1789 array unset global_config_new
1790 foreach name [array names repo_config] {
1791 set repo_config_new($name) $repo_config($name)
1792 }
358d8de8
SP
1793 load_config 1
1794 foreach name [array names repo_config] {
1795 switch -- $name {
1796 gui.diffcontext {continue}
1797 }
1798 set repo_config_new($name) $repo_config($name)
1799 }
51f4d16b
SP
1800 foreach name [array names global_config] {
1801 set global_config_new($name) $global_config($name)
1802 }
e01b4221
SP
1803 set reponame [lindex [file split \
1804 [file normalize [file dirname $gitdir]]] \
1805 end]
51f4d16b
SP
1806
1807 set w .options_editor
1808 toplevel $w
e01b4221 1809 wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
51f4d16b
SP
1810
1811 label $w.header -text "$appname Options" \
1812 -font font_uibold
1813 pack $w.header -side top -fill x
1814
1815 frame $w.buttons
92148d80
SP
1816 button $w.buttons.restore -text {Restore Defaults} \
1817 -font font_ui \
1818 -command do_restore_defaults
1819 pack $w.buttons.restore -side left
51f4d16b
SP
1820 button $w.buttons.save -text Save \
1821 -font font_ui \
92148d80 1822 -command [list do_save_config $w]
51f4d16b
SP
1823 pack $w.buttons.save -side right
1824 button $w.buttons.cancel -text {Cancel} \
1825 -font font_ui \
92148d80 1826 -command [list destroy $w]
51f4d16b 1827 pack $w.buttons.cancel -side right
92148d80 1828 pack $w.buttons -side bottom -fill x -pady 10 -padx 10
51f4d16b 1829
e01b4221 1830 labelframe $w.repo -text "$reponame Repository" \
92148d80 1831 -font font_ui \
51f4d16b
SP
1832 -relief raised -borderwidth 2
1833 labelframe $w.global -text {Global (All Repositories)} \
92148d80 1834 -font font_ui \
51f4d16b
SP
1835 -relief raised -borderwidth 2
1836 pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5
1837 pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5
1838
1839 foreach option {
f7f8d322 1840 {b partialinclude {Allow Partially Included Files}}
358d8de8
SP
1841 {b pullsummary {Show Pull Summary}}
1842 {b trustmtime {Trust File Modification Timestamps}}
1843 {i diffcontext {Number of Diff Context Lines}}
51f4d16b 1844 } {
358d8de8
SP
1845 set type [lindex $option 0]
1846 set name [lindex $option 1]
1847 set text [lindex $option 2]
51f4d16b 1848 foreach f {repo global} {
358d8de8
SP
1849 switch $type {
1850 b {
1851 checkbutton $w.$f.$name -text $text \
1852 -variable ${f}_config_new(gui.$name) \
1853 -onvalue true \
1854 -offvalue false \
1855 -font font_ui
1856 pack $w.$f.$name -side top -anchor w
1857 }
1858 i {
1859 frame $w.$f.$name
1860 label $w.$f.$name.l -text "$text:" -font font_ui
1861 pack $w.$f.$name.l -side left -anchor w -fill x
1862 spinbox $w.$f.$name.v \
1863 -textvariable ${f}_config_new(gui.$name) \
1864 -from 1 -to 99 -increment 1 \
1865 -width 3 \
1866 -font font_ui
1867 pack $w.$f.$name.v -side right -anchor e
1868 pack $w.$f.$name -side top -anchor w -fill x
1869 }
1870 }
51f4d16b
SP
1871 }
1872 }
1873
92148d80
SP
1874 set all_fonts [lsort [font families]]
1875 foreach option $font_descs {
1876 set name [lindex $option 0]
1877 set font [lindex $option 1]
1878 set text [lindex $option 2]
1879
1880 set global_config_new(gui.$font^^family) \
1881 [font configure $font -family]
1882 set global_config_new(gui.$font^^size) \
1883 [font configure $font -size]
1884
1885 frame $w.global.$name
1886 label $w.global.$name.l -text "$text:" -font font_ui
1887 pack $w.global.$name.l -side left -anchor w -fill x
1888 eval tk_optionMenu $w.global.$name.family \
1889 global_config_new(gui.$font^^family) \
1890 $all_fonts
1891 spinbox $w.global.$name.size \
1892 -textvariable global_config_new(gui.$font^^size) \
1893 -from 2 -to 80 -increment 1 \
1894 -width 3 \
1895 -font font_ui
1896 pack $w.global.$name.size -side right -anchor e
1897 pack $w.global.$name.family -side right -anchor e
1898 pack $w.global.$name -side top -anchor w -fill x
1899 }
1900
51f4d16b
SP
1901 bind $w <Visibility> "grab $w; focus $w"
1902 bind $w <Key-Escape> "destroy $w"
e01b4221 1903 wm title $w "$appname ($reponame): Options"
51f4d16b
SP
1904 tkwait window $w
1905}
1906
92148d80 1907proc do_restore_defaults {} {
7b64d0b7 1908 global font_descs default_config repo_config
92148d80
SP
1909 global repo_config_new global_config_new
1910
1911 foreach name [array names default_config] {
1912 set repo_config_new($name) $default_config($name)
1913 set global_config_new($name) $default_config($name)
1914 }
1915
1916 foreach option $font_descs {
1917 set name [lindex $option 0]
7b64d0b7 1918 set repo_config(gui.$name) $default_config(gui.$name)
92148d80
SP
1919 }
1920 apply_config
1921
1922 foreach option $font_descs {
1923 set name [lindex $option 0]
1924 set font [lindex $option 1]
1925 set global_config_new(gui.$font^^family) \
1926 [font configure $font -family]
1927 set global_config_new(gui.$font^^size) \
1928 [font configure $font -size]
1929 }
1930}
1931
1932proc do_save_config {w} {
1933 if {[catch {save_config} err]} {
1934 error_popup "Failed to completely save options:\n\n$err"
1935 }
358d8de8 1936 reshow_diff
92148d80
SP
1937 destroy $w
1938}
1939
7d0d289e
SP
1940proc file_left_click {w x y} {
1941 global file_lists
131f503b 1942
cb07fc2a
SP
1943 set pos [split [$w index @$x,$y] .]
1944 set lno [lindex $pos 0]
1945 set col [lindex $pos 1]
03e4ec53 1946 set path [lindex $file_lists($w) [expr $lno - 1]]
043f7011 1947 if {$path eq {}} return
cb07fc2a 1948
7d0d289e 1949 if {$col > 0} {
03e4ec53 1950 show_diff $path $w $lno
cb07fc2a
SP
1951 }
1952}
1953
7d0d289e 1954proc file_left_unclick {w x y} {
7f1df79b
SP
1955 global file_lists
1956
cb07fc2a
SP
1957 set pos [split [$w index @$x,$y] .]
1958 set lno [lindex $pos 0]
1959 set col [lindex $pos 1]
7f1df79b 1960 set path [lindex $file_lists($w) [expr $lno - 1]]
043f7011 1961 if {$path eq {}} return
cb07fc2a 1962
e210e674 1963 if {$col == 0} {
74e6b12f 1964 update_index [list $path]
cb07fc2a
SP
1965 }
1966}
1967
1968######################################################################
1969##
92148d80 1970## config defaults
cb07fc2a 1971
00f949fb 1972set cursor_ptr arrow
b4946930
SP
1973font create font_diff -family Courier -size 10
1974font create font_ui
1975catch {
1976 label .dummy
1977 eval font configure font_ui [font actual [.dummy cget -font]]
1978 destroy .dummy
1979}
1980
92148d80
SP
1981font create font_uibold
1982font create font_diffbold
cb07fc2a 1983
16fccd7a
SP
1984set M1B M1
1985set M1T M1
043f7011 1986if {$tcl_platform(platform) eq {windows}} {
16fccd7a
SP
1987 set M1B Control
1988 set M1T Ctrl
1989} elseif {[is_MacOSX]} {
1990 set M1B M1
1991 set M1T Cmd
e210e674
SP
1992}
1993
92148d80
SP
1994proc apply_config {} {
1995 global repo_config font_descs
1996
1997 foreach option $font_descs {
1998 set name [lindex $option 0]
1999 set font [lindex $option 1]
2000 if {[catch {
2001 foreach {cn cv} $repo_config(gui.$name) {
2002 font configure $font $cn $cv
2003 }
2004 } err]} {
2005 error_popup "Invalid font specified in gui.$name:\n\n$err"
2006 }
2007 foreach {cn cv} [font configure $font] {
2008 font configure ${font}bold $cn $cv
2009 }
2010 font configure ${font}bold -weight bold
2011 }
2012}
2013
2014set default_config(gui.trustmtime) false
ebf336b9 2015set default_config(gui.pullsummary) true
f7f8d322 2016set default_config(gui.partialinclude) false
358d8de8 2017set default_config(gui.diffcontext) 5
92148d80
SP
2018set default_config(gui.fontui) [font configure font_ui]
2019set default_config(gui.fontdiff) [font configure font_diff]
2020set font_descs {
2021 {fontui font_ui {Main Font}}
2022 {fontdiff font_diff {Diff/Console Font}}
2023}
6bbd1cb9 2024load_config 0
92148d80
SP
2025apply_config
2026
2027######################################################################
2028##
2029## ui construction
2030
cb07fc2a 2031# -- Menu Bar
b4946930 2032menu .mbar -tearoff 0
cb07fc2a 2033.mbar add cascade -label Project -menu .mbar.project
9861671d 2034.mbar add cascade -label Edit -menu .mbar.edit
cb07fc2a 2035.mbar add cascade -label Commit -menu .mbar.commit
4ccdab02
SP
2036if {!$single_commit} {
2037 .mbar add cascade -label Fetch -menu .mbar.fetch
2038 .mbar add cascade -label Pull -menu .mbar.pull
2039 .mbar add cascade -label Push -menu .mbar.push
2040}
cb07fc2a
SP
2041. configure -menu .mbar
2042
2043# -- Project Menu
2044menu .mbar.project
6f6eed28 2045.mbar.project add command -label Visualize \
cb07fc2a 2046 -command do_gitk \
b4946930 2047 -font font_ui
4ccdab02
SP
2048if {!$single_commit} {
2049 .mbar.project add command -label {Repack Database} \
2050 -command do_repack \
2051 -font font_ui
2052}
cb07fc2a
SP
2053.mbar.project add command -label Quit \
2054 -command do_quit \
e210e674 2055 -accelerator $M1T-Q \
b4946930 2056 -font font_ui
cb07fc2a 2057
9861671d
SP
2058# -- Edit Menu
2059#
2060menu .mbar.edit
2061.mbar.edit add command -label Undo \
2062 -command {catch {[focus] edit undo}} \
2063 -accelerator $M1T-Z \
b4946930 2064 -font font_ui
9861671d
SP
2065.mbar.edit add command -label Redo \
2066 -command {catch {[focus] edit redo}} \
2067 -accelerator $M1T-Y \
b4946930 2068 -font font_ui
9861671d
SP
2069.mbar.edit add separator
2070.mbar.edit add command -label Cut \
2071 -command {catch {tk_textCut [focus]}} \
2072 -accelerator $M1T-X \
b4946930 2073 -font font_ui
9861671d
SP
2074.mbar.edit add command -label Copy \
2075 -command {catch {tk_textCopy [focus]}} \
2076 -accelerator $M1T-C \
b4946930 2077 -font font_ui
9861671d
SP
2078.mbar.edit add command -label Paste \
2079 -command {catch {tk_textPaste [focus]; [focus] see insert}} \
2080 -accelerator $M1T-V \
b4946930 2081 -font font_ui
9861671d
SP
2082.mbar.edit add command -label Delete \
2083 -command {catch {[focus] delete sel.first sel.last}} \
2084 -accelerator Del \
b4946930 2085 -font font_ui
9861671d
SP
2086.mbar.edit add separator
2087.mbar.edit add command -label {Select All} \
2088 -command {catch {[focus] tag add sel 0.0 end}} \
2089 -accelerator $M1T-A \
b4946930 2090 -font font_ui
51f4d16b
SP
2091.mbar.edit add separator
2092.mbar.edit add command -label {Options...} \
2093 -command do_options \
2094 -font font_ui
9861671d 2095
cb07fc2a
SP
2096# -- Commit Menu
2097menu .mbar.commit
2098.mbar.commit add command -label Rescan \
2099 -command do_rescan \
e210e674 2100 -accelerator F5 \
b4946930 2101 -font font_ui
e210e674
SP
2102lappend disable_on_lock \
2103 [list .mbar.commit entryconf [.mbar.commit index last] -state]
e57ca85e
SP
2104.mbar.commit add command -label {Amend Last Commit} \
2105 -command do_amend_last \
b4946930 2106 -font font_ui
e57ca85e
SP
2107lappend disable_on_lock \
2108 [list .mbar.commit entryconf [.mbar.commit index last] -state]
7fe7e733
SP
2109.mbar.commit add command -label {Include All Files} \
2110 -command do_include_all \
49b86f01 2111 -accelerator $M1T-I \
b4946930 2112 -font font_ui
e210e674
SP
2113lappend disable_on_lock \
2114 [list .mbar.commit entryconf [.mbar.commit index last] -state]
131f503b
SP
2115.mbar.commit add command -label {Sign Off} \
2116 -command do_signoff \
e210e674 2117 -accelerator $M1T-S \
b4946930 2118 -font font_ui
131f503b
SP
2119.mbar.commit add command -label Commit \
2120 -command do_commit \
e210e674 2121 -accelerator $M1T-Return \
b4946930 2122 -font font_ui
e210e674
SP
2123lappend disable_on_lock \
2124 [list .mbar.commit entryconf [.mbar.commit index last] -state]
cb07fc2a 2125
4ccdab02
SP
2126if {!$single_commit} {
2127 # -- Fetch Menu
2128 menu .mbar.fetch
cb07fc2a 2129
4ccdab02
SP
2130 # -- Pull Menu
2131 menu .mbar.pull
cb07fc2a 2132
4ccdab02
SP
2133 # -- Push Menu
2134 menu .mbar.push
2135}
8c0ce436 2136
cb07fc2a
SP
2137# -- Main Window Layout
2138panedwindow .vpane -orient vertical
2139panedwindow .vpane.files -orient horizontal
6f6eed28 2140.vpane add .vpane.files -sticky nsew -height 100 -width 400
cb07fc2a
SP
2141pack .vpane -anchor n -side top -fill both -expand 1
2142
2143# -- Index File List
cb07fc2a
SP
2144frame .vpane.files.index -height 100 -width 400
2145label .vpane.files.index.title -text {Modified Files} \
2146 -background green \
b4946930 2147 -font font_ui
cb07fc2a
SP
2148text $ui_index -background white -borderwidth 0 \
2149 -width 40 -height 10 \
b4946930 2150 -font font_ui \
6c6dd01a 2151 -cursor $cursor_ptr \
cb07fc2a 2152 -yscrollcommand {.vpane.files.index.sb set} \
cb07fc2a
SP
2153 -state disabled
2154scrollbar .vpane.files.index.sb -command [list $ui_index yview]
2155pack .vpane.files.index.title -side top -fill x
2156pack .vpane.files.index.sb -side right -fill y
2157pack $ui_index -side left -fill both -expand 1
2158.vpane.files add .vpane.files.index -sticky nsew
2159
2160# -- Other (Add) File List
cb07fc2a
SP
2161frame .vpane.files.other -height 100 -width 100
2162label .vpane.files.other.title -text {Untracked Files} \
2163 -background red \
b4946930 2164 -font font_ui
cb07fc2a
SP
2165text $ui_other -background white -borderwidth 0 \
2166 -width 40 -height 10 \
b4946930 2167 -font font_ui \
6c6dd01a 2168 -cursor $cursor_ptr \
cb07fc2a 2169 -yscrollcommand {.vpane.files.other.sb set} \
cb07fc2a
SP
2170 -state disabled
2171scrollbar .vpane.files.other.sb -command [list $ui_other yview]
2172pack .vpane.files.other.title -side top -fill x
2173pack .vpane.files.other.sb -side right -fill y
2174pack $ui_other -side left -fill both -expand 1
2175.vpane.files add .vpane.files.other -sticky nsew
2176
b4946930
SP
2177$ui_index tag conf in_diff -font font_uibold
2178$ui_other tag conf in_diff -font font_uibold
131f503b 2179
0fb8f9ce 2180# -- Diff and Commit Area
8009dcdc 2181frame .vpane.lower -height 300 -width 400
0fb8f9ce
SP
2182frame .vpane.lower.commarea
2183frame .vpane.lower.diff -relief sunken -borderwidth 1
2184pack .vpane.lower.commarea -side top -fill x
2185pack .vpane.lower.diff -side bottom -fill both -expand 1
2186.vpane add .vpane.lower -stick nsew
cb07fc2a
SP
2187
2188# -- Commit Area Buttons
0fb8f9ce
SP
2189frame .vpane.lower.commarea.buttons
2190label .vpane.lower.commarea.buttons.l -text {} \
cb07fc2a
SP
2191 -anchor w \
2192 -justify left \
b4946930 2193 -font font_ui
0fb8f9ce
SP
2194pack .vpane.lower.commarea.buttons.l -side top -fill x
2195pack .vpane.lower.commarea.buttons -side left -fill y
131f503b 2196
0fb8f9ce 2197button .vpane.lower.commarea.buttons.rescan -text {Rescan} \
cb07fc2a 2198 -command do_rescan \
b4946930 2199 -font font_ui
0fb8f9ce 2200pack .vpane.lower.commarea.buttons.rescan -side top -fill x
390adaea
SP
2201lappend disable_on_lock \
2202 {.vpane.lower.commarea.buttons.rescan conf -state}
131f503b 2203
0fb8f9ce 2204button .vpane.lower.commarea.buttons.amend -text {Amend Last} \
e57ca85e 2205 -command do_amend_last \
b4946930 2206 -font font_ui
0fb8f9ce 2207pack .vpane.lower.commarea.buttons.amend -side top -fill x
390adaea
SP
2208lappend disable_on_lock \
2209 {.vpane.lower.commarea.buttons.amend conf -state}
e57ca85e 2210
7fe7e733
SP
2211button .vpane.lower.commarea.buttons.incall -text {Include All} \
2212 -command do_include_all \
b4946930 2213 -font font_ui
7fe7e733 2214pack .vpane.lower.commarea.buttons.incall -side top -fill x
390adaea
SP
2215lappend disable_on_lock \
2216 {.vpane.lower.commarea.buttons.incall conf -state}
131f503b 2217
0fb8f9ce 2218button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \
131f503b 2219 -command do_signoff \
b4946930 2220 -font font_ui
0fb8f9ce 2221pack .vpane.lower.commarea.buttons.signoff -side top -fill x
131f503b 2222
0fb8f9ce 2223button .vpane.lower.commarea.buttons.commit -text {Commit} \
cb07fc2a 2224 -command do_commit \
b4946930 2225 -font font_ui
0fb8f9ce 2226pack .vpane.lower.commarea.buttons.commit -side top -fill x
390adaea
SP
2227lappend disable_on_lock \
2228 {.vpane.lower.commarea.buttons.commit conf -state}
cb07fc2a
SP
2229
2230# -- Commit Message Buffer
0fb8f9ce
SP
2231frame .vpane.lower.commarea.buffer
2232set ui_comm .vpane.lower.commarea.buffer.t
2233set ui_coml .vpane.lower.commarea.buffer.l
bd1e2b40 2234label $ui_coml -text {Commit Message:} \
cb07fc2a
SP
2235 -anchor w \
2236 -justify left \
b4946930 2237 -font font_ui
bd1e2b40
SP
2238trace add variable commit_type write {uplevel #0 {
2239 switch -glob $commit_type \
2240 initial {$ui_coml conf -text {Initial Commit Message:}} \
2241 amend {$ui_coml conf -text {Amended Commit Message:}} \
2242 merge {$ui_coml conf -text {Merge Commit Message:}} \
2243 * {$ui_coml conf -text {Commit Message:}}
2244}}
cb07fc2a 2245text $ui_comm -background white -borderwidth 1 \
9861671d 2246 -undo true \
b2c6fcf1 2247 -maxundo 20 \
9861671d 2248 -autoseparators true \
cb07fc2a 2249 -relief sunken \
0fb8f9ce 2250 -width 75 -height 9 -wrap none \
b4946930 2251 -font font_diff \
6c6dd01a 2252 -yscrollcommand {.vpane.lower.commarea.buffer.sby set}
390adaea
SP
2253scrollbar .vpane.lower.commarea.buffer.sby \
2254 -command [list $ui_comm yview]
bd1e2b40 2255pack $ui_coml -side top -fill x
0fb8f9ce 2256pack .vpane.lower.commarea.buffer.sby -side right -fill y
cb07fc2a 2257pack $ui_comm -side left -fill y
0fb8f9ce
SP
2258pack .vpane.lower.commarea.buffer -side left -fill y
2259
0e794311
SP
2260# -- Commit Message Buffer Context Menu
2261#
2262menu $ui_comm.ctxm -tearoff 0
2263$ui_comm.ctxm add command -label "Cut" \
b4946930 2264 -font font_ui \
0e794311
SP
2265 -command "tk_textCut $ui_comm"
2266$ui_comm.ctxm add command -label "Copy" \
b4946930 2267 -font font_ui \
0e794311
SP
2268 -command "tk_textCopy $ui_comm"
2269$ui_comm.ctxm add command -label "Paste" \
b4946930 2270 -font font_ui \
0e794311
SP
2271 -command "tk_textPaste $ui_comm"
2272$ui_comm.ctxm add command -label "Delete" \
b4946930 2273 -font font_ui \
0e794311
SP
2274 -command "$ui_comm delete sel.first sel.last"
2275$ui_comm.ctxm add separator
2276$ui_comm.ctxm add command -label "Select All" \
b4946930 2277 -font font_ui \
0e794311
SP
2278 -command "$ui_comm tag add sel 0.0 end"
2279$ui_comm.ctxm add command -label "Copy All" \
b4946930 2280 -font font_ui \
0e794311
SP
2281 -command "
2282 $ui_comm tag add sel 0.0 end
2283 tk_textCopy $ui_comm
2284 $ui_comm tag remove sel 0.0 end
2285 "
2286$ui_comm.ctxm add separator
2287$ui_comm.ctxm add command -label "Sign Off" \
b4946930 2288 -font font_ui \
0e794311 2289 -command do_signoff
16fccd7a 2290bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y"
0e794311 2291
0fb8f9ce
SP
2292# -- Diff Header
2293set ui_fname_value {}
2294set ui_fstatus_value {}
2295frame .vpane.lower.diff.header -background orange
3e7b0e1d
SP
2296label .vpane.lower.diff.header.l4 \
2297 -textvariable ui_fstatus_value \
2298 -background orange \
2299 -width $max_status_desc \
2300 -anchor w \
2301 -justify left \
2302 -font font_ui
0fb8f9ce
SP
2303label .vpane.lower.diff.header.l1 -text {File:} \
2304 -background orange \
b4946930 2305 -font font_ui
c11b5f20 2306set ui_fname .vpane.lower.diff.header.l2
fce89e46
SP
2307label $ui_fname \
2308 -textvariable ui_fname_value \
0fb8f9ce 2309 -background orange \
fce89e46
SP
2310 -anchor w \
2311 -justify left \
b4946930 2312 -font font_ui
c11b5f20 2313menu $ui_fname.ctxm -tearoff 0
fce89e46 2314$ui_fname.ctxm add command -label "Copy" \
c11b5f20 2315 -font font_ui \
fce89e46
SP
2316 -command {
2317 clipboard clear
2318 clipboard append \
2319 -format STRING \
2320 -type STRING \
2321 -- $ui_fname_value
2322 }
c11b5f20 2323bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y"
3e7b0e1d 2324pack .vpane.lower.diff.header.l4 -side left
0fb8f9ce 2325pack .vpane.lower.diff.header.l1 -side left
3e7b0e1d 2326pack $ui_fname -fill x
0fb8f9ce
SP
2327
2328# -- Diff Body
2329frame .vpane.lower.diff.body
2330set ui_diff .vpane.lower.diff.body.t
2331text $ui_diff -background white -borderwidth 0 \
2332 -width 80 -height 15 -wrap none \
b4946930 2333 -font font_diff \
0fb8f9ce
SP
2334 -xscrollcommand {.vpane.lower.diff.body.sbx set} \
2335 -yscrollcommand {.vpane.lower.diff.body.sby set} \
0fb8f9ce
SP
2336 -state disabled
2337scrollbar .vpane.lower.diff.body.sbx -orient horizontal \
2338 -command [list $ui_diff xview]
2339scrollbar .vpane.lower.diff.body.sby -orient vertical \
2340 -command [list $ui_diff yview]
2341pack .vpane.lower.diff.body.sbx -side bottom -fill x
2342pack .vpane.lower.diff.body.sby -side right -fill y
2343pack $ui_diff -side left -fill both -expand 1
2344pack .vpane.lower.diff.header -side top -fill x
2345pack .vpane.lower.diff.body -side bottom -fill both -expand 1
2346
2347$ui_diff tag conf dm -foreground red
2348$ui_diff tag conf dp -foreground blue
b4946930
SP
2349$ui_diff tag conf di -foreground {#00a000}
2350$ui_diff tag conf dni -foreground {#a000a0}
2351$ui_diff tag conf da -font font_diffbold
2352$ui_diff tag conf bold -font font_diffbold
cb07fc2a 2353
0e794311
SP
2354# -- Diff Body Context Menu
2355#
2356menu $ui_diff.ctxm -tearoff 0
2357$ui_diff.ctxm add command -label "Copy" \
b4946930 2358 -font font_ui \
0e794311
SP
2359 -command "tk_textCopy $ui_diff"
2360$ui_diff.ctxm add command -label "Select All" \
b4946930 2361 -font font_ui \
0e794311
SP
2362 -command "$ui_diff tag add sel 0.0 end"
2363$ui_diff.ctxm add command -label "Copy All" \
b4946930 2364 -font font_ui \
0e794311
SP
2365 -command "
2366 $ui_diff tag add sel 0.0 end
2367 tk_textCopy $ui_diff
2368 $ui_diff tag remove sel 0.0 end
2369 "
2c26e6f5
SP
2370$ui_diff.ctxm add separator
2371$ui_diff.ctxm add command -label "Decrease Font Size" \
b4946930
SP
2372 -font font_ui \
2373 -command {incr_font_size font_diff -1}
2c26e6f5 2374$ui_diff.ctxm add command -label "Increase Font Size" \
b4946930
SP
2375 -font font_ui \
2376 -command {incr_font_size font_diff 1}
358d8de8
SP
2377$ui_diff.ctxm add separator
2378$ui_diff.ctxm add command -label "Show Less Context" \
2379 -font font_ui \
2380 -command {if {$ui_fname_value ne {}
2381 && $repo_config(gui.diffcontext) >= 2} {
2382 incr repo_config(gui.diffcontext) -1
2383 reshow_diff
2384 }}
2385$ui_diff.ctxm add command -label "Show More Context" \
2386 -font font_ui \
2387 -command {if {$ui_fname_value ne {}} {
2388 incr repo_config(gui.diffcontext)
2389 reshow_diff
2390 }}
2391$ui_diff.ctxm add separator
8009dcdc
SP
2392$ui_diff.ctxm add command -label {Options...} \
2393 -font font_ui \
2394 -command do_options
16fccd7a 2395bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y"
0e794311 2396
cb07fc2a
SP
2397# -- Status Bar
2398set ui_status_value {Initializing...}
2399label .status -textvariable ui_status_value \
2400 -anchor w \
2401 -justify left \
2402 -borderwidth 1 \
2403 -relief sunken \
b4946930 2404 -font font_ui
cb07fc2a
SP
2405pack .status -anchor w -side bottom -fill x
2406
2d19516d
SP
2407# -- Load geometry
2408catch {
51f4d16b 2409set gm $repo_config(gui.geometry)
c4fe7728
SP
2410wm geometry . [lindex $gm 0]
2411.vpane sash place 0 \
2412 [lindex [.vpane sash coord 0] 0] \
2413 [lindex $gm 1]
2414.vpane.files sash place 0 \
2415 [lindex $gm 2] \
2416 [lindex [.vpane.files sash coord 0] 1]
c4fe7728 2417unset gm
390adaea 2418}
2d19516d 2419
cb07fc2a 2420# -- Key Bindings
ec6b424a 2421bind $ui_comm <$M1B-Key-Return> {do_commit;break}
49b86f01
SP
2422bind $ui_comm <$M1B-Key-i> {do_include_all;break}
2423bind $ui_comm <$M1B-Key-I> {do_include_all;break}
9861671d
SP
2424bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break}
2425bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break}
2426bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break}
2427bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break}
2428bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break}
2429bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break}
2430bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break}
2431bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break}
2432
2433bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
2434bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
2435bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break}
2436bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break}
2437bind $ui_diff <$M1B-Key-v> {break}
2438bind $ui_diff <$M1B-Key-V> {break}
2439bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break}
2440bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break}
b2c6fcf1
SP
2441bind $ui_diff <Key-Up> {catch {%W yview scroll -1 units};break}
2442bind $ui_diff <Key-Down> {catch {%W yview scroll 1 units};break}
2443bind $ui_diff <Key-Left> {catch {%W xview scroll -1 units};break}
2444bind $ui_diff <Key-Right> {catch {%W xview scroll 1 units};break}
49b86f01 2445
07123f40
SP
2446bind . <Destroy> do_quit
2447bind all <Key-F5> do_rescan
2448bind all <$M1B-Key-r> do_rescan
2449bind all <$M1B-Key-R> do_rescan
2450bind . <$M1B-Key-s> do_signoff
2451bind . <$M1B-Key-S> do_signoff
49b86f01
SP
2452bind . <$M1B-Key-i> do_include_all
2453bind . <$M1B-Key-I> do_include_all
07123f40
SP
2454bind . <$M1B-Key-Return> do_commit
2455bind all <$M1B-Key-q> do_quit
2456bind all <$M1B-Key-Q> do_quit
2457bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
2458bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
cb07fc2a 2459foreach i [list $ui_index $ui_other] {
7d0d289e
SP
2460 bind $i <Button-1> {file_left_click %W %x %y; break}
2461 bind $i <ButtonRelease-1> {file_left_unclick %W %x %y; break}
cb07fc2a 2462}
62aac80b
SP
2463unset i
2464
2465set file_lists($ui_index) [list]
2466set file_lists($ui_other) [list]
cb07fc2a 2467
ec6b424a 2468wm title . "$appname ([file normalize [file dirname $gitdir]])"
cb07fc2a 2469focus -force $ui_comm
4ccdab02
SP
2470if {!$single_commit} {
2471 load_all_remotes
2472 populate_remote_menu .mbar.fetch From fetch_from
2473 populate_remote_menu .mbar.push To push_to
2474 populate_pull_menu .mbar.pull
2475}
4af2c384 2476after 1 update_status