2 # Tcl ignores the next line -*- tcl -*- \
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.
10 ######################################################################
14 proc load_repo_config
{} {
16 global cfg_trust_mtime
18 array
unset repo_config
20 set fd_rc
[open
"| git repo-config --list" r
]
21 while {[gets
$fd_rc line
] >= 0} {
22 if {[regexp
{^
([^
=]+)=(.
*)$
} $line line name value
]} {
23 lappend repo_config
($name) $value
29 if {[catch
{set cfg_trust_mtime \
30 [lindex
$repo_config(gui.trustmtime
) 0]
32 set cfg_trust_mtime false
36 proc save_my_config
{} {
38 global cfg_trust_mtime
40 if {[catch
{set rc_trustMTime
$repo_config(gui.trustmtime
)}]} {
41 set rc_trustMTime
[list false
]
43 if {$cfg_trust_mtime != [lindex
$rc_trustMTime 0]} {
44 exec git repo-config gui.trustMTime
$cfg_trust_mtime
45 set repo_config
(gui.trustmtime
) [list
$cfg_trust_mtime]
48 set cfg_geometry
[list \
50 [.vpane sash coord
0] \
51 [.vpane.files sash coord
0] \
53 if {[catch
{set rc_geometry
$repo_config(gui.geometry
)}]} {
54 set rc_geometry
[list
[list
]]
56 if {$cfg_geometry != [lindex
$rc_geometry 0]} {
57 exec git repo-config gui.geometry
$cfg_geometry
58 set repo_config
(gui.geometry
) [list
$cfg_geometry]
62 ######################################################################
66 set appname
[lindex
[file split $argv0] end
]
68 set GIT_COMMITTER_IDENT
{}
70 if {[catch
{set cdup
[exec git rev-parse
--show-cdup]} err
]} {
71 show_msg
{} .
"Cannot find the git directory: $err"
79 if {[catch
{set gitdir
[exec git rev-parse
--git-dir]} err
]} {
80 show_msg
{} .
"Cannot find the git directory: $err"
84 if {$appname == {git-citool
}} {
90 ######################################################################
99 set update_index_fd
{}
101 set disable_on_lock
[list
]
102 set index_lock_type none
108 proc lock_index
{type} {
109 global index_lock_type disable_on_lock
111 if {$index_lock_type == {none
}} {
112 set index_lock_type
$type
113 foreach w
$disable_on_lock {
114 uplevel
#0 $w disabled
117 } elseif
{$index_lock_type == {begin-update
} && $type == {update
}} {
118 set index_lock_type
$type
124 proc unlock_index
{} {
125 global index_lock_type disable_on_lock
127 set index_lock_type none
128 foreach w
$disable_on_lock {
133 ######################################################################
137 proc repository_state
{hdvar ctvar
} {
139 upvar
$hdvar hd
$ctvar ct
141 if {[catch
{set hd
[exec git rev-parse
--verify HEAD
]}]} {
143 } elseif
{[file exists
[file join $gitdir MERGE_HEAD
]]} {
150 proc update_status
{{final Ready.
}} {
151 global HEAD PARENT commit_type
152 global ui_index ui_other ui_status_value ui_comm
153 global status_active file_states
154 global cfg_trust_mtime
156 if {$status_active ||
![lock_index
read]} return
158 repository_state new_HEAD new_type
159 if {$commit_type == {amend
}
160 && $new_type == {normal
}
161 && $new_HEAD == $HEAD} {
165 set commit_type
$new_type
168 array
unset file_states
169 foreach w
[list
$ui_index $ui_other] {
170 $w conf
-state normal
172 $w conf
-state disabled
175 if {![$ui_comm edit modified
]
176 ||
[string trim
[$ui_comm get
0.0 end
]] == {}} {
177 if {[load_message GITGUI_MSG
]} {
178 } elseif
{[load_message MERGE_MSG
]} {
179 } elseif
{[load_message SQUASH_MSG
]} {
181 $ui_comm edit modified false
185 if {$cfg_trust_mtime == {true
}} {
186 update_status_stage2
{} $final
189 set ui_status_value
{Refreshing
file status...
}
190 set fd_rf
[open
"| git update-index -q --unmerged --refresh" r
]
191 fconfigure
$fd_rf -blocking 0 -translation binary
192 fileevent
$fd_rf readable
[list update_status_stage2
$fd_rf $final]
196 proc update_status_stage2
{fd final
} {
197 global gitdir PARENT commit_type
198 global ui_index ui_other ui_status_value ui_comm
199 global status_active file_states
200 global buf_rdi buf_rdf buf_rlo
204 if {![eof
$fd]} return
208 set ls_others
[list | git ls-files
--others -z \
209 --exclude-per-directory=.gitignore
]
210 set info_exclude
[file join $gitdir info exclude
]
211 if {[file readable
$info_exclude]} {
212 lappend ls_others
"--exclude-from=$info_exclude"
220 set ui_status_value
{Scanning
for modified files ...
}
221 set fd_di
[open
"| git diff-index --cached -z $PARENT" r
]
222 set fd_df
[open
"| git diff-files -z" r
]
223 set fd_lo
[open
$ls_others r
]
225 fconfigure
$fd_di -blocking 0 -translation binary
226 fconfigure
$fd_df -blocking 0 -translation binary
227 fconfigure
$fd_lo -blocking 0 -translation binary
228 fileevent
$fd_di readable
[list read_diff_index
$fd_di $final]
229 fileevent
$fd_df readable
[list read_diff_files
$fd_df $final]
230 fileevent
$fd_lo readable
[list read_ls_others
$fd_lo $final]
233 proc load_message
{file} {
234 global gitdir ui_comm
236 set f
[file join $gitdir $file]
237 if {[file isfile
$f]} {
238 if {[catch
{set fd
[open
$f r
]}]} {
241 set content
[string trim
[read $fd]]
243 $ui_comm delete
0.0 end
244 $ui_comm insert end
$content
250 proc read_diff_index
{fd final
} {
253 append buf_rdi
[read $fd]
255 set n
[string length
$buf_rdi]
257 set z1
[string first
"\0" $buf_rdi $c]
260 set z2
[string first
"\0" $buf_rdi $z1]
266 [string range
$buf_rdi $z1 $z2] \
267 [string index
$buf_rdi [expr $z1 - 2]]_
271 set buf_rdi
[string range
$buf_rdi $c end
]
276 status_eof
$fd buf_rdi
$final
279 proc read_diff_files
{fd final
} {
282 append buf_rdf
[read $fd]
284 set n
[string length
$buf_rdf]
286 set z1
[string first
"\0" $buf_rdf $c]
289 set z2
[string first
"\0" $buf_rdf $z1]
295 [string range
$buf_rdf $z1 $z2] \
296 _
[string index
$buf_rdf [expr $z1 - 2]]
300 set buf_rdf
[string range
$buf_rdf $c end
]
305 status_eof
$fd buf_rdf
$final
308 proc read_ls_others
{fd final
} {
311 append buf_rlo
[read $fd]
312 set pck
[split $buf_rlo "\0"]
313 set buf_rlo
[lindex
$pck end
]
314 foreach p
[lrange
$pck 0 end-1
] {
317 status_eof
$fd buf_rlo
$final
320 proc status_eof
{fd buf final
} {
321 global status_active
$buf
322 global ui_fname_value ui_status_value file_states
328 if {[incr status_active
-1] == 0} {
332 set ui_status_value
$final
334 if {$ui_fname_value != {} && [array names file_states \
335 -exact $ui_fname_value] != {}} {
336 show_diff
$ui_fname_value
344 ######################################################################
349 global ui_diff ui_fname_value ui_fstatus_value
351 $ui_diff conf
-state normal
352 $ui_diff delete
0.0 end
353 $ui_diff conf
-state disabled
354 set ui_fname_value
{}
355 set ui_fstatus_value
{}
358 proc show_diff
{path
} {
359 global file_states PARENT diff_3way diff_active
360 global ui_diff ui_fname_value ui_fstatus_value ui_status_value
362 if {$diff_active ||
![lock_index
read]} return
365 set s
$file_states($path)
369 set ui_fname_value
$path
370 set ui_fstatus_value
[mapdesc
$m $path]
371 set ui_status_value
"Loading diff of $path..."
373 set cmd
[list | git diff-index
-p $PARENT -- $path]
378 set cmd
[list | git diff-index
-p -c $PARENT $path]
382 set fd
[open
$path r
]
383 set content
[read $fd]
388 set ui_status_value
"Unable to display $path"
389 error_popup
"Error loading file:\n$err"
392 $ui_diff conf
-state normal
393 $ui_diff insert end
$content
394 $ui_diff conf
-state disabled
397 set ui_status_value
{Ready.
}
402 if {[catch
{set fd
[open
$cmd r
]} err
]} {
405 set ui_status_value
"Unable to display $path"
406 error_popup
"Error loading diff:\n$err"
410 fconfigure
$fd -blocking 0 -translation auto
411 fileevent
$fd readable
[list read_diff
$fd]
414 proc read_diff
{fd
} {
415 global ui_diff ui_status_value diff_3way diff_active
417 while {[gets
$fd line
] >= 0} {
418 if {[string match
{diff --git *} $line]} continue
419 if {[string match
{diff --combined *} $line]} continue
420 if {[string match
{--- *} $line]} continue
421 if {[string match
{+++ *} $line]} continue
422 if {[string match index
* $line]} {
423 if {[string first
, $line] >= 0} {
428 $ui_diff conf
-state normal
430 set x
[string index
$line 0]
435 default
{set tags
{}}
438 set x
[string range
$line 0 1]
440 default
{set tags
{}}
442 "++" {set tags dp
; set x
" +"}
443 " +" {set tags
{di bold
}; set x
"++"}
444 "+ " {set tags dni
; set x
"-+"}
445 "--" {set tags dm
; set x
" -"}
446 " -" {set tags
{dm bold
}; set x
"--"}
447 "- " {set tags di
; set x
"+-"}
448 default
{set tags
{}}
450 set line
[string replace
$line 0 1 $x]
452 $ui_diff insert end
$line $tags
453 $ui_diff insert end
"\n"
454 $ui_diff conf
-state disabled
461 set ui_status_value
{Ready.
}
465 ######################################################################
469 proc load_last_commit
{} {
470 global HEAD PARENT commit_type ui_comm
472 if {$commit_type == {amend
}} return
473 if {$commit_type != {normal
}} {
474 error_popup
"Can't amend a $commit_type commit."
482 set fd
[open
"| git cat-file commit $HEAD" r
]
483 while {[gets
$fd line
] > 0} {
484 if {[string match
{parent
*} $line]} {
485 set parent
[string range
$line 7 end
]
489 set msg
[string trim
[read $fd]]
492 error_popup
"Error loading commit data for amend:\n$err"
496 if {$parent_count == 0} {
497 set commit_type amend
501 } elseif
{$parent_count == 1} {
502 set commit_type amend
504 $ui_comm delete
0.0 end
505 $ui_comm insert end
$msg
506 $ui_comm edit modified false
510 error_popup
{You can
't amend a merge commit.}
515 proc commit_tree {} {
516 global tcl_platform HEAD gitdir commit_type file_states
517 global commit_active ui_status_value
520 if {$commit_active || ![lock_index update]} return
522 # -- Our in memory state should match the repository.
524 repository_state curHEAD cur_type
525 if {$commit_type == {amend}
526 && $cur_type == {normal}
527 && $curHEAD == $HEAD} {
528 } elseif {$commit_type != $cur_type || $HEAD != $curHEAD} {
529 error_popup {Last scanned state does not match repository state.
531 Its highly likely that another Git program modified the
532 repository since our last scan. A rescan is required
540 # -- At least one file should differ in the index.
543 foreach path [array names file_states] {
544 set s $file_states($path)
545 switch -glob -- [lindex $s 0] {
549 M* {set files_ready 1; break}
551 error_popup "Unmerged files cannot be committed.
553 File $path has merge conflicts.
554 You must resolve them and include the file before committing.
560 error_popup "Unknown file state [lindex $s 0] detected.
562 File $path cannot be committed by this program.
568 error_popup {No included files to commit.
570 You must include at least 1 file before you can commit.
576 # -- A message is required.
578 set msg [string trim [$ui_comm get 1.0 end]]
580 error_popup {Please supply a commit message.
582 A good commit message has the following format:
584 - First line: Describe in one sentance what you did.
586 - Remaining lines: Describe why this change is good.
592 # -- Ask the pre-commit hook for the go-ahead.
594 set pchook [file join $gitdir hooks pre-commit]
595 if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} {
596 set pchook [list sh -c \
597 "if test -x \"$pchook\"; then exec \"$pchook\"; fi"]
598 } elseif {[file executable $pchook]} {
599 set pchook [list $pchook]
603 if {$pchook != {} && [catch {eval exec $pchook} err]} {
604 hook_failed_popup pre-commit $err
609 # -- Write the tree in the background.
612 set ui_status_value {Committing changes...}
614 set fd_wt [open "| git write-tree" r]
615 fileevent $fd_wt readable [list commit_stage2 $fd_wt $curHEAD $msg]
618 proc commit_stage2 {fd_wt curHEAD msg} {
619 global single_commit gitdir PARENT commit_type
620 global commit_active ui_status_value ui_comm
625 if {$tree_id == {}} {
626 error_popup "write-tree failed"
628 set ui_status_value {Commit failed.}
633 # -- Create the commit.
635 set cmd [list git commit-tree $tree_id]
637 lappend cmd -p $PARENT
639 if {$commit_type == {merge}} {
641 set fd_mh [open [file join $gitdir MERGE_HEAD] r]
642 while {[gets $fd_mh merge_head] >= 0} {
643 lappend cmd -p $merge_head
647 error_popup "Loading MERGE_HEADs failed:\n$err"
649 set ui_status_value {Commit failed.}
655 # git commit-tree writes to stderr during initial commit.
656 lappend cmd 2>/dev/null
659 if {[catch {set cmt_id [eval exec $cmd]} err]} {
660 error_popup "commit-tree failed:\n$err"
662 set ui_status_value {Commit failed.}
667 # -- Update the HEAD ref.
670 if {$commit_type != {normal}} {
671 append reflogm " ($commit_type)"
673 set i [string first "\n" $msg]
675 append reflogm {: } [string range $msg 0 [expr $i - 1]]
677 append reflogm {: } $msg
679 set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD]
680 if {[catch {eval exec $cmd} err]} {
681 error_popup "update-ref failed:\n$err"
683 set ui_status_value {Commit failed.}
688 # -- Cleanup after ourselves.
690 catch {file delete [file join $gitdir MERGE_HEAD]}
691 catch {file delete [file join $gitdir MERGE_MSG]}
692 catch {file delete [file join $gitdir SQUASH_MSG]}
693 catch {file delete [file join $gitdir GITGUI_MSG]}
695 # -- Let rerere do its thing.
697 if {[file isdirectory [file join $gitdir rr-cache]]} {
698 catch {exec git rerere}
701 $ui_comm delete 0.0 end
702 $ui_comm edit modified false
705 if {$single_commit} do_quit
712 update_status "Changes committed as [string range $cmt_id 0 7]."
715 ######################################################################
719 proc fetch_from {remote} {
720 set w [new_console "fetch $remote" \
721 "Fetching new changes from $remote"]
722 set cmd [list git fetch]
727 proc pull_remote {remote branch} {
728 global HEAD commit_type
731 if {![lock_index update]} return
733 # -- Our in memory state should match the repository.
735 repository_state curHEAD cur_type
736 if {$commit_type != $cur_type || $HEAD != $curHEAD} {
737 error_popup {Last scanned state does not match repository state.
739 Its highly likely that another Git program modified the
740 repository since our last scan. A rescan is required
741 before a pull can be started.
748 # -- No differences should exist before a pull.
750 if {[array size file_states] != 0} {
751 error_popup {Uncommitted but modified files are present.
753 You should not perform a pull with unmodified files in your working
754 directory as Git would be unable to recover from an incorrect merge.
756 Commit or throw away all changes before starting a pull operation.
762 set w [new_console "pull $remote $branch" \
763 "Pulling new changes from branch $branch in $remote"]
764 set cmd [list git pull]
767 console_exec $w $cmd [list post_pull_remote $remote $branch]
770 proc post_pull_remote {remote branch success} {
771 global HEAD PARENT commit_type
772 global ui_status_value
776 repository_state HEAD commit_type
778 set $ui_status_value {Ready.}
780 update_status "Conflicts detected while pulling $branch from $remote."
784 proc push_to {remote} {
785 set w [new_console "push $remote" \
786 "Pushing changes to $remote"]
787 set cmd [list git push]
792 ######################################################################
796 proc mapcol {state path} {
797 global all_cols ui_other
799 if {[catch {set r $all_cols($state)}]} {
800 puts "error: no column for state={$state} $path"
806 proc mapicon {state path} {
809 if {[catch {set r $all_icons($state)}]} {
810 puts "error: no icon for state={$state} $path"
816 proc mapdesc {state path} {
819 if {[catch {set r $all_descs($state)}]} {
820 puts "error: no desc for state={$state} $path"
826 proc bsearch {w path} {
827 set hi [expr [lindex [split [$w index end] .] 0] - 2]
833 set mi [expr [expr $lo + $hi] / 2]
834 set ti [expr $mi + 1]
835 set cmp [string compare [$w get $ti.1 $ti.end] $path]
838 } elseif {$cmp == 0} {
844 return -[expr $lo + 1]
849 proc merge_state {path new_state} {
850 global file_states next_icon_id
852 set s0 [string index $new_state 0]
853 set s1 [string index $new_state 1]
855 if {[catch {set info $file_states($path)}]} {
857 set icon n[incr next_icon_id]
859 set state [lindex $info 0]
860 set icon [lindex $info 1]
864 set s0 [string index $state 0]
865 } elseif {$s0 == {*}} {
870 set s1 [string index $state 1]
871 } elseif {$s1 == {*}} {
875 set file_states($path) [list $s0$s1 $icon]
879 proc display_file {path state} {
880 global ui_index ui_other file_states status_active
882 set old_m [merge_state $path $state]
883 if {$status_active} return
885 set s $file_states($path)
886 set new_m [lindex $s 0]
887 set new_w [mapcol $new_m $path]
888 set old_w [mapcol $old_m $path]
889 set new_icon [mapicon $new_m $path]
891 if {$new_w != $old_w} {
892 set lno [bsearch $old_w $path]
895 $old_w conf -state normal
896 $old_w delete $lno.0 [expr $lno + 1].0
897 $old_w conf -state disabled
900 set lno [expr abs([bsearch $new_w $path] + 1) + 1]
901 $new_w conf -state normal
902 $new_w image create $lno.0 \
903 -align center -padx 5 -pady 1 \
904 -name [lindex $s 1] \
906 $new_w insert $lno.1 "$path\n"
907 $new_w conf -state disabled
908 } elseif {$new_icon != [mapicon $old_m $path]} {
909 $new_w conf -state normal
910 $new_w image conf [lindex $s 1] -image $new_icon
911 $new_w conf -state disabled
915 proc display_all_files {} {
916 global ui_index ui_other file_states
918 $ui_index conf -state normal
919 $ui_other conf -state normal
921 foreach path [lsort [array names file_states]] {
922 set s $file_states($path)
924 set w [mapcol $m $path]
925 $w image create end \
926 -align center -padx 5 -pady 1 \
927 -name [lindex $s 1] \
928 -image [mapicon $m $path]
929 $w insert end "$path\n"
932 $ui_index conf -state disabled
933 $ui_other conf -state disabled
936 proc with_update_index {body} {
937 global update_index_fd
939 if {$update_index_fd == {}} {
940 if {![lock_index update]} return
941 set update_index_fd [open \
942 "| git update-index --add --remove -z --stdin" \
944 fconfigure $update_index_fd -translation binary
946 close $update_index_fd
947 set update_index_fd {}
954 proc update_index {path} {
955 global update_index_fd
957 if {$update_index_fd == {}} {
958 error {not in with_update_index}
960 puts -nonewline $update_index_fd "$path\0"
964 proc toggle_mode {path} {
965 global file_states ui_fname_value
967 set s $file_states($path)
980 with_update_index {update_index $path}
981 display_file $path $new
982 if {$ui_fname_value == $path} {
987 ######################################################################
991 proc load_all_remotes {} {
992 global gitdir all_remotes repo_config
994 set all_remotes [list]
995 set rm_dir [file join $gitdir remotes]
996 if {[file isdirectory $rm_dir]} {
997 set all_remotes [concat $all_remotes [glob \
1001 -directory $rm_dir *]]
1004 foreach line [array names repo_config remote.*.url] {
1005 if {[regexp ^remote\.(.*)\.url\$ $line line name]} {
1006 lappend all_remotes $name
1010 set all_remotes [lsort -unique $all_remotes]
1013 proc populate_remote_menu {m pfx op} {
1014 global all_remotes mainfont
1016 foreach remote $all_remotes {
1017 $m add command -label "$pfx $remote..." \
1018 -command [list $op $remote] \
1023 proc populate_pull_menu {m} {
1024 global gitdir repo_config all_remotes mainfont disable_on_lock
1026 foreach remote $all_remotes {
1028 if {[array get repo_config remote.$remote.url] != {}} {
1029 if {[array get repo_config remote.$remote.fetch] != {}} {
1030 regexp {^([^:]+):} \
1031 [lindex $repo_config(remote.$remote.fetch) 0] \
1036 set fd [open [file join $gitdir remotes $remote] r]
1037 while {[gets $fd line] >= 0} {
1038 if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} {
1047 regsub ^refs/heads/ $rb {} rb_short
1048 if {$rb_short != {}} {
1050 -label "Branch $rb_short from $remote..." \
1051 -command [list pull_remote $remote $rb] \
1053 lappend disable_on_lock \
1054 [list $m entryconf [$m index last] -state]
1059 ######################################################################
1064 #define mask_width 14
1065 #define mask_height 15
1066 static unsigned char mask_bits[] = {
1067 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1068 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1069 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1072 image create bitmap file_plain -background white -foreground black -data {
1073 #define plain_width 14
1074 #define plain_height 15
1075 static unsigned char plain_bits[] = {
1076 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1077 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1078 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1079 } -maskdata $filemask
1081 image create bitmap file_mod -background white -foreground blue -data {
1082 #define mod_width 14
1083 #define mod_height 15
1084 static unsigned char mod_bits[] = {
1085 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1086 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1087 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1088 } -maskdata $filemask
1090 image create bitmap file_fulltick -background white -foreground "#007000" -data {
1091 #define file_fulltick_width 14
1092 #define file_fulltick_height 15
1093 static unsigned char file_fulltick_bits[] = {
1094 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1095 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1096 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1097 } -maskdata $filemask
1099 image create bitmap file_parttick -background white -foreground "#005050" -data {
1100 #define parttick_width 14
1101 #define parttick_height 15
1102 static unsigned char parttick_bits[] = {
1103 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1104 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1105 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1106 } -maskdata $filemask
1108 image create bitmap file_question -background white -foreground black -data {
1109 #define file_question_width 14
1110 #define file_question_height 15
1111 static unsigned char file_question_bits[] = {
1112 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1113 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1114 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1115 } -maskdata $filemask
1117 image create bitmap file_removed -background white -foreground red -data {
1118 #define file_removed_width 14
1119 #define file_removed_height 15
1120 static unsigned char file_removed_bits[] = {
1121 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1122 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1123 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1124 } -maskdata $filemask
1126 image create bitmap file_merge -background white -foreground blue -data {
1127 #define file_merge_width 14
1128 #define file_merge_height 15
1129 static unsigned char file_merge_bits[] = {
1130 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1131 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1132 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1133 } -maskdata $filemask
1135 set ui_index .vpane.files.index.list
1136 set ui_other .vpane.files.other.list
1137 set max_status_desc 0
1139 {__ i plain "Unmodified"}
1140 {_M i mod "Modified"}
1141 {M_ i fulltick "Checked in"}
1142 {MM i parttick "Partially included"}
1144 {_O o plain "Untracked"}
1145 {A_ o fulltick "Added"}
1146 {AM o parttick "Partially added"}
1147 {AD o question "Added (but now gone)"}
1149 {_D i question "Missing"}
1150 {D_ i removed "Removed"}
1151 {DD i removed "Removed"}
1152 {DO i removed "Removed (still exists)"}
1154 {UM i merge "Merge conflicts"}
1155 {U_ i merge "Merge conflicts"}
1157 if {$max_status_desc < [string length [lindex $i 3]]} {
1158 set max_status_desc [string length [lindex $i 3]]
1160 if {[lindex $i 1] == {i}} {
1161 set all_cols([lindex $i 0]) $ui_index
1163 set all_cols([lindex $i 0]) $ui_other
1165 set all_icons([lindex $i 0]) file_[lindex $i 2]
1166 set all_descs([lindex $i 0]) [lindex $i 3]
1170 ######################################################################
1174 proc error_popup {msg} {
1181 proc show_msg {w top msg} {
1182 global gitdir appname mainfont
1184 message $w.m -text $msg -justify left -aspect 400
1185 pack $w.m -side top -fill x -padx 5 -pady 10
1186 button $w.ok -text OK \
1189 -command "destroy $top"
1190 pack $w.ok -side bottom
1191 bind $top <Visibility> "grab $top; focus $top"
1192 bind $top <Key-Return> "destroy $top"
1193 wm title $w "$appname ([lindex [file split \
1194 [file normalize [file dirname $gitdir]]] \
1199 proc hook_failed_popup {hook msg} {
1200 global gitdir mainfont difffont appname
1207 label $w.m.l1 -text "$hook hook failed:" \
1210 -font [concat $mainfont bold]
1212 -background white -borderwidth 1 \
1214 -width 80 -height 10 \
1216 -yscrollcommand [list $w.m.sby set]
1218 -text {You must correct the above errors before committing.} \
1221 -font [concat $mainfont bold]
1222 scrollbar $w.m.sby -command [list $w.m.t yview]
1223 pack $w.m.l1 -side top -fill x
1224 pack $w.m.l2 -side bottom -fill x
1225 pack $w.m.sby -side right -fill y
1226 pack $w.m.t -side left -fill both -expand 1
1227 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
1229 $w.m.t insert 1.0 $msg
1230 $w.m.t conf -state disabled
1232 button $w.ok -text OK \
1235 -command "destroy $w"
1236 pack $w.ok -side bottom
1238 bind $w <Visibility> "grab $w; focus $w"
1239 bind $w <Key-Return> "destroy $w"
1240 wm title $w "$appname ([lindex [file split \
1241 [file normalize [file dirname $gitdir]]] \
1246 set next_console_id 0
1248 proc new_console {short_title long_title} {
1249 global next_console_id console_data
1250 set w .console[incr next_console_id]
1251 set console_data($w) [list $short_title $long_title]
1252 return [console_init $w]
1255 proc console_init {w} {
1256 global console_cr console_data
1257 global gitdir appname mainfont difffont
1259 set console_cr($w) 1.0
1262 label $w.m.l1 -text "[lindex $console_data($w) 1]:" \
1265 -font [concat $mainfont bold]
1267 -background white -borderwidth 1 \
1269 -width 80 -height 10 \
1272 -yscrollcommand [list $w.m.sby set]
1273 label $w.m.s -anchor w \
1275 -font [concat $mainfont bold]
1276 scrollbar $w.m.sby -command [list $w.m.t yview]
1277 pack $w.m.l1 -side top -fill x
1278 pack $w.m.s -side bottom -fill x
1279 pack $w.m.sby -side right -fill y
1280 pack $w.m.t -side left -fill both -expand 1
1281 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
1283 button $w.ok -text {Running...} \
1287 -command "destroy $w"
1288 pack $w.ok -side bottom
1290 bind $w <Visibility> "focus $w"
1291 wm title $w "$appname ([lindex [file split \
1292 [file normalize [file dirname $gitdir]]] \
1293 end]): [lindex $console_data($w) 0]"
1297 proc console_exec {w cmd {after {}}} {
1300 # -- Windows tosses the enviroment when we exec our child.
1301 # But most users need that so we have to relogin. :-(
1303 if {$tcl_platform(platform) == {windows}} {
1304 set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"]
1307 # -- Tcl won't
let us redirect both stdout and stderr to
1308 # the same pipe. So pass it through cat...
1310 set cmd
[concat |
$cmd |
& cat]
1312 set fd_f
[open
$cmd r
]
1313 fconfigure
$fd_f -blocking 0 -translation binary
1314 fileevent
$fd_f readable
[list console_read
$w $fd_f $after]
1317 proc console_read
{w fd after
} {
1318 global console_cr console_data
1322 if {![winfo exists
$w]} {console_init
$w}
1323 $w.m.t conf
-state normal
1325 set n
[string length
$buf]
1327 set cr
[string first
"\r" $buf $c]
1328 set lf
[string first
"\n" $buf $c]
1329 if {$cr < 0} {set cr
[expr $n + 1]}
1330 if {$lf < 0} {set lf
[expr $n + 1]}
1333 $w.m.t insert end
[string range
$buf $c $lf]
1334 set console_cr
($w) [$w.m.t index
{end
-1c}]
1338 $w.m.t delete
$console_cr($w) end
1339 $w.m.t insert end
"\n"
1340 $w.m.t insert end
[string range
$buf $c $cr]
1345 $w.m.t conf
-state disabled
1349 fconfigure
$fd -blocking 1
1351 if {[catch
{close
$fd}]} {
1352 if {![winfo exists
$w]} {console_init
$w}
1353 $w.m.s conf
-background red
-text {Error
: Command Failed
}
1354 $w.ok conf
-text Close
1355 $w.ok conf
-state normal
1357 } elseif
{[winfo exists
$w]} {
1358 $w.m.s conf
-background green
-text {Success
}
1359 $w.ok conf
-text Close
1360 $w.ok conf
-state normal
1363 array
unset console_cr
$w
1364 array
unset console_data
$w
1366 uplevel
#0 $after $ok
1370 fconfigure
$fd -blocking 0
1373 ######################################################################
1377 set starting_gitk_msg
{Please
wait... Starting gitk...
}
1380 global tcl_platform ui_status_value starting_gitk_msg
1382 set ui_status_value
$starting_gitk_msg
1384 if {$ui_status_value == $starting_gitk_msg} {
1385 set ui_status_value
{Ready.
}
1389 if {$tcl_platform(platform
) == {windows
}} {
1397 set w
[new_console
"repack" "Repacking the object database"]
1398 set cmd
[list git repack
]
1401 console_exec
$w $cmd
1405 global gitdir ui_comm
1407 set save
[file join $gitdir GITGUI_MSG
]
1408 set msg
[string trim
[$ui_comm get
0.0 end
]]
1409 if {[$ui_comm edit modified
] && $msg != {}} {
1411 set fd
[open
$save w
]
1412 puts
$fd [string trim
[$ui_comm get
0.0 end
]]
1415 } elseif
{$msg == {} && [file exists
$save]} {
1427 proc do_include_all
{} {
1428 global update_active ui_status_value
1430 if {$update_active ||
![lock_index begin-update
]} return
1433 set ui_status_value
{Including all modified files...
}
1436 foreach path
[array names file_states
] {
1437 set s
$file_states($path)
1443 _D
{toggle_mode
$path}
1448 set ui_status_value
{Ready.
}
1452 proc do_signoff
{} {
1453 global ui_comm GIT_COMMITTER_IDENT
1455 if {$GIT_COMMITTER_IDENT == {}} {
1456 if {[catch
{set me
[exec git var GIT_COMMITTER_IDENT
]} err
]} {
1457 error_popup
"Unable to obtain your identity:\n$err"
1460 if {![regexp
{^
(.
*) [0-9]+ [-+0-9]+$
} \
1461 $me me GIT_COMMITTER_IDENT
]} {
1462 error_popup
"Invalid GIT_COMMITTER_IDENT:\n$me"
1467 set str
"Signed-off-by: $GIT_COMMITTER_IDENT"
1468 if {[$ui_comm get
{end
-1c linestart
} {end
-1c}] != $str} {
1469 $ui_comm edit separator
1470 $ui_comm insert end
"\n$str"
1471 $ui_comm edit separator
1476 proc do_amend_last
{} {
1484 # shift == 1: left click
1486 proc click
{w x y
shift wx wy
} {
1487 global ui_index ui_other
1489 set pos
[split [$w index @
$x,$y] .
]
1490 set lno
[lindex
$pos 0]
1491 set col [lindex
$pos 1]
1492 set path
[$w get
$lno.1 $lno.end
]
1493 if {$path == {}} return
1495 if {$col > 0 && $shift == 1} {
1496 $ui_index tag remove in_diff
0.0 end
1497 $ui_other tag remove in_diff
0.0 end
1498 $w tag add in_diff
$lno.0 [expr $lno + 1].0
1503 proc unclick
{w x y
} {
1504 set pos
[split [$w index @
$x,$y] .
]
1505 set lno
[lindex
$pos 0]
1506 set col [lindex
$pos 1]
1507 set path
[$w get
$lno.1 $lno.end
]
1508 if {$path == {}} return
1515 ######################################################################
1519 set mainfont
{Helvetica
10}
1520 set difffont
{Courier
10}
1521 set maincursor
[. cget
-cursor]
1523 switch
-glob -- "$tcl_platform(platform),$tcl_platform(os)" {
1524 windows
,* {set M1B Control
; set M1T Ctrl
}
1525 unix
,Darwin
{set M1B M1
; set M1T Cmd
}
1526 default
{set M1B M1
; set M1T M1
}
1530 menu .mbar
-tearoff 0
1531 .mbar add cascade
-label Project
-menu .mbar.project
1532 .mbar add cascade
-label Edit
-menu .mbar.edit
1533 .mbar add cascade
-label Commit
-menu .mbar.commit
1534 .mbar add cascade
-label Fetch
-menu .mbar.fetch
1535 .mbar add cascade
-label Pull
-menu .mbar.pull
1536 .mbar add cascade
-label Push
-menu .mbar.push
1537 .mbar add cascade
-label Options
-menu .mbar.options
1538 . configure
-menu .mbar
1542 .mbar.project add
command -label Visualize \
1545 .mbar.project add
command -label {Repack Database
} \
1546 -command do_repack \
1548 .mbar.project add
command -label Quit \
1550 -accelerator $M1T-Q \
1556 .mbar.edit add
command -label Undo \
1557 -command {catch
{[focus
] edit undo
}} \
1558 -accelerator $M1T-Z \
1560 .mbar.edit add
command -label Redo \
1561 -command {catch
{[focus
] edit redo
}} \
1562 -accelerator $M1T-Y \
1564 .mbar.edit add separator
1565 .mbar.edit add
command -label Cut \
1566 -command {catch
{tk_textCut
[focus
]}} \
1567 -accelerator $M1T-X \
1569 .mbar.edit add
command -label Copy \
1570 -command {catch
{tk_textCopy
[focus
]}} \
1571 -accelerator $M1T-C \
1573 .mbar.edit add
command -label Paste \
1574 -command {catch
{tk_textPaste
[focus
]; [focus
] see insert
}} \
1575 -accelerator $M1T-V \
1577 .mbar.edit add
command -label Delete \
1578 -command {catch
{[focus
] delete sel.first sel.last
}} \
1581 .mbar.edit add separator
1582 .mbar.edit add
command -label {Select All
} \
1583 -command {catch
{[focus
] tag add sel
0.0 end
}} \
1584 -accelerator $M1T-A \
1589 .mbar.commit add
command -label Rescan \
1590 -command do_rescan \
1593 lappend disable_on_lock \
1594 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1595 .mbar.commit add
command -label {Amend Last Commit
} \
1596 -command do_amend_last \
1598 lappend disable_on_lock \
1599 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1600 .mbar.commit add
command -label {Include All Files
} \
1601 -command do_include_all \
1602 -accelerator $M1T-I \
1604 lappend disable_on_lock \
1605 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1606 .mbar.commit add
command -label {Sign Off
} \
1607 -command do_signoff \
1608 -accelerator $M1T-S \
1610 .mbar.commit add
command -label Commit \
1611 -command do_commit \
1612 -accelerator $M1T-Return \
1614 lappend disable_on_lock \
1615 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1628 .mbar.options add checkbutton \
1629 -label {Trust File Modification Timestamps
} \
1632 -variable cfg_trust_mtime
1634 # -- Main Window Layout
1635 panedwindow .vpane
-orient vertical
1636 panedwindow .vpane.files
-orient horizontal
1637 .vpane add .vpane.files
-sticky nsew
-height 100 -width 400
1638 pack .vpane
-anchor n
-side top
-fill both
-expand 1
1640 # -- Index File List
1641 frame .vpane.files.index
-height 100 -width 400
1642 label .vpane.files.index.title
-text {Modified Files
} \
1645 text
$ui_index -background white
-borderwidth 0 \
1646 -width 40 -height 10 \
1648 -yscrollcommand {.vpane.files.index.sb
set} \
1649 -cursor $maincursor \
1651 scrollbar .vpane.files.index.sb
-command [list
$ui_index yview
]
1652 pack .vpane.files.index.title
-side top
-fill x
1653 pack .vpane.files.index.sb
-side right
-fill y
1654 pack
$ui_index -side left
-fill both
-expand 1
1655 .vpane.files add .vpane.files.index
-sticky nsew
1657 # -- Other (Add) File List
1658 frame .vpane.files.other
-height 100 -width 100
1659 label .vpane.files.other.title
-text {Untracked Files
} \
1662 text
$ui_other -background white
-borderwidth 0 \
1663 -width 40 -height 10 \
1665 -yscrollcommand {.vpane.files.other.sb
set} \
1666 -cursor $maincursor \
1668 scrollbar .vpane.files.other.sb
-command [list
$ui_other yview
]
1669 pack .vpane.files.other.title
-side top
-fill x
1670 pack .vpane.files.other.sb
-side right
-fill y
1671 pack
$ui_other -side left
-fill both
-expand 1
1672 .vpane.files add .vpane.files.other
-sticky nsew
1674 $ui_index tag conf in_diff
-font [concat
$mainfont bold
]
1675 $ui_other tag conf in_diff
-font [concat
$mainfont bold
]
1677 # -- Diff and Commit Area
1678 frame .vpane.lower
-height 400 -width 400
1679 frame .vpane.lower.commarea
1680 frame .vpane.lower.
diff -relief sunken
-borderwidth 1
1681 pack .vpane.lower.commarea
-side top
-fill x
1682 pack .vpane.lower.
diff -side bottom
-fill both
-expand 1
1683 .vpane add .vpane.lower
-stick nsew
1685 # -- Commit Area Buttons
1686 frame .vpane.lower.commarea.buttons
1687 label .vpane.lower.commarea.buttons.l
-text {} \
1691 pack .vpane.lower.commarea.buttons.l
-side top
-fill x
1692 pack .vpane.lower.commarea.buttons
-side left
-fill y
1694 button .vpane.lower.commarea.buttons.rescan
-text {Rescan
} \
1695 -command do_rescan \
1697 pack .vpane.lower.commarea.buttons.rescan
-side top
-fill x
1698 lappend disable_on_lock
{.vpane.lower.commarea.buttons.rescan conf
-state}
1700 button .vpane.lower.commarea.buttons.amend
-text {Amend Last
} \
1701 -command do_amend_last \
1703 pack .vpane.lower.commarea.buttons.amend
-side top
-fill x
1704 lappend disable_on_lock
{.vpane.lower.commarea.buttons.amend conf
-state}
1706 button .vpane.lower.commarea.buttons.incall
-text {Include All
} \
1707 -command do_include_all \
1709 pack .vpane.lower.commarea.buttons.incall
-side top
-fill x
1710 lappend disable_on_lock
{.vpane.lower.commarea.buttons.incall conf
-state}
1712 button .vpane.lower.commarea.buttons.signoff
-text {Sign Off
} \
1713 -command do_signoff \
1715 pack .vpane.lower.commarea.buttons.signoff
-side top
-fill x
1717 button .vpane.lower.commarea.buttons.commit
-text {Commit
} \
1718 -command do_commit \
1720 pack .vpane.lower.commarea.buttons.commit
-side top
-fill x
1721 lappend disable_on_lock
{.vpane.lower.commarea.buttons.commit conf
-state}
1723 # -- Commit Message Buffer
1724 frame .vpane.lower.commarea.buffer
1725 set ui_comm .vpane.lower.commarea.buffer.t
1726 set ui_coml .vpane.lower.commarea.buffer.l
1727 label
$ui_coml -text {Commit Message
:} \
1731 trace add variable commit_type
write {uplevel
#0 {
1732 switch
-glob $commit_type \
1733 initial
{$ui_coml conf
-text {Initial Commit Message
:}} \
1734 amend
{$ui_coml conf
-text {Amended Commit Message
:}} \
1735 merge
{$ui_coml conf
-text {Merge Commit Message
:}} \
1736 * {$ui_coml conf
-text {Commit Message
:}}
1738 text
$ui_comm -background white
-borderwidth 1 \
1741 -autoseparators true \
1743 -width 75 -height 9 -wrap none \
1745 -yscrollcommand {.vpane.lower.commarea.buffer.sby
set} \
1747 scrollbar .vpane.lower.commarea.buffer.sby
-command [list
$ui_comm yview
]
1748 pack
$ui_coml -side top
-fill x
1749 pack .vpane.lower.commarea.buffer.sby
-side right
-fill y
1750 pack
$ui_comm -side left
-fill y
1751 pack .vpane.lower.commarea.buffer
-side left
-fill y
1754 set ui_fname_value
{}
1755 set ui_fstatus_value
{}
1756 frame .vpane.lower.
diff.header
-background orange
1757 label .vpane.lower.
diff.header.l1
-text {File
:} \
1758 -background orange \
1760 label .vpane.lower.
diff.header.l2
-textvariable ui_fname_value \
1761 -background orange \
1765 label .vpane.lower.
diff.header.l3
-text {Status
:} \
1766 -background orange \
1768 label .vpane.lower.
diff.header.l4
-textvariable ui_fstatus_value \
1769 -background orange \
1770 -width $max_status_desc \
1774 pack .vpane.lower.
diff.header.l1
-side left
1775 pack .vpane.lower.
diff.header.l2
-side left
-fill x
1776 pack .vpane.lower.
diff.header.l4
-side right
1777 pack .vpane.lower.
diff.header.l3
-side right
1780 frame .vpane.lower.
diff.body
1781 set ui_diff .vpane.lower.
diff.body.t
1782 text
$ui_diff -background white
-borderwidth 0 \
1783 -width 80 -height 15 -wrap none \
1785 -xscrollcommand {.vpane.lower.
diff.body.sbx
set} \
1786 -yscrollcommand {.vpane.lower.
diff.body.sby
set} \
1787 -cursor $maincursor \
1789 scrollbar .vpane.lower.
diff.body.sbx
-orient horizontal \
1790 -command [list
$ui_diff xview
]
1791 scrollbar .vpane.lower.
diff.body.sby
-orient vertical \
1792 -command [list
$ui_diff yview
]
1793 pack .vpane.lower.
diff.body.sbx
-side bottom
-fill x
1794 pack .vpane.lower.
diff.body.sby
-side right
-fill y
1795 pack
$ui_diff -side left
-fill both
-expand 1
1796 pack .vpane.lower.
diff.header
-side top
-fill x
1797 pack .vpane.lower.
diff.body
-side bottom
-fill both
-expand 1
1799 $ui_diff tag conf dm
-foreground red
1800 $ui_diff tag conf dp
-foreground blue
1801 $ui_diff tag conf da
-font [concat
$difffont bold
]
1802 $ui_diff tag conf di
-foreground "#00a000"
1803 $ui_diff tag conf dni
-foreground "#a000a0"
1804 $ui_diff tag conf bold
-font [concat
$difffont bold
]
1807 set ui_status_value
{Initializing...
}
1808 label .status
-textvariable ui_status_value \
1814 pack .status
-anchor w
-side bottom
-fill x
1818 wm geometry .
[lindex
$repo_config(gui.geometry
) 0 0]
1819 eval .vpane sash place
0 [lindex
$repo_config(gui.geometry
) 0 1]
1820 eval .vpane.files sash place
0 [lindex
$repo_config(gui.geometry
) 0 2]
1824 bind $ui_comm <$M1B-Key-Return> {do_commit
;break}
1825 bind $ui_comm <$M1B-Key-i> {do_include_all
;break}
1826 bind $ui_comm <$M1B-Key-I> {do_include_all
;break}
1827 bind $ui_comm <$M1B-Key-x> {tk_textCut
%W
;break}
1828 bind $ui_comm <$M1B-Key-X> {tk_textCut
%W
;break}
1829 bind $ui_comm <$M1B-Key-c> {tk_textCopy
%W
;break}
1830 bind $ui_comm <$M1B-Key-C> {tk_textCopy
%W
;break}
1831 bind $ui_comm <$M1B-Key-v> {tk_textPaste
%W
; %W see insert
; break}
1832 bind $ui_comm <$M1B-Key-V> {tk_textPaste
%W
; %W see insert
; break}
1833 bind $ui_comm <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
1834 bind $ui_comm <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
1836 bind $ui_diff <$M1B-Key-x> {tk_textCopy
%W
;break}
1837 bind $ui_diff <$M1B-Key-X> {tk_textCopy
%W
;break}
1838 bind $ui_diff <$M1B-Key-c> {tk_textCopy
%W
;break}
1839 bind $ui_diff <$M1B-Key-C> {tk_textCopy
%W
;break}
1840 bind $ui_diff <$M1B-Key-v> {break}
1841 bind $ui_diff <$M1B-Key-V> {break}
1842 bind $ui_diff <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
1843 bind $ui_diff <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
1844 bind $ui_diff <Key-Up
> {catch
{%W yview scroll
-1 units
};break}
1845 bind $ui_diff <Key-Down
> {catch
{%W yview scroll
1 units
};break}
1846 bind $ui_diff <Key-Left
> {catch
{%W xview scroll
-1 units
};break}
1847 bind $ui_diff <Key-Right
> {catch
{%W xview scroll
1 units
};break}
1849 bind .
<Destroy
> do_quit
1850 bind all
<Key-F5
> do_rescan
1851 bind all
<$M1B-Key-r> do_rescan
1852 bind all
<$M1B-Key-R> do_rescan
1853 bind .
<$M1B-Key-s> do_signoff
1854 bind .
<$M1B-Key-S> do_signoff
1855 bind .
<$M1B-Key-i> do_include_all
1856 bind .
<$M1B-Key-I> do_include_all
1857 bind .
<$M1B-Key-Return> do_commit
1858 bind all
<$M1B-Key-q> do_quit
1859 bind all
<$M1B-Key-Q> do_quit
1860 bind all
<$M1B-Key-w> {destroy
[winfo toplevel
%W
]}
1861 bind all
<$M1B-Key-W> {destroy
[winfo toplevel
%W
]}
1862 foreach i
[list
$ui_index $ui_other] {
1863 bind $i <Button-1
> {click
%W
%x
%y
1 %X
%Y
; break}
1864 bind $i <Button-3
> {click
%W
%x
%y
3 %X
%Y
; break}
1865 bind $i <ButtonRelease-1
> {unclick
%W
%x
%y
; break}
1869 wm title .
"$appname ([file normalize [file dirname $gitdir]])"
1870 focus
-force $ui_comm
1872 populate_remote_menu .mbar.fetch From fetch_from
1873 populate_remote_menu .mbar.push To push_to
1874 populate_pull_menu .mbar.pull