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 set appname
[lindex
[file split $argv0] end
]
13 ######################################################################
17 proc is_many_config
{name
} {
18 switch
-glob -- $name {
27 proc load_config
{include_global
} {
28 global repo_config global_config default_config
30 array
unset global_config
31 if {$include_global} {
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
39 set global_config
($name) $value
47 array
unset repo_config
49 set fd_rc
[open
"| git repo-config --list" r
]
50 while {[gets
$fd_rc line
] >= 0} {
51 if {[regexp
{^
([^
=]+)=(.
*)$
} $line line name value
]} {
52 if {[is_many_config
$name]} {
53 lappend repo_config
($name) $value
55 set repo_config
($name) $value
62 foreach name
[array names default_config
] {
63 if {[catch
{set v
$global_config($name)}]} {
64 set global_config
($name) $default_config($name)
66 if {[catch
{set v
$repo_config($name)}]} {
67 set repo_config
($name) $default_config($name)
73 global default_config font_descs
74 global repo_config global_config
75 global repo_config_new global_config_new
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
)
91 foreach name
[array names default_config
] {
92 set value
$global_config_new($name)
93 if {$value ne
$global_config($name)} {
94 if {$value eq
$default_config($name)} {
95 catch
{exec git repo-config
--global --unset $name}
97 regsub
-all "\[{}\]" $value {"} value
98 exec git repo-config --global $name $value
100 set global_config($name) $value
101 if {$value eq $repo_config($name)} {
102 catch {exec git repo-config --unset $name}
103 set repo_config($name) $value
108 foreach name [array names default_config] {
109 set value $repo_config_new($name)
110 if {$value ne $repo_config($name)} {
111 if {$value eq $global_config($name)} {
112 catch {exec git repo-config --unset $name}
114 regsub -all "\
[{}\
]" $value {"} value
115 exec git repo-config
$name $value
117 set repo_config
($name) $value
122 proc error_popup
{msg
} {
123 global gitdir appname
128 append title
[lindex \
129 [file split [file normalize
[file dirname $gitdir]]] \
133 set cmd
[list tk_messageBox \
136 -title "$title: error" \
138 if {[winfo ismapped .
]} {
139 lappend cmd
-parent .
144 proc info_popup
{msg
} {
145 global gitdir appname
150 append title
[lindex \
151 [file split [file normalize
[file dirname $gitdir]]] \
163 ######################################################################
167 if { [catch
{set gitdir
$env(GIT_DIR
)}]
168 && [catch
{set gitdir
[exec git rev-parse
--git-dir]} err
]} {
169 catch
{wm withdraw .
}
170 error_popup
"Cannot find the git directory:\n\n$err"
173 if {![file isdirectory
$gitdir]} {
174 catch
{wm withdraw .
}
175 error_popup
"Git directory not found:\n\n$gitdir"
178 if {[lindex
[file split $gitdir] end
] ne
{.git
}} {
179 catch
{wm withdraw .
}
180 error_popup
"Cannot use funny .git directory:\n\n$gitdir"
183 if {[catch
{cd [file dirname $gitdir]} err
]} {
184 catch
{wm withdraw .
}
185 error_popup
"No working directory [file dirname $gitdir]:\n\n$err"
190 if {$appname eq
{git-citool
}} {
194 ######################################################################
202 set disable_on_lock
[list
]
203 set index_lock_type none
205 proc lock_index
{type} {
206 global index_lock_type disable_on_lock
208 if {$index_lock_type eq
{none
}} {
209 set index_lock_type
$type
210 foreach w
$disable_on_lock {
211 uplevel
#0 $w disabled
214 } elseif
{$index_lock_type eq
"begin-$type"} {
215 set index_lock_type
$type
221 proc unlock_index
{} {
222 global index_lock_type disable_on_lock
224 set index_lock_type none
225 foreach w
$disable_on_lock {
230 ######################################################################
234 proc repository_state
{hdvar ctvar
} {
236 upvar
$hdvar hd
$ctvar ct
238 if {[catch
{set hd
[exec git rev-parse
--verify HEAD
]}]} {
241 } elseif
{[file exists
[file join $gitdir MERGE_HEAD
]]} {
249 global PARENT empty_tree
254 if {$empty_tree eq
{}} {
255 set empty_tree
[exec git mktree
<< {}]
260 proc rescan
{after
} {
261 global HEAD PARENT commit_type
262 global ui_index ui_other ui_status_value ui_comm
263 global rescan_active file_states
266 if {$rescan_active > 0 ||
![lock_index
read]} return
268 repository_state new_HEAD new_type
269 if {[string match amend
* $commit_type]
270 && $new_type eq
{normal
}
271 && $new_HEAD eq
$HEAD} {
275 set commit_type
$new_type
278 array
unset file_states
280 if {![$ui_comm edit modified
]
281 ||
[string trim
[$ui_comm get
0.0 end
]] eq
{}} {
282 if {[load_message GITGUI_MSG
]} {
283 } elseif
{[load_message MERGE_MSG
]} {
284 } elseif
{[load_message SQUASH_MSG
]} {
286 $ui_comm edit modified false
290 if {$repo_config(gui.trustmtime
) eq
{true
}} {
291 rescan_stage2
{} $after
294 set ui_status_value
{Refreshing
file status...
}
295 set cmd
[list git update-index
]
297 lappend cmd
--unmerged
298 lappend cmd
--ignore-missing
299 lappend cmd
--refresh
300 set fd_rf
[open
"| $cmd" r
]
301 fconfigure
$fd_rf -blocking 0 -translation binary
302 fileevent
$fd_rf readable \
303 [list rescan_stage2
$fd_rf $after]
307 proc rescan_stage2
{fd after
} {
308 global gitdir ui_status_value
309 global rescan_active buf_rdi buf_rdf buf_rlo
313 if {![eof
$fd]} return
317 set ls_others
[list | git ls-files
--others -z \
318 --exclude-per-directory=.gitignore
]
319 set info_exclude
[file join $gitdir info exclude
]
320 if {[file readable
$info_exclude]} {
321 lappend ls_others
"--exclude-from=$info_exclude"
329 set ui_status_value
{Scanning
for modified files ...
}
330 set fd_di
[open
"| git diff-index --cached -z [PARENT]" r
]
331 set fd_df
[open
"| git diff-files -z" r
]
332 set fd_lo
[open
$ls_others r
]
334 fconfigure
$fd_di -blocking 0 -translation binary
335 fconfigure
$fd_df -blocking 0 -translation binary
336 fconfigure
$fd_lo -blocking 0 -translation binary
337 fileevent
$fd_di readable
[list read_diff_index
$fd_di $after]
338 fileevent
$fd_df readable
[list read_diff_files
$fd_df $after]
339 fileevent
$fd_lo readable
[list read_ls_others
$fd_lo $after]
342 proc load_message
{file} {
343 global gitdir ui_comm
345 set f
[file join $gitdir $file]
346 if {[file isfile
$f]} {
347 if {[catch
{set fd
[open
$f r
]}]} {
350 set content
[string trim
[read $fd]]
352 $ui_comm delete
0.0 end
353 $ui_comm insert end
$content
359 proc read_diff_index
{fd after
} {
362 append buf_rdi
[read $fd]
364 set n
[string length
$buf_rdi]
366 set z1
[string first
"\0" $buf_rdi $c]
369 set z2
[string first
"\0" $buf_rdi $z1]
375 [string range
$buf_rdi $z1 $z2] \
376 [string index
$buf_rdi [expr {$z1 - 2}]]?
380 set buf_rdi
[string range
$buf_rdi $c end
]
385 rescan_done
$fd buf_rdi
$after
388 proc read_diff_files
{fd after
} {
391 append buf_rdf
[read $fd]
393 set n
[string length
$buf_rdf]
395 set z1
[string first
"\0" $buf_rdf $c]
398 set z2
[string first
"\0" $buf_rdf $z1]
404 [string range
$buf_rdf $z1 $z2] \
405 ?
[string index
$buf_rdf [expr {$z1 - 2}]]
409 set buf_rdf
[string range
$buf_rdf $c end
]
414 rescan_done
$fd buf_rdf
$after
417 proc read_ls_others
{fd after
} {
420 append buf_rlo
[read $fd]
421 set pck
[split $buf_rlo "\0"]
422 set buf_rlo
[lindex
$pck end
]
423 foreach p
[lrange
$pck 0 end-1
] {
426 rescan_done
$fd buf_rlo
$after
429 proc rescan_done
{fd buf after
} {
431 global file_states repo_config
434 if {![eof
$fd]} return
437 if {[incr rescan_active
-1] > 0} return
443 if {$repo_config(gui.partialinclude
) ne
{true
}} {
445 foreach path
[array names file_states
] {
446 switch
-- [lindex
$file_states($path) 0] {
448 MM
{lappend pathList
$path}
451 if {$pathList ne
{}} {
453 "Updating included files" \
455 [concat
{reshow_diff
;} $after]
464 proc prune_selection
{} {
465 global file_states selected_paths
467 foreach path
[array names selected_paths
] {
468 if {[catch
{set still_here
$file_states($path)}]} {
469 unset selected_paths
($path)
474 ######################################################################
479 global ui_diff current_diff ui_index ui_other
481 $ui_diff conf
-state normal
482 $ui_diff delete
0.0 end
483 $ui_diff conf
-state disabled
487 $ui_index tag remove in_diff
0.0 end
488 $ui_other tag remove in_diff
0.0 end
491 proc reshow_diff
{} {
492 global current_diff ui_status_value file_states
494 if {$current_diff eq
{}
495 ||
[catch
{set s
$file_states($current_diff)}]} {
498 show_diff
$current_diff
502 proc handle_empty_diff
{} {
503 global current_diff file_states file_lists
505 set path
$current_diff
506 set s
$file_states($path)
507 if {[lindex
$s 0] ne
{_M
}} return
509 info_popup
"No differences detected.
511 [short_path $path] has no changes.
513 The modification date of this file was updated
514 by another application and you currently have
515 the Trust File Modification Timestamps option
516 enabled, so Git did not automatically detect
517 that there are no content differences in this
520 This file will now be removed from the modified
521 files list, to prevent possible confusion.
523 if {[catch
{exec git update-index
-- $path} err
]} {
524 error_popup
"Failed to refresh index:\n\n$err"
528 set old_w
[mapcol
[lindex
$file_states($path) 0] $path]
529 set lno
[lsearch
-sorted $file_lists($old_w) $path]
531 set file_lists
($old_w) \
532 [lreplace
$file_lists($old_w) $lno $lno]
534 $old_w conf
-state normal
535 $old_w delete
$lno.0 [expr {$lno + 1}].0
536 $old_w conf
-state disabled
540 proc show_diff
{path
{w
{}} {lno
{}}} {
541 global file_states file_lists
542 global diff_3way diff_active repo_config
543 global ui_diff current_diff ui_status_value
545 if {$diff_active ||
![lock_index
read]} return
548 if {$w eq
{} ||
$lno == {}} {
549 foreach w
[array names file_lists
] {
550 set lno
[lsearch
-sorted $file_lists($w) $path]
557 if {$w ne
{} && $lno >= 1} {
558 $w tag add in_diff
$lno.0 [expr {$lno + 1}].0
561 set s
$file_states($path)
565 set current_diff
$path
566 set ui_status_value
"Loading diff of [escape_path $path]..."
568 set cmd
[list | git diff-index
]
569 lappend cmd
--no-color
570 if {$repo_config(gui.diffcontext
) > 0} {
571 lappend cmd
"-U$repo_config(gui.diffcontext)"
581 set fd
[open
$path r
]
582 set content
[read $fd]
587 set ui_status_value
"Unable to display [escape_path $path]"
588 error_popup
"Error loading file:\n\n$err"
591 $ui_diff conf
-state normal
592 $ui_diff insert end
$content
593 $ui_diff conf
-state disabled
596 set ui_status_value
{Ready.
}
605 if {[catch
{set fd
[open
$cmd r
]} err
]} {
608 set ui_status_value
"Unable to display [escape_path $path]"
609 error_popup
"Error loading diff:\n\n$err"
613 fconfigure
$fd -blocking 0 -translation auto
614 fileevent
$fd readable
[list read_diff
$fd]
617 proc read_diff
{fd
} {
618 global ui_diff ui_status_value diff_3way diff_active
621 while {[gets
$fd line
] >= 0} {
622 if {[string match
{diff --git *} $line]} continue
623 if {[string match
{diff --combined *} $line]} continue
624 if {[string match
{--- *} $line]} continue
625 if {[string match
{+++ *} $line]} continue
626 if {[string match index
* $line]} {
627 if {[string first
, $line] >= 0} {
632 $ui_diff conf
-state normal
634 set x
[string index
$line 0]
639 default
{set tags
{}}
642 set x
[string range
$line 0 1]
644 default
{set tags
{}}
646 "++" {set tags dp
; set x
" +"}
647 " +" {set tags
{di bold
}; set x
"++"}
648 "+ " {set tags dni
; set x
"-+"}
649 "--" {set tags dm
; set x
" -"}
650 " -" {set tags
{dm bold
}; set x
"--"}
651 "- " {set tags di
; set x
"+-"}
652 default
{set tags
{}}
654 set line
[string replace
$line 0 1 $x]
656 $ui_diff insert end
$line $tags
657 $ui_diff insert end
"\n"
658 $ui_diff conf
-state disabled
665 set ui_status_value
{Ready.
}
667 if {$repo_config(gui.trustmtime
) eq
{true
}
668 && [$ui_diff index end
] eq
{2.0}} {
674 ######################################################################
678 proc load_last_commit
{} {
679 global HEAD PARENT commit_type ui_comm
681 if {[string match amend
* $commit_type]} return
682 if {$commit_type ne
{normal
}} {
683 error_popup
"Can't amend a $commit_type commit."
691 set fd
[open
"| git cat-file commit $HEAD" r
]
692 while {[gets
$fd line
] > 0} {
693 if {[string match
{parent
*} $line]} {
694 set parent
[string range
$line 7 end
]
698 set msg
[string trim
[read $fd]]
701 error_popup
"Error loading commit data for amend:\n\n$err"
705 if {$parent_count > 1} {
706 error_popup
{Can
't amend a merge commit.}
710 if {$parent_count == 0} {
711 set commit_type amend-initial
713 } elseif {$parent_count == 1} {
714 set commit_type amend
718 $ui_comm delete 0.0 end
719 $ui_comm insert end $msg
720 $ui_comm edit modified false
722 rescan {set ui_status_value {Ready.}}
725 proc create_new_commit {} {
726 global commit_type ui_comm
728 set commit_type normal
729 $ui_comm delete 0.0 end
730 $ui_comm edit modified false
732 rescan {set ui_status_value {Ready.}}
735 set GIT_COMMITTER_IDENT {}
737 proc committer_ident {} {
738 global GIT_COMMITTER_IDENT
740 if {$GIT_COMMITTER_IDENT eq {}} {
741 if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
742 error_popup "Unable to obtain your identity:\n\n$err"
745 if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \
746 $me me GIT_COMMITTER_IDENT]} {
747 error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me"
752 return $GIT_COMMITTER_IDENT
755 proc commit_tree {} {
756 global HEAD commit_type file_states ui_comm repo_config
758 if {![lock_index update]} return
759 if {[committer_ident] eq {}} return
761 # -- Our in memory state should match the repository.
763 repository_state curHEAD cur_type
764 if {[string match amend* $commit_type]
765 && $cur_type eq {normal}
766 && $curHEAD eq $HEAD} {
767 } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
768 error_popup {Last scanned state does not match repository state.
770 Its highly likely that another Git program modified the
771 repository since the last scan. A rescan is required
774 A rescan will be automatically started now.
777 rescan {set ui_status_value {Ready.}}
781 # -- At least one file should differ in the index.
784 foreach path [array names file_states] {
785 switch -glob -- [lindex $file_states($path) 0] {
789 M? {set files_ready 1; break}
791 error_popup "Unmerged files cannot be committed.
793 File [short_path $path] has merge conflicts.
794 You must resolve them and include the file before committing.
800 error_popup "Unknown file state [lindex $s 0] detected.
802 File [short_path $path] cannot be committed by this program.
808 error_popup {No included files to commit.
810 You must include at least 1 file before you can commit.
816 # -- A message is required.
818 set msg [string trim [$ui_comm get 1.0 end]]
820 error_popup {Please supply a commit message.
822 A good commit message has the following format:
824 - First line: Describe in one sentance what you did.
826 - Remaining lines: Describe why this change is good.
832 # -- Update included files if partialincludes are off.
834 if {$repo_config(gui.partialinclude) ne {true}} {
836 foreach path [array names file_states] {
837 switch -glob -- [lindex $file_states($path) 0] {
839 M? {lappend pathList $path}
842 if {$pathList ne {}} {
845 "Updating included files" \
847 [concat {lock_index update;} \
848 [list commit_prehook $curHEAD $msg]]
853 commit_prehook $curHEAD $msg
856 proc commit_prehook {curHEAD msg} {
857 global tcl_platform gitdir ui_status_value pch_error
859 # On Cygwin [file executable] might lie so we need to ask
860 # the shell if the hook is executable. Yes that's annoying.
862 set pchook
[file join $gitdir hooks pre-commit
]
863 if {$tcl_platform(platform
) eq
{windows
}
864 && [file isfile
$pchook]} {
865 set pchook
[list sh
-c [concat \
866 "if test -x \"$pchook\";" \
867 "then exec \"$pchook\" 2>&1;" \
869 } elseif
{[file executable
$pchook]} {
870 set pchook
[list
$pchook |
& cat]
872 commit_writetree
$curHEAD $msg
876 set ui_status_value
{Calling pre-commit hook...
}
878 set fd_ph
[open
"| $pchook" r
]
879 fconfigure
$fd_ph -blocking 0 -translation binary
880 fileevent
$fd_ph readable \
881 [list commit_prehook_wait
$fd_ph $curHEAD $msg]
884 proc commit_prehook_wait
{fd_ph curHEAD msg
} {
885 global pch_error ui_status_value
887 append pch_error
[read $fd_ph]
888 fconfigure
$fd_ph -blocking 1
890 if {[catch
{close
$fd_ph}]} {
891 set ui_status_value
{Commit declined by pre-commit hook.
}
892 hook_failed_popup pre-commit
$pch_error
895 commit_writetree
$curHEAD $msg
900 fconfigure
$fd_ph -blocking 0
903 proc commit_writetree
{curHEAD msg
} {
904 global ui_status_value
906 set ui_status_value
{Committing changes...
}
907 set fd_wt
[open
"| git write-tree" r
]
908 fileevent
$fd_wt readable \
909 [list commit_committree
$fd_wt $curHEAD $msg]
912 proc commit_committree
{fd_wt curHEAD msg
} {
913 global single_commit gitdir HEAD PARENT commit_type tcl_platform
914 global ui_status_value ui_comm selected_commit_type
915 global file_states selected_paths
918 if {$tree_id eq
{} ||
[catch
{close
$fd_wt} err
]} {
919 error_popup
"write-tree failed:\n\n$err"
920 set ui_status_value
{Commit failed.
}
925 # -- Create the commit.
927 set cmd
[list git commit-tree
$tree_id]
929 lappend cmd
-p $PARENT
931 if {$commit_type eq
{merge
}} {
933 set fd_mh
[open
[file join $gitdir MERGE_HEAD
] r
]
934 while {[gets
$fd_mh merge_head
] >= 0} {
935 lappend cmd
-p $merge_head
939 error_popup
"Loading MERGE_HEAD failed:\n\n$err"
940 set ui_status_value
{Commit failed.
}
946 # git commit-tree writes to stderr during initial commit.
947 lappend cmd
2>/dev
/null
950 if {[catch
{set cmt_id
[eval exec $cmd]} err
]} {
951 error_popup
"commit-tree failed:\n\n$err"
952 set ui_status_value
{Commit failed.
}
957 # -- Update the HEAD ref.
960 if {$commit_type ne
{normal
}} {
961 append reflogm
" ($commit_type)"
963 set i
[string first
"\n" $msg]
965 append reflogm
{: } [string range
$msg 0 [expr {$i - 1}]]
967 append reflogm
{: } $msg
969 set cmd
[list git update-ref
-m $reflogm HEAD
$cmt_id $curHEAD]
970 if {[catch
{eval exec $cmd} err
]} {
971 error_popup
"update-ref failed:\n\n$err"
972 set ui_status_value
{Commit failed.
}
977 # -- Cleanup after ourselves.
979 catch
{file delete
[file join $gitdir MERGE_HEAD
]}
980 catch
{file delete
[file join $gitdir MERGE_MSG
]}
981 catch
{file delete
[file join $gitdir SQUASH_MSG
]}
982 catch
{file delete
[file join $gitdir GITGUI_MSG
]}
984 # -- Let rerere do its thing.
986 if {[file isdirectory
[file join $gitdir rr-cache
]]} {
987 catch
{exec git rerere
}
990 # -- Run the post-commit hook.
992 set pchook
[file join $gitdir hooks post-commit
]
993 if {$tcl_platform(platform
) eq
{windows
} && [file isfile
$pchook]} {
994 set pchook
[list sh
-c [concat \
995 "if test -x \"$pchook\";" \
996 "then exec \"$pchook\";" \
998 } elseif
{![file executable
$pchook]} {
1001 if {$pchook ne
{}} {
1002 catch
{exec $pchook &}
1005 $ui_comm delete
0.0 end
1006 $ui_comm edit modified false
1009 if {$single_commit} do_quit
1011 # -- Update status without invoking any git commands.
1013 set commit_type normal
1014 set selected_commit_type new
1018 foreach path
[array names file_states
] {
1019 set s
$file_states($path)
1021 switch
-glob -- $m {
1024 D?
{set m _
[string index
$m 1]}
1028 unset file_states
($path)
1029 catch
{unset selected_paths
($path)}
1031 lset file_states
($path) 0 $m
1038 set ui_status_value \
1039 "Changes committed as [string range $cmt_id 0 7]."
1042 ######################################################################
1046 proc fetch_from
{remote
} {
1047 set w
[new_console
"fetch $remote" \
1048 "Fetching new changes from $remote"]
1049 set cmd
[list git fetch
]
1051 console_exec
$w $cmd
1054 proc pull_remote
{remote branch
} {
1055 global HEAD commit_type file_states repo_config
1057 if {![lock_index update
]} return
1059 # -- Our in memory state should match the repository.
1061 repository_state curHEAD cur_type
1062 if {$commit_type ne
$cur_type ||
$HEAD ne
$curHEAD} {
1063 error_popup
{Last scanned state does not match repository state.
1065 Its highly likely that another Git program modified the
1066 repository since our last scan. A rescan is required
1067 before a pull can be started.
1070 rescan
{set ui_status_value
{Ready.
}}
1074 # -- No differences should exist before a pull.
1076 if {[array size file_states
] != 0} {
1077 error_popup
{Uncommitted but modified files are present.
1079 You should not perform a pull with unmodified files
in your working
1080 directory as Git would be unable to recover from an incorrect merge.
1082 Commit or throw away all changes before starting a pull operation.
1088 set w
[new_console
"pull $remote $branch" \
1089 "Pulling new changes from branch $branch in $remote"]
1090 set cmd
[list git pull
]
1091 if {$repo_config(gui.pullsummary
) eq
{false
}} {
1092 lappend cmd
--no-summary
1096 console_exec
$w $cmd [list post_pull_remote
$remote $branch]
1099 proc post_pull_remote
{remote branch success
} {
1100 global HEAD PARENT commit_type selected_commit_type
1101 global ui_status_value
1105 repository_state HEAD commit_type
1107 set selected_commit_type new
1108 set $ui_status_value "Pulling $branch from $remote complete."
1110 set m
"Conflicts detected while pulling $branch from $remote."
1111 rescan
"set ui_status_value {$m}"
1115 proc push_to
{remote
} {
1116 set w
[new_console
"push $remote" \
1117 "Pushing changes to $remote"]
1118 set cmd
[list git push
]
1120 console_exec
$w $cmd
1123 ######################################################################
1127 proc mapcol
{state path
} {
1128 global all_cols ui_other
1130 if {[catch
{set r
$all_cols($state)}]} {
1131 puts
"error: no column for state={$state} $path"
1137 proc mapicon
{state path
} {
1140 if {[catch
{set r
$all_icons($state)}]} {
1141 puts
"error: no icon for state={$state} $path"
1147 proc mapdesc
{state path
} {
1150 if {[catch
{set r
$all_descs($state)}]} {
1151 puts
"error: no desc for state={$state} $path"
1157 proc escape_path
{path
} {
1158 regsub
-all "\n" $path "\\n" path
1162 proc short_path
{path
} {
1163 return [escape_path
[lindex
[file split $path] end
]]
1168 proc merge_state
{path new_state
} {
1169 global file_states next_icon_id
1171 set s0
[string index
$new_state 0]
1172 set s1
[string index
$new_state 1]
1174 if {[catch
{set info
$file_states($path)}]} {
1176 set icon n
[incr next_icon_id
]
1178 set state
[lindex
$info 0]
1179 set icon
[lindex
$info 1]
1183 set s0
[string index
$state 0]
1184 } elseif
{$s0 eq
{_
}} {
1189 set s1
[string index
$state 1]
1190 } elseif
{$s1 eq
{_
}} {
1194 set file_states
($path) [list
$s0$s1 $icon]
1198 proc display_file
{path state
} {
1199 global file_states file_lists selected_paths rescan_active
1201 set old_m
[merge_state
$path $state]
1202 if {$rescan_active > 0} return
1204 set s
$file_states($path)
1205 set new_m
[lindex
$s 0]
1206 set new_w
[mapcol
$new_m $path]
1207 set old_w
[mapcol
$old_m $path]
1208 set new_icon
[mapicon
$new_m $path]
1210 if {$new_w ne
$old_w} {
1211 set lno
[lsearch
-sorted $file_lists($old_w) $path]
1214 $old_w conf
-state normal
1215 $old_w delete
$lno.0 [expr {$lno + 1}].0
1216 $old_w conf
-state disabled
1219 lappend file_lists
($new_w) $path
1220 set file_lists
($new_w) [lsort
$file_lists($new_w)]
1221 set lno
[lsearch
-sorted $file_lists($new_w) $path]
1223 $new_w conf
-state normal
1224 $new_w image create
$lno.0 \
1225 -align center
-padx 5 -pady 1 \
1226 -name [lindex
$s 1] \
1228 $new_w insert
$lno.1 "[escape_path $path]\n"
1229 if {[catch
{set in_sel
$selected_paths($path)}]} {
1233 $new_w tag add in_sel
$lno.0 [expr {$lno + 1}].0
1235 $new_w conf
-state disabled
1236 } elseif
{$new_icon ne
[mapicon
$old_m $path]} {
1237 $new_w conf
-state normal
1238 $new_w image conf
[lindex
$s 1] -image $new_icon
1239 $new_w conf
-state disabled
1243 proc display_all_files
{} {
1244 global ui_index ui_other
1245 global file_states file_lists
1246 global last_clicked selected_paths
1248 $ui_index conf
-state normal
1249 $ui_other conf
-state normal
1251 $ui_index delete
0.0 end
1252 $ui_other delete
0.0 end
1255 set file_lists
($ui_index) [list
]
1256 set file_lists
($ui_other) [list
]
1258 foreach path
[lsort
[array names file_states
]] {
1259 set s
$file_states($path)
1261 set w
[mapcol
$m $path]
1262 lappend file_lists
($w) $path
1263 set lno
[expr {[lindex
[split [$w index end
] .
] 0] - 1}]
1264 $w image create end \
1265 -align center
-padx 5 -pady 1 \
1266 -name [lindex
$s 1] \
1267 -image [mapicon
$m $path]
1268 $w insert end
"[escape_path $path]\n"
1269 if {[catch
{set in_sel
$selected_paths($path)}]} {
1273 $w tag add in_sel
$lno.0 [expr {$lno + 1}].0
1277 $ui_index conf
-state disabled
1278 $ui_other conf
-state disabled
1281 proc update_index
{msg pathList after
} {
1282 global update_index_cp ui_status_value
1284 if {![lock_index update
]} return
1286 set update_index_cp
0
1287 set pathList
[lsort
$pathList]
1288 set totalCnt
[llength
$pathList]
1289 set batch [expr {int
($totalCnt * .01) + 1}]
1290 if {$batch > 25} {set batch 25}
1292 set ui_status_value
[format \
1293 "$msg... %i/%i files (%.2f%%)" \
1297 set fd
[open
"| git update-index --add --remove -z --stdin" w
]
1303 fileevent
$fd writable
[list \
1304 write_update_index \
1314 proc write_update_index
{fd pathList totalCnt
batch msg after
} {
1315 global update_index_cp ui_status_value
1316 global file_states current_diff
1318 if {$update_index_cp >= $totalCnt} {
1325 for {set i
$batch} \
1326 {$update_index_cp < $totalCnt && $i > 0} \
1328 set path
[lindex
$pathList $update_index_cp]
1329 incr update_index_cp
1331 switch
-glob -- [lindex
$file_states($path) 0] {
1347 puts
-nonewline $fd $path
1348 puts
-nonewline $fd "\0"
1349 display_file
$path $new
1352 set ui_status_value
[format \
1353 "$msg... %i/%i files (%.2f%%)" \
1356 [expr {100.0 * $update_index_cp / $totalCnt}]]
1359 ######################################################################
1361 ## remote management
1363 proc load_all_remotes
{} {
1364 global gitdir all_remotes repo_config
1366 set all_remotes
[list
]
1367 set rm_dir
[file join $gitdir remotes
]
1368 if {[file isdirectory
$rm_dir]} {
1369 set all_remotes
[concat
$all_remotes [glob \
1373 -directory $rm_dir *]]
1376 foreach line
[array names repo_config remote.
*.url
] {
1377 if {[regexp ^remote\.
(.
*)\.url\$
$line line name
]} {
1378 lappend all_remotes
$name
1382 set all_remotes
[lsort
-unique $all_remotes]
1385 proc populate_fetch_menu
{m
} {
1386 global gitdir all_remotes repo_config
1388 foreach r
$all_remotes {
1390 if {![catch
{set a
$repo_config(remote.
$r.url
)}]} {
1391 if {![catch
{set a
$repo_config(remote.
$r.fetch
)}]} {
1396 set fd
[open
[file join $gitdir remotes
$r] r
]
1397 while {[gets
$fd n
] >= 0} {
1398 if {[regexp
{^Pull
:[ \t]*([^
:]+):} $n]} {
1409 -label "Fetch from $r..." \
1410 -command [list fetch_from
$r] \
1416 proc populate_push_menu
{m
} {
1417 global gitdir all_remotes repo_config
1419 foreach r
$all_remotes {
1421 if {![catch
{set a
$repo_config(remote.
$r.url
)}]} {
1422 if {![catch
{set a
$repo_config(remote.
$r.push
)}]} {
1427 set fd
[open
[file join $gitdir remotes
$r] r
]
1428 while {[gets
$fd n
] >= 0} {
1429 if {[regexp
{^Push
:[ \t]*([^
:]+):} $n]} {
1440 -label "Push to $r..." \
1441 -command [list push_to
$r] \
1447 proc populate_pull_menu
{m
} {
1448 global gitdir repo_config all_remotes disable_on_lock
1450 foreach remote
$all_remotes {
1452 if {[array get repo_config remote.
$remote.url
] ne
{}} {
1453 if {[array get repo_config remote.
$remote.fetch
] ne
{}} {
1454 regexp
{^
([^
:]+):} \
1455 [lindex
$repo_config(remote.
$remote.fetch
) 0] \
1460 set fd
[open
[file join $gitdir remotes
$remote] r
]
1461 while {[gets
$fd line
] >= 0} {
1462 if {[regexp
{^Pull
:[ \t]*([^
:]+):} $line line rb
]} {
1471 regsub ^refs
/heads
/ $rb {} rb_short
1472 if {$rb_short ne
{}} {
1474 -label "Branch $rb_short from $remote..." \
1475 -command [list pull_remote
$remote $rb] \
1477 lappend disable_on_lock \
1478 [list
$m entryconf
[$m index last
] -state]
1483 ######################################################################
1488 #define mask_width 14
1489 #define mask_height 15
1490 static unsigned char mask_bits
[] = {
1491 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1492 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1493 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1496 image create bitmap file_plain
-background white
-foreground black
-data {
1497 #define plain_width 14
1498 #define plain_height 15
1499 static unsigned char plain_bits
[] = {
1500 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1501 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1502 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1503 } -maskdata $filemask
1505 image create bitmap file_mod
-background white
-foreground blue
-data {
1506 #define mod_width 14
1507 #define mod_height 15
1508 static unsigned char mod_bits
[] = {
1509 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1510 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1511 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1512 } -maskdata $filemask
1514 image create bitmap file_fulltick
-background white
-foreground "#007000" -data {
1515 #define file_fulltick_width 14
1516 #define file_fulltick_height 15
1517 static unsigned char file_fulltick_bits
[] = {
1518 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1519 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1520 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1521 } -maskdata $filemask
1523 image create bitmap file_parttick
-background white
-foreground "#005050" -data {
1524 #define parttick_width 14
1525 #define parttick_height 15
1526 static unsigned char parttick_bits
[] = {
1527 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1528 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1529 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1530 } -maskdata $filemask
1532 image create bitmap file_question
-background white
-foreground black
-data {
1533 #define file_question_width 14
1534 #define file_question_height 15
1535 static unsigned char file_question_bits
[] = {
1536 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1537 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1538 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1539 } -maskdata $filemask
1541 image create bitmap file_removed
-background white
-foreground red
-data {
1542 #define file_removed_width 14
1543 #define file_removed_height 15
1544 static unsigned char file_removed_bits
[] = {
1545 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1546 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1547 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1548 } -maskdata $filemask
1550 image create bitmap file_merge
-background white
-foreground blue
-data {
1551 #define file_merge_width 14
1552 #define file_merge_height 15
1553 static unsigned char file_merge_bits
[] = {
1554 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1555 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1556 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1557 } -maskdata $filemask
1559 set ui_index .vpane.files.index.list
1560 set ui_other .vpane.files.other.list
1561 set max_status_desc
0
1563 {__ i plain
"Unmodified"}
1564 {_M i mod
"Modified"}
1565 {M_ i fulltick
"Included in commit"}
1566 {MM i parttick
"Partially included"}
1568 {_O o plain
"Untracked"}
1569 {A_ o fulltick
"Added by commit"}
1570 {AM o parttick
"Partially added"}
1571 {AD o question
"Added (but now gone)"}
1573 {_D i question
"Missing"}
1574 {D_ i removed
"Removed by commit"}
1575 {DD i removed
"Removed by commit"}
1576 {DO i removed
"Removed (still exists)"}
1578 {UM i merge
"Merge conflicts"}
1579 {U_ i merge
"Merge conflicts"}
1581 if {$max_status_desc < [string length
[lindex
$i 3]]} {
1582 set max_status_desc
[string length
[lindex
$i 3]]
1584 if {[lindex
$i 1] eq
{i
}} {
1585 set all_cols
([lindex
$i 0]) $ui_index
1587 set all_cols
([lindex
$i 0]) $ui_other
1589 set all_icons
([lindex
$i 0]) file_
[lindex
$i 2]
1590 set all_descs
([lindex
$i 0]) [lindex
$i 3]
1594 ######################################################################
1599 global tcl_platform tk_library
1600 if {$tcl_platform(platform
) eq
{unix
}
1601 && $tcl_platform(os
) eq
{Darwin
}
1602 && [string match
/Library
/Frameworks
/* $tk_library]} {
1608 proc bind_button3
{w cmd
} {
1609 bind $w <Any-Button-3
> $cmd
1611 bind $w <Control-Button-1
> $cmd
1615 proc incr_font_size
{font
{amt
1}} {
1616 set sz
[font configure
$font -size]
1618 font configure
$font -size $sz
1619 font configure
${font}bold
-size $sz
1622 proc hook_failed_popup
{hook msg
} {
1623 global gitdir appname
1629 label
$w.m.l1
-text "$hook hook failed:" \
1634 -background white
-borderwidth 1 \
1636 -width 80 -height 10 \
1638 -yscrollcommand [list
$w.m.sby
set]
1640 -text {You must correct the above errors before committing.
} \
1644 scrollbar
$w.m.sby
-command [list
$w.m.t yview
]
1645 pack
$w.m.l1
-side top
-fill x
1646 pack
$w.m.l2
-side bottom
-fill x
1647 pack
$w.m.sby
-side right
-fill y
1648 pack
$w.m.t
-side left
-fill both
-expand 1
1649 pack
$w.m
-side top
-fill both
-expand 1 -padx 5 -pady 10
1651 $w.m.t insert
1.0 $msg
1652 $w.m.t conf
-state disabled
1654 button
$w.ok
-text OK \
1657 -command "destroy $w"
1658 pack
$w.ok
-side bottom
-anchor e
-pady 10 -padx 10
1660 bind $w <Visibility
> "grab $w; focus $w"
1661 bind $w <Key-Return
> "destroy $w"
1662 wm title
$w "$appname ([lindex [file split \
1663 [file normalize [file dirname $gitdir]]] \
1668 set next_console_id
0
1670 proc new_console
{short_title long_title
} {
1671 global next_console_id console_data
1672 set w .console
[incr next_console_id
]
1673 set console_data
($w) [list
$short_title $long_title]
1674 return [console_init
$w]
1677 proc console_init
{w
} {
1678 global console_cr console_data
1679 global gitdir appname M1B
1681 set console_cr
($w) 1.0
1684 label
$w.m.l1
-text "[lindex $console_data($w) 1]:" \
1689 -background white
-borderwidth 1 \
1691 -width 80 -height 10 \
1694 -yscrollcommand [list
$w.m.sby
set]
1695 label
$w.m.s
-text {Working... please
wait...
} \
1699 scrollbar
$w.m.sby
-command [list
$w.m.t yview
]
1700 pack
$w.m.l1
-side top
-fill x
1701 pack
$w.m.s
-side bottom
-fill x
1702 pack
$w.m.sby
-side right
-fill y
1703 pack
$w.m.t
-side left
-fill both
-expand 1
1704 pack
$w.m
-side top
-fill both
-expand 1 -padx 5 -pady 10
1706 menu
$w.ctxm
-tearoff 0
1707 $w.ctxm add
command -label "Copy" \
1709 -command "tk_textCopy $w.m.t"
1710 $w.ctxm add
command -label "Select All" \
1712 -command "$w.m.t tag add sel 0.0 end"
1713 $w.ctxm add
command -label "Copy All" \
1716 $w.m.t tag add sel 0.0 end
1718 $w.m.t tag remove sel 0.0 end
1721 button
$w.ok
-text {Close
} \
1724 -command "destroy $w"
1725 pack
$w.ok
-side bottom
-anchor e
-pady 10 -padx 10
1727 bind_button3
$w.m.t
"tk_popup $w.ctxm %X %Y"
1728 bind $w.m.t
<$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break"
1729 bind $w.m.t
<$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break"
1730 bind $w <Visibility
> "focus $w"
1731 wm title
$w "$appname ([lindex [file split \
1732 [file normalize [file dirname $gitdir]]] \
1733 end]): [lindex $console_data($w) 0]"
1737 proc console_exec
{w cmd
{after
{}}} {
1740 # -- Windows tosses the enviroment when we exec our child.
1741 # But most users need that so we have to relogin. :-(
1743 if {$tcl_platform(platform
) eq
{windows
}} {
1744 set cmd
[list sh
--login -c "cd \"[pwd]\" && [join $cmd { }]"]
1747 # -- Tcl won't let us redirect both stdout and stderr to
1748 # the same pipe. So pass it through cat...
1750 set cmd
[concat |
$cmd |
& cat]
1752 set fd_f
[open
$cmd r
]
1753 fconfigure
$fd_f -blocking 0 -translation binary
1754 fileevent
$fd_f readable
[list console_read
$w $fd_f $after]
1757 proc console_read
{w fd after
} {
1758 global console_cr console_data
1762 if {![winfo exists
$w]} {console_init
$w}
1763 $w.m.t conf
-state normal
1765 set n
[string length
$buf]
1767 set cr
[string first
"\r" $buf $c]
1768 set lf
[string first
"\n" $buf $c]
1769 if {$cr < 0} {set cr
[expr {$n + 1}]}
1770 if {$lf < 0} {set lf
[expr {$n + 1}]}
1773 $w.m.t insert end
[string range
$buf $c $lf]
1774 set console_cr
($w) [$w.m.t index
{end
-1c}]
1778 $w.m.t delete
$console_cr($w) end
1779 $w.m.t insert end
"\n"
1780 $w.m.t insert end
[string range
$buf $c $cr]
1785 $w.m.t conf
-state disabled
1789 fconfigure
$fd -blocking 1
1791 if {[catch
{close
$fd}]} {
1792 if {![winfo exists
$w]} {console_init
$w}
1793 $w.m.s conf
-background red
-text {Error
: Command Failed
}
1794 $w.ok conf
-state normal
1796 } elseif
{[winfo exists
$w]} {
1797 $w.m.s conf
-background green
-text {Success
}
1798 $w.ok conf
-state normal
1801 array
unset console_cr
$w
1802 array
unset console_data
$w
1804 uplevel
#0 $after $ok
1808 fconfigure
$fd -blocking 0
1811 ######################################################################
1815 set starting_gitk_msg
{Please
wait... Starting gitk...
}
1818 global tcl_platform ui_status_value starting_gitk_msg
1820 set ui_status_value
$starting_gitk_msg
1822 if {$ui_status_value eq
$starting_gitk_msg} {
1823 set ui_status_value
{Ready.
}
1827 if {$tcl_platform(platform
) eq
{windows
}} {
1835 set w
[new_console
"repack" "Repacking the object database"]
1836 set cmd
[list git repack
]
1839 console_exec
$w $cmd
1845 global gitdir ui_comm is_quitting repo_config
1847 if {$is_quitting} return
1850 # -- Stash our current commit buffer.
1852 set save
[file join $gitdir GITGUI_MSG
]
1853 set msg
[string trim
[$ui_comm get
0.0 end
]]
1854 if {[$ui_comm edit modified
] && $msg ne
{}} {
1856 set fd
[open
$save w
]
1857 puts
$fd [string trim
[$ui_comm get
0.0 end
]]
1860 } elseif
{$msg eq
{} && [file exists
$save]} {
1864 # -- Stash our current window geometry into this repository.
1866 set cfg_geometry
[list
]
1867 lappend cfg_geometry
[wm geometry .
]
1868 lappend cfg_geometry
[lindex
[.vpane sash coord
0] 1]
1869 lappend cfg_geometry
[lindex
[.vpane.files sash coord
0] 0]
1870 if {[catch
{set rc_geometry
$repo_config(gui.geometry
)}]} {
1873 if {$cfg_geometry ne
$rc_geometry} {
1874 catch
{exec git repo-config gui.geometry
$cfg_geometry}
1881 rescan
{set ui_status_value
{Ready.
}}
1884 proc include_helper
{txt paths
} {
1885 global file_states current_diff
1887 if {![lock_index begin-update
]} return
1891 foreach path
$paths {
1892 switch
-- [lindex
$file_states($path) 0] {
1897 lappend pathList
$path
1898 if {$path eq
$current_diff} {
1899 set after
{reshow_diff
;}
1904 if {$pathList eq
{}} {
1910 [concat
$after {set ui_status_value
{Ready to commit.
}}]
1914 proc do_include_selection
{} {
1915 global current_diff selected_paths
1917 if {[array size selected_paths
] > 0} {
1919 {Including selected files
} \
1920 [array names selected_paths
]
1921 } elseif
{$current_diff ne
{}} {
1923 "Including [short_path $current_diff]" \
1924 [list
$current_diff]
1928 proc do_include_all
{} {
1931 {Including all modified files
} \
1932 [array names file_states
]
1935 proc do_signoff
{} {
1938 set me
[committer_ident
]
1939 if {$me eq
{}} return
1941 set sob
"Signed-off-by: $me"
1942 set last
[$ui_comm get
{end
-1c linestart
} {end
-1c}]
1943 if {$last ne
$sob} {
1944 $ui_comm edit separator
1946 && ![regexp
{^
[A-Z
][A-Za-z
]*-[A-Za-z-
]+: *} $last]} {
1947 $ui_comm insert end
"\n"
1949 $ui_comm insert end
"\n$sob"
1950 $ui_comm edit separator
1955 proc do_select_commit_type
{} {
1956 global commit_type selected_commit_type
1958 if {$selected_commit_type eq
{new
}
1959 && [string match amend
* $commit_type]} {
1961 } elseif
{$selected_commit_type eq
{amend
}
1962 && ![string match amend
* $commit_type]} {
1965 # The amend request was rejected...
1967 if {![string match amend
* $commit_type]} {
1977 proc do_options
{} {
1978 global appname gitdir font_descs
1979 global repo_config global_config
1980 global repo_config_new global_config_new
1982 array
unset repo_config_new
1983 array
unset global_config_new
1984 foreach name
[array names repo_config
] {
1985 set repo_config_new
($name) $repo_config($name)
1988 foreach name
[array names repo_config
] {
1990 gui.diffcontext
{continue}
1992 set repo_config_new
($name) $repo_config($name)
1994 foreach name
[array names global_config
] {
1995 set global_config_new
($name) $global_config($name)
1997 set reponame
[lindex
[file split \
1998 [file normalize
[file dirname $gitdir]]] \
2001 set w .options_editor
2003 wm geometry
$w "+[winfo rootx .]+[winfo rooty .]"
2005 label
$w.header
-text "$appname Options" \
2007 pack
$w.header
-side top
-fill x
2010 button
$w.buttons.restore
-text {Restore Defaults
} \
2012 -command do_restore_defaults
2013 pack
$w.buttons.restore
-side left
2014 button
$w.buttons.save
-text Save \
2016 -command [list do_save_config
$w]
2017 pack
$w.buttons.save
-side right
2018 button
$w.buttons.cancel
-text {Cancel
} \
2020 -command [list destroy
$w]
2021 pack
$w.buttons.cancel
-side right
2022 pack
$w.buttons
-side bottom
-fill x
-pady 10 -padx 10
2024 labelframe
$w.repo
-text "$reponame Repository" \
2026 -relief raised
-borderwidth 2
2027 labelframe
$w.global
-text {Global
(All Repositories
)} \
2029 -relief raised
-borderwidth 2
2030 pack
$w.repo
-side left
-fill both
-expand 1 -pady 5 -padx 5
2031 pack
$w.global
-side right
-fill both
-expand 1 -pady 5 -padx 5
2034 {b partialinclude
{Allow Partially Included Files
}}
2035 {b pullsummary
{Show Pull Summary
}}
2036 {b trustmtime
{Trust File Modification Timestamps
}}
2037 {i diffcontext
{Number of Diff Context Lines
}}
2039 set type [lindex
$option 0]
2040 set name
[lindex
$option 1]
2041 set text
[lindex
$option 2]
2042 foreach f
{repo global
} {
2045 checkbutton
$w.
$f.
$name -text $text \
2046 -variable ${f}_config_new
(gui.
$name) \
2050 pack
$w.
$f.
$name -side top
-anchor w
2054 label
$w.
$f.
$name.l
-text "$text:" -font font_ui
2055 pack
$w.
$f.
$name.l
-side left
-anchor w
-fill x
2056 spinbox
$w.
$f.
$name.v \
2057 -textvariable ${f}_config_new
(gui.
$name) \
2058 -from 1 -to 99 -increment 1 \
2061 pack
$w.
$f.
$name.v
-side right
-anchor e
2062 pack
$w.
$f.
$name -side top
-anchor w
-fill x
2068 set all_fonts
[lsort
[font families
]]
2069 foreach option
$font_descs {
2070 set name
[lindex
$option 0]
2071 set font
[lindex
$option 1]
2072 set text
[lindex
$option 2]
2074 set global_config_new
(gui.
$font^^family
) \
2075 [font configure
$font -family]
2076 set global_config_new
(gui.
$font^^size
) \
2077 [font configure
$font -size]
2079 frame
$w.global.
$name
2080 label
$w.global.
$name.l
-text "$text:" -font font_ui
2081 pack
$w.global.
$name.l
-side left
-anchor w
-fill x
2082 eval tk_optionMenu
$w.global.
$name.family \
2083 global_config_new
(gui.
$font^^family
) \
2085 spinbox
$w.global.
$name.size \
2086 -textvariable global_config_new
(gui.
$font^^size
) \
2087 -from 2 -to 80 -increment 1 \
2090 pack
$w.global.
$name.size
-side right
-anchor e
2091 pack
$w.global.
$name.family
-side right
-anchor e
2092 pack
$w.global.
$name -side top
-anchor w
-fill x
2095 bind $w <Visibility
> "grab $w; focus $w"
2096 bind $w <Key-Escape
> "destroy $w"
2097 wm title
$w "$appname ($reponame): Options"
2101 proc do_restore_defaults
{} {
2102 global font_descs default_config repo_config
2103 global repo_config_new global_config_new
2105 foreach name
[array names default_config
] {
2106 set repo_config_new
($name) $default_config($name)
2107 set global_config_new
($name) $default_config($name)
2110 foreach option
$font_descs {
2111 set name
[lindex
$option 0]
2112 set repo_config
(gui.
$name) $default_config(gui.
$name)
2116 foreach option
$font_descs {
2117 set name
[lindex
$option 0]
2118 set font
[lindex
$option 1]
2119 set global_config_new
(gui.
$font^^family
) \
2120 [font configure
$font -family]
2121 set global_config_new
(gui.
$font^^size
) \
2122 [font configure
$font -size]
2126 proc do_save_config
{w
} {
2127 if {[catch
{save_config
} err
]} {
2128 error_popup
"Failed to completely save options:\n\n$err"
2134 proc do_windows_shortcut
{} {
2135 global gitdir appname argv0
2137 set reponame
[lindex
[file split \
2138 [file normalize
[file dirname $gitdir]]] \
2142 set desktop
[exec cygpath \
2150 set fn
[tk_getSaveFile \
2152 -title "$appname ($reponame): Create Desktop Icon" \
2153 -initialdir $desktop \
2154 -initialfile "Git $reponame.bat"]
2158 set sh
[exec cygpath \
2163 set me
[exec cygpath \
2167 set gd
[exec cygpath \
2171 regsub
-all ' $me "'\\''" me
2172 regsub -all ' $gd "'\\''" gd
2173 puts -nonewline $fd "\"$sh\" --login -c \""
2174 puts -nonewline $fd "GIT_DIR='$gd'"
2175 puts -nonewline $fd " '$me'"
2179 error_popup "Cannot write script:\n\n$err"
2184 proc do_macosx_app {} {
2185 global gitdir appname argv0 env
2187 set reponame [lindex [file split \
2188 [file normalize [file dirname $gitdir]]] \
2191 set fn [tk_getSaveFile \
2193 -title "$appname ($reponame): Create Desktop Icon" \
2194 -initialdir [file join $env(HOME) Desktop] \
2195 -initialfile "Git $reponame.app"]
2198 set Contents [file join $fn Contents]
2199 set MacOS [file join $Contents MacOS]
2200 set exe [file join $MacOS git-gui]
2204 set fd [open [file join $Contents PkgInfo] w]
2205 puts -nonewline $fd {APPL????}
2208 set fd [open [file join $Contents Info.plist] w]
2209 puts $fd {<?xml version="1.0" encoding="UTF-8"?>
2210 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2211 <plist version="1.0">
2213 <key>CFBundleDevelopmentRegion</key>
2214 <string>English</string>
2215 <key>CFBundleExecutable</key>
2216 <string>git-gui</string>
2217 <key>CFBundleIdentifier</key>
2218 <string>org.spearce.git-gui</string>
2219 <key>CFBundleInfoDictionaryVersion</key>
2220 <string>6.0</string>
2221 <key>CFBundlePackageType</key>
2222 <string>APPL</string>
2223 <key>CFBundleSignature</key>
2224 <string>????</string>
2225 <key>CFBundleVersion</key>
2226 <string>1.0</string>
2227 <key>NSPrincipalClass</key>
2228 <string>NSApplication</string>
2233 set fd [open $exe w]
2234 set gd [file normalize $gitdir]
2235 set ep [file normalize [exec git --exec-path]]
2236 regsub -all ' $gd "'\\''" gd
2237 regsub
-all ' $ep "'\\''" ep
2238 puts $fd "#!/bin/sh"
2239 foreach name
[array names env
] {
2240 if {[string match GIT_
* $name]} {
2241 regsub
-all ' $env($name) "'\\''" v
2242 puts $fd "export $name='$v'"
2245 puts $fd "export PATH
='$ep':\
$PATH"
2246 puts $fd "export GIT_DIR
='$gd'"
2247 puts $fd "exec [file normalize
$argv0]"
2250 file attributes $exe -permissions u+x,g+x,o+x
2252 error_popup "Cannot
write icon
:\n\n$err"
2257 proc toggle_or_diff {w x y} {
2258 global file_lists current_diff ui_index ui_other
2259 global last_clicked selected_paths
2261 set pos [split [$w index @$x,$y] .]
2262 set lno [lindex $pos 0]
2263 set col [lindex $pos 1]
2264 set path [lindex $file_lists($w) [expr {$lno - 1}]]
2270 set last_clicked [list $w $lno]
2271 array unset selected_paths
2272 $ui_index tag remove in_sel 0.0 end
2273 $ui_other tag remove in_sel 0.0 end
2276 if {$current_diff eq $path} {
2277 set after {reshow_diff;}
2282 "Including
[short_path
$path]" \
2284 [concat $after {set ui_status_value {Ready.}}]
2286 show_diff $path $w $lno
2290 proc add_one_to_selection {w x y} {
2292 global last_clicked selected_paths
2294 set pos [split [$w index @$x,$y] .]
2295 set lno [lindex $pos 0]
2296 set col [lindex $pos 1]
2297 set path [lindex $file_lists($w) [expr {$lno - 1}]]
2303 set last_clicked [list $w $lno]
2304 if {[catch {set in_sel $selected_paths($path)}]} {
2308 unset selected_paths($path)
2309 $w tag remove in_sel $lno.0 [expr {$lno + 1}].0
2311 set selected_paths($path) 1
2312 $w tag add in_sel $lno.0 [expr {$lno + 1}].0
2316 proc add_range_to_selection {w x y} {
2318 global last_clicked selected_paths
2320 if {[lindex $last_clicked 0] ne $w} {
2321 toggle_or_diff $w $x $y
2325 set pos [split [$w index @$x,$y] .]
2326 set lno [lindex $pos 0]
2327 set lc [lindex $last_clicked 1]
2336 foreach path [lrange $file_lists($w) \
2337 [expr {$begin - 1}] \
2338 [expr {$end - 1}]] {
2339 set selected_paths($path) 1
2341 $w tag add in_sel $begin.0 [expr {$end + 1}].0
2344 ######################################################################
2348 set cursor_ptr arrow
2349 font create font_diff -family Courier -size 10
2353 eval font configure font_ui [font actual [.dummy cget -font]]
2357 font create font_uibold
2358 font create font_diffbold
2362 if {$tcl_platform(platform) eq {windows}} {
2365 } elseif {[is_MacOSX]} {
2370 proc apply_config {} {
2371 global repo_config font_descs
2373 foreach option $font_descs {
2374 set name [lindex $option 0]
2375 set font [lindex $option 1]
2377 foreach {cn cv} $repo_config(gui.$name) {
2378 font configure $font $cn $cv
2381 error_popup "Invalid font specified
in gui.
$name:\n\n$err"
2383 foreach {cn cv} [font configure $font] {
2384 font configure ${font}bold $cn $cv
2386 font configure ${font}bold -weight bold
2390 set default_config(gui.trustmtime) false
2391 set default_config(gui.pullsummary) true
2392 set default_config(gui.partialinclude) false
2393 set default_config(gui.diffcontext) 5
2394 set default_config(gui.fontui) [font configure font_ui]
2395 set default_config(gui.fontdiff) [font configure font_diff]
2397 {fontui font_ui {Main Font}}
2398 {fontdiff font_diff {Diff/Console Font}}
2403 ######################################################################
2409 menu .mbar -tearoff 0
2410 .mbar add cascade -label Project -menu .mbar.project
2411 .mbar add cascade -label Edit -menu .mbar.edit
2412 .mbar add cascade -label Commit -menu .mbar.commit
2413 if {!$single_commit} {
2414 .mbar add cascade -label Fetch -menu .mbar.fetch
2415 .mbar add cascade -label Pull -menu .mbar.pull
2416 .mbar add cascade -label Push -menu .mbar.push
2418 . configure -menu .mbar
2423 .mbar.project add command -label Visualize \
2426 if {!$single_commit} {
2427 .mbar.project add command -label {Repack Database} \
2428 -command do_repack \
2431 if {$tcl_platform(platform) eq {windows}} {
2432 .mbar.project add command \
2433 -label {Create Desktop Icon} \
2434 -command do_windows_shortcut \
2436 } elseif {[is_MacOSX]} {
2437 .mbar.project add command \
2438 -label {Create Desktop Icon} \
2439 -command do_macosx_app \
2443 .mbar.project add command -label Quit \
2445 -accelerator $M1T-Q \
2451 .mbar.edit add command -label Undo \
2452 -command {catch {[focus] edit undo}} \
2453 -accelerator $M1T-Z \
2455 .mbar.edit add command -label Redo \
2456 -command {catch {[focus] edit redo}} \
2457 -accelerator $M1T-Y \
2459 .mbar.edit add separator
2460 .mbar.edit add command -label Cut \
2461 -command {catch {tk_textCut [focus]}} \
2462 -accelerator $M1T-X \
2464 .mbar.edit add command -label Copy \
2465 -command {catch {tk_textCopy [focus]}} \
2466 -accelerator $M1T-C \
2468 .mbar.edit add command -label Paste \
2469 -command {catch {tk_textPaste [focus]; [focus] see insert}} \
2470 -accelerator $M1T-V \
2472 .mbar.edit add command -label Delete \
2473 -command {catch {[focus] delete sel.first sel.last}} \
2476 .mbar.edit add separator
2477 .mbar.edit add command -label {Select All} \
2478 -command {catch {[focus] tag add sel 0.0 end}} \
2479 -accelerator $M1T-A \
2481 .mbar.edit add separator
2482 .mbar.edit add command -label {Options...} \
2483 -command do_options \
2490 .mbar.commit add radiobutton \
2491 -label {New Commit} \
2492 -command do_select_commit_type \
2493 -variable selected_commit_type \
2496 lappend disable_on_lock \
2497 [list .mbar.commit entryconf [.mbar.commit index last] -state]
2499 .mbar.commit add radiobutton \
2500 -label {Amend Last Commit} \
2501 -command do_select_commit_type \
2502 -variable selected_commit_type \
2505 lappend disable_on_lock \
2506 [list .mbar.commit entryconf [.mbar.commit index last] -state]
2508 .mbar.commit add separator
2510 .mbar.commit add command -label Rescan \
2511 -command do_rescan \
2514 lappend disable_on_lock \
2515 [list .mbar.commit entryconf [.mbar.commit index last] -state]
2517 .mbar.commit add command -label {Include Selected Files} \
2518 -command do_include_selection \
2520 lappend disable_on_lock \
2521 [list .mbar.commit entryconf [.mbar.commit index last] -state]
2523 .mbar.commit add command -label {Include All Files} \
2524 -command do_include_all \
2525 -accelerator $M1T-I \
2527 lappend disable_on_lock \
2528 [list .mbar.commit entryconf [.mbar.commit index last] -state]
2530 .mbar.commit add command -label {Sign Off} \
2531 -command do_signoff \
2532 -accelerator $M1T-S \
2535 .mbar.commit add command -label Commit \
2536 -command do_commit \
2537 -accelerator $M1T-Return \
2539 lappend disable_on_lock \
2540 [list .mbar.commit entryconf [.mbar.commit index last] -state]
2542 # -- Transport menus
2544 if {!$single_commit} {
2550 # -- Main Window Layout
2552 panedwindow .vpane -orient vertical
2553 panedwindow .vpane.files -orient horizontal
2554 .vpane add .vpane.files -sticky nsew -height 100 -width 400
2555 pack .vpane -anchor n -side top -fill both -expand 1
2557 # -- Index File List
2559 frame .vpane.files.index -height 100 -width 400
2560 label .vpane.files.index.title -text {Modified Files} \
2563 text $ui_index -background white -borderwidth 0 \
2564 -width 40 -height 10 \
2566 -cursor $cursor_ptr \
2567 -yscrollcommand {.vpane.files.index.sb set} \
2569 scrollbar .vpane.files.index.sb -command [list $ui_index yview]
2570 pack .vpane.files.index.title -side top -fill x
2571 pack .vpane.files.index.sb -side right -fill y
2572 pack $ui_index -side left -fill both -expand 1
2573 .vpane.files add .vpane.files.index -sticky nsew
2575 # -- Other (Add) File List
2577 frame .vpane.files.other -height 100 -width 100
2578 label .vpane.files.other.title -text {Untracked Files} \
2581 text $ui_other -background white -borderwidth 0 \
2582 -width 40 -height 10 \
2584 -cursor $cursor_ptr \
2585 -yscrollcommand {.vpane.files.other.sb set} \
2587 scrollbar .vpane.files.other.sb -command [list $ui_other yview]
2588 pack .vpane.files.other.title -side top -fill x
2589 pack .vpane.files.other.sb -side right -fill y
2590 pack $ui_other -side left -fill both -expand 1
2591 .vpane.files add .vpane.files.other -sticky nsew
2593 foreach i [list $ui_index $ui_other] {
2594 $i tag conf in_diff -font font_uibold
2595 $i tag conf in_sel \
2596 -background [$i cget -foreground] \
2597 -foreground [$i cget -background]
2601 # -- Diff and Commit Area
2603 frame .vpane.lower -height 300 -width 400
2604 frame .vpane.lower.commarea
2605 frame .vpane.lower.diff -relief sunken -borderwidth 1
2606 pack .vpane.lower.commarea -side top -fill x
2607 pack .vpane.lower.diff -side bottom -fill both -expand 1
2608 .vpane add .vpane.lower -stick nsew
2610 # -- Commit Area Buttons
2612 frame .vpane.lower.commarea.buttons
2613 label .vpane.lower.commarea.buttons.l -text {} \
2617 pack .vpane.lower.commarea.buttons.l -side top -fill x
2618 pack .vpane.lower.commarea.buttons -side left -fill y
2620 button .vpane.lower.commarea.buttons.rescan -text {Rescan} \
2621 -command do_rescan \
2623 pack .vpane.lower.commarea.buttons.rescan -side top -fill x
2624 lappend disable_on_lock \
2625 {.vpane.lower.commarea.buttons.rescan conf -state}
2627 button .vpane.lower.commarea.buttons.incall -text {Include All} \
2628 -command do_include_all \
2630 pack .vpane.lower.commarea.buttons.incall -side top -fill x
2631 lappend disable_on_lock \
2632 {.vpane.lower.commarea.buttons.incall conf -state}
2634 button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \
2635 -command do_signoff \
2637 pack .vpane.lower.commarea.buttons.signoff -side top -fill x
2639 button .vpane.lower.commarea.buttons.commit -text {Commit} \
2640 -command do_commit \
2642 pack .vpane.lower.commarea.buttons.commit -side top -fill x
2643 lappend disable_on_lock \
2644 {.vpane.lower.commarea.buttons.commit conf -state}
2646 # -- Commit Message Buffer
2648 frame .vpane.lower.commarea.buffer
2649 frame .vpane.lower.commarea.buffer.header
2650 set ui_comm .vpane.lower.commarea.buffer.t
2651 set ui_coml .vpane.lower.commarea.buffer.header.l
2652 radiobutton .vpane.lower.commarea.buffer.header.new \
2653 -text {New Commit} \
2654 -command do_select_commit_type \
2655 -variable selected_commit_type \
2658 lappend disable_on_lock \
2659 [list .vpane.lower.commarea.buffer.header.new conf -state]
2660 radiobutton .vpane.lower.commarea.buffer.header.amend \
2661 -text {Amend Last Commit} \
2662 -command do_select_commit_type \
2663 -variable selected_commit_type \
2666 lappend disable_on_lock \
2667 [list .vpane.lower.commarea.buffer.header.amend conf -state]
2672 proc trace_commit_type {varname args} {
2673 global ui_coml commit_type
2674 switch -glob -- $commit_type {
2675 initial {set txt {Initial Commit Message:}}
2676 amend {set txt {Amended Commit Message:}}
2677 amend-initial {set txt {Amended Initial Commit Message:}}
2678 merge {set txt {Merge Commit Message:}}
2679 * {set txt {Commit Message:}}
2681 $ui_coml conf -text $txt
2683 trace add variable commit_type write trace_commit_type
2684 pack $ui_coml -side left -fill x
2685 pack .vpane.lower.commarea.buffer.header.amend -side right
2686 pack .vpane.lower.commarea.buffer.header.new -side right
2688 text $ui_comm -background white -borderwidth 1 \
2691 -autoseparators true \
2693 -width 75 -height 9 -wrap none \
2695 -yscrollcommand {.vpane.lower.commarea.buffer.sby set}
2696 scrollbar .vpane.lower.commarea.buffer.sby \
2697 -command [list $ui_comm yview]
2698 pack .vpane.lower.commarea.buffer.header -side top -fill x
2699 pack .vpane.lower.commarea.buffer.sby -side right -fill y
2700 pack $ui_comm -side left -fill y
2701 pack .vpane.lower.commarea.buffer -side left -fill y
2703 # -- Commit Message Buffer Context Menu
2705 set ctxm .vpane.lower.commarea.buffer.ctxm
2706 menu $ctxm -tearoff 0
2710 -command {tk_textCut $ui_comm}
2714 -command {tk_textCopy $ui_comm}
2718 -command {tk_textPaste $ui_comm}
2722 -command {$ui_comm delete sel.first sel.last}
2725 -label {Select All} \
2727 -command {$ui_comm tag add sel 0.0 end}
2732 $ui_comm tag add sel 0.0 end
2733 tk_textCopy $ui_comm
2734 $ui_comm tag remove sel 0.0 end
2741 bind_button3 $ui_comm "tk_popup
$ctxm %X
%Y
"
2746 set diff_actions [list]
2747 proc trace_current_diff {varname args} {
2748 global current_diff diff_actions file_states
2749 if {$current_diff eq {}} {
2756 set s [mapdesc [lindex $file_states($p) 0] $p]
2758 set p [escape_path $p]
2762 .vpane.lower.diff.header.status configure -text $s
2763 .vpane.lower.diff.header.file configure -text $f
2764 .vpane.lower.diff.header.path configure -text $p
2765 foreach w $diff_actions {
2769 trace add variable current_diff write trace_current_diff
2771 frame .vpane.lower.diff.header -background orange
2772 label .vpane.lower.diff.header.status \
2773 -background orange \
2774 -width $max_status_desc \
2778 label .vpane.lower.diff.header.file \
2779 -background orange \
2783 label .vpane.lower.diff.header.path \
2784 -background orange \
2788 pack .vpane.lower.diff.header.status -side left
2789 pack .vpane.lower.diff.header.file -side left
2790 pack .vpane.lower.diff.header.path -fill x
2791 set ctxm .vpane.lower.diff.header.ctxm
2792 menu $ctxm -tearoff 0
2803 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2804 bind_button3 .vpane.lower.diff.header.path "tk_popup
$ctxm %X
%Y
"
2808 frame .vpane.lower.diff.body
2809 set ui_diff .vpane.lower.diff.body.t
2810 text $ui_diff -background white -borderwidth 0 \
2811 -width 80 -height 15 -wrap none \
2813 -xscrollcommand {.vpane.lower.diff.body.sbx set} \
2814 -yscrollcommand {.vpane.lower.diff.body.sby set} \
2816 scrollbar .vpane.lower.diff.body.sbx -orient horizontal \
2817 -command [list $ui_diff xview]
2818 scrollbar .vpane.lower.diff.body.sby -orient vertical \
2819 -command [list $ui_diff yview]
2820 pack .vpane.lower.diff.body.sbx -side bottom -fill x
2821 pack .vpane.lower.diff.body.sby -side right -fill y
2822 pack $ui_diff -side left -fill both -expand 1
2823 pack .vpane.lower.diff.header -side top -fill x
2824 pack .vpane.lower.diff.body -side bottom -fill both -expand 1
2826 $ui_diff tag conf dm -foreground red
2827 $ui_diff tag conf dp -foreground blue
2828 $ui_diff tag conf di -foreground {#00a000}
2829 $ui_diff tag conf dni -foreground {#a000a0}
2830 $ui_diff tag conf da -font font_diffbold
2831 $ui_diff tag conf bold -font font_diffbold
2833 # -- Diff Body Context Menu
2835 set ctxm .vpane.lower.diff.body.ctxm
2836 menu $ctxm -tearoff 0
2840 -command {tk_textCopy $ui_diff}
2841 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2843 -label {Select All} \
2845 -command {$ui_diff tag add sel 0.0 end}
2846 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2851 $ui_diff tag add sel 0.0 end
2852 tk_textCopy $ui_diff
2853 $ui_diff tag remove sel 0.0 end
2855 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2858 -label {Decrease Font Size} \
2860 -command {incr_font_size font_diff -1}
2861 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2863 -label {Increase Font Size} \
2865 -command {incr_font_size font_diff 1}
2866 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2869 -label {Show Less Context} \
2871 -command {if {$repo_config(gui.diffcontext) >= 2} {
2872 incr repo_config(gui.diffcontext) -1
2875 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2877 -label {Show More Context} \
2880 incr repo_config(gui.diffcontext)
2883 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2885 $ctxm add command -label {Options...} \
2888 bind_button3 $ui_diff "tk_popup
$ctxm %X
%Y
"
2892 set ui_status_value {Initializing...}
2893 label .status -textvariable ui_status_value \
2899 pack .status -anchor w -side bottom -fill x
2904 set gm $repo_config(gui.geometry)
2905 wm geometry . [lindex $gm 0]
2906 .vpane sash place 0 \
2907 [lindex [.vpane sash coord 0] 0] \
2909 .vpane.files sash place 0 \
2911 [lindex [.vpane.files sash coord 0] 1]
2917 bind $ui_comm <$M1B-Key-Return> {do_commit;break}
2918 bind $ui_comm <$M1B-Key-i> {do_include_all;break}
2919 bind $ui_comm <$M1B-Key-I> {do_include_all;break}
2920 bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break}
2921 bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break}
2922 bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break}
2923 bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break}
2924 bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break}
2925 bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break}
2926 bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break}
2927 bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break}
2929 bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
2930 bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
2931 bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break}
2932 bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break}
2933 bind $ui_diff <$M1B-Key-v> {break}
2934 bind $ui_diff <$M1B-Key-V> {break}
2935 bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break}
2936 bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break}
2937 bind $ui_diff <Key-Up> {catch {%W yview scroll -1 units};break}
2938 bind $ui_diff <Key-Down> {catch {%W yview scroll 1 units};break}
2939 bind $ui_diff <Key-Left> {catch {%W xview scroll -1 units};break}
2940 bind $ui_diff <Key-Right> {catch {%W xview scroll 1 units};break}
2942 bind . <Destroy> do_quit
2943 bind all <Key-F5> do_rescan
2944 bind all <$M1B-Key-r> do_rescan
2945 bind all <$M1B-Key-R> do_rescan
2946 bind . <$M1B-Key-s> do_signoff
2947 bind . <$M1B-Key-S> do_signoff
2948 bind . <$M1B-Key-i> do_include_all
2949 bind . <$M1B-Key-I> do_include_all
2950 bind . <$M1B-Key-Return> do_commit
2951 bind all <$M1B-Key-q> do_quit
2952 bind all <$M1B-Key-Q> do_quit
2953 bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
2954 bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
2955 foreach i [list $ui_index $ui_other] {
2956 bind $i <Button-1> "toggle_or_diff
$i %x
%y
; break"
2957 bind $i <$M1B-Button-1> "add_one_to_selection
$i %x
%y
; break"
2958 bind $i <Shift-Button-1> "add_range_to_selection
$i %x
%y
; break"
2962 set file_lists($ui_index) [list]
2963 set file_lists($ui_other) [list]
2970 set selected_commit_type new
2972 wm title . "$appname ([file normalize
[file dirname $gitdir]])"
2973 focus -force $ui_comm
2974 if {!$single_commit} {
2976 populate_fetch_menu .mbar.fetch
2977 populate_pull_menu .mbar.pull
2978 populate_push_menu .mbar.push
2980 lock_index begin-read