##
## config
-proc load_repo_config {} {
- global repo_config
- global cfg_trust_mtime
+proc is_many_config {name} {
+ switch -glob -- $name {
+ remote.*.fetch -
+ remote.*.push
+ {return 1}
+ *
+ {return 0}
+ }
+}
+
+proc load_config {include_global} {
+ global repo_config global_config default_config
+
+ array unset global_config
+ if {$include_global} {
+ catch {
+ set fd_rc [open "| git repo-config --global --list" r]
+ while {[gets $fd_rc line] >= 0} {
+ if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
+ if {[is_many_config $name]} {
+ lappend global_config($name) $value
+ } else {
+ set global_config($name) $value
+ }
+ }
+ }
+ close $fd_rc
+ }
+ }
array unset repo_config
catch {
set fd_rc [open "| git repo-config --list" r]
while {[gets $fd_rc line] >= 0} {
if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
- lappend repo_config($name) $value
+ if {[is_many_config $name]} {
+ lappend repo_config($name) $value
+ } else {
+ set repo_config($name) $value
+ }
}
}
close $fd_rc
}
- if {[catch {set cfg_trust_mtime \
- [lindex $repo_config(gui.trustmtime) 0]
- }]} {
- set cfg_trust_mtime false
+ foreach name [array names default_config] {
+ if {[catch {set v $global_config($name)}]} {
+ set global_config($name) $default_config($name)
+ }
+ if {[catch {set v $repo_config($name)}]} {
+ set repo_config($name) $default_config($name)
+ }
}
}
-proc save_my_config {} {
- global repo_config
- global cfg_trust_mtime
+proc save_config {} {
+ global default_config font_descs
+ global repo_config global_config
+ global repo_config_new global_config_new
- if {[catch {set rc_trustMTime $repo_config(gui.trustmtime)}]} {
- set rc_trustMTime [list false]
- }
- if {$cfg_trust_mtime != [lindex $rc_trustMTime 0]} {
- exec git repo-config gui.trustMTime $cfg_trust_mtime
- set repo_config(gui.trustmtime) [list $cfg_trust_mtime]
+ foreach option $font_descs {
+ set name [lindex $option 0]
+ set font [lindex $option 1]
+ font configure $font \
+ -family $global_config_new(gui.$font^^family) \
+ -size $global_config_new(gui.$font^^size)
+ font configure ${font}bold \
+ -family $global_config_new(gui.$font^^family) \
+ -size $global_config_new(gui.$font^^size)
+ set global_config_new(gui.$name) [font configure $font]
+ unset global_config_new(gui.$font^^family)
+ unset global_config_new(gui.$font^^size)
}
- set cfg_geometry [wm geometry .]
- append cfg_geometry " [lindex [.vpane sash coord 0] 1]"
- append cfg_geometry " [lindex [.vpane.files sash coord 0] 0]"
- if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
- set rc_geometry [list [list]]
+ foreach name [array names default_config] {
+ set value $global_config_new($name)
+ if {$value ne $global_config($name)} {
+ if {$value eq $default_config($name)} {
+ catch {exec git repo-config --global --unset $name}
+ } else {
+ regsub -all "\[{}\]" $value {"} value
+ exec git repo-config --global $name $value
+ }
+ set global_config($name) $value
+ if {$value eq $repo_config($name)} {
+ catch {exec git repo-config --unset $name}
+ set repo_config($name) $value
+ }
+ }
}
- if {$cfg_geometry != [lindex $rc_geometry 0]} {
- exec git repo-config gui.geometry $cfg_geometry
- set repo_config(gui.geometry) [list $cfg_geometry]
+
+ foreach name [array names default_config] {
+ set value $repo_config_new($name)
+ if {$value ne $repo_config($name)} {
+ if {$value eq $global_config($name)} {
+ catch {exec git repo-config --unset $name}
+ } else {
+ regsub -all "\[{}\]" $value {"} value
+ exec git repo-config $name $value
+ }
+ set repo_config($name) $value
+ }
}
}
global gitdir appname
set title $appname
- if {$gitdir != {}} {
+ if {$gitdir ne {}} {
append title { (}
append title [lindex \
[file split [file normalize [file dirname $gitdir]]] \
global gitdir appname
set title $appname
- if {$gitdir != {}} {
+ if {$gitdir ne {}} {
append title { (}
append title [lindex \
[file split [file normalize [file dirname $gitdir]]] \
error_popup "Cannot find the git directory:\n\n$err"
exit 1
}
-if {$cdup != ""} {
+if {$cdup ne ""} {
cd $cdup
}
unset cdup
-if {$appname == {git-citool}} {
+set single_commit 0
+if {$appname eq {git-citool}} {
set single_commit 1
}
-load_repo_config
-
######################################################################
##
## task management
-set single_commit 0
set status_active 0
set diff_active 0
-set update_active 0
-set commit_active 0
-set update_index_fd {}
set disable_on_lock [list]
set index_lock_type none
proc lock_index {type} {
global index_lock_type disable_on_lock
- if {$index_lock_type == {none}} {
+ if {$index_lock_type eq {none}} {
set index_lock_type $type
foreach w $disable_on_lock {
uplevel #0 $w disabled
}
return 1
- } elseif {$index_lock_type == {begin-update} && $type == {update}} {
+ } elseif {$index_lock_type eq {begin-update} && $type eq {update}} {
set index_lock_type $type
return 1
}
global HEAD PARENT commit_type
global ui_index ui_other ui_status_value ui_comm
global status_active file_states
- global cfg_trust_mtime
+ global repo_config
if {$status_active || ![lock_index read]} return
repository_state new_HEAD new_type
- if {$commit_type == {amend}
- && $new_type == {normal}
- && $new_HEAD == $HEAD} {
+ if {$commit_type eq {amend}
+ && $new_type eq {normal}
+ && $new_HEAD eq $HEAD} {
} else {
set HEAD $new_HEAD
set PARENT $new_HEAD
array unset file_states
if {![$ui_comm edit modified]
- || [string trim [$ui_comm get 0.0 end]] == {}} {
+ || [string trim [$ui_comm get 0.0 end]] eq {}} {
if {[load_message GITGUI_MSG]} {
} elseif {[load_message MERGE_MSG]} {
} elseif {[load_message SQUASH_MSG]} {
$ui_comm edit reset
}
- if {$cfg_trust_mtime == {true}} {
+ if {$repo_config(gui.trustmtime) eq {true}} {
update_status_stage2 {} $final
} else {
set status_active 1
global status_active
global buf_rdi buf_rdf buf_rlo
- if {$fd != {}} {
+ if {$fd ne {}} {
read $fd
if {![eof $fd]} return
close $fd
proc reshow_diff {} {
global ui_fname_value ui_status_value file_states
- if {$ui_fname_value == {}
+ if {$ui_fname_value eq {}
|| [catch {set s $file_states($ui_fname_value)}]} {
clear_diff
} else {
set path $ui_fname_value
set s $file_states($path)
- if {[lindex $s 0] != {_M}} return
+ if {[lindex $s 0] ne {_M}} return
info_popup "No differences detected.
The modification date of this file was updated by another
application and you currently have the Trust File Modification
-Timestamps feature enabled, so Git did not automatically detect
+Timestamps option enabled, so Git did not automatically detect
that there are no content differences in this file.
This file will now be removed from the modified files list, to
proc show_diff {path {w {}} {lno {}}} {
global file_states file_lists
- global PARENT diff_3way diff_active
+ global PARENT diff_3way diff_active repo_config
global ui_diff ui_fname_value ui_fstatus_value ui_status_value
if {$diff_active || ![lock_index read]} return
clear_diff
- if {$w == {} || $lno == {}} {
+ if {$w eq {} || $lno == {}} {
foreach w [array names file_lists] {
set lno [lsearch -sorted $file_lists($w) $path]
if {$lno >= 0} {
}
}
}
- if {$w != {} && $lno >= 1} {
+ if {$w ne {} && $lno >= 1} {
$w tag add in_diff $lno.0 [expr $lno + 1].0
}
set ui_fstatus_value [mapdesc $m $path]
set ui_status_value "Loading diff of [escape_path $path]..."
- set cmd [list | git diff-index -p $PARENT -- $path]
+ set cmd [list | git diff-index]
+ lappend cmd --no-color
+ if {$repo_config(gui.diffcontext) > 0} {
+ lappend cmd "-U$repo_config(gui.diffcontext)"
+ }
+ lappend cmd -p
+
switch $m {
MM {
- set cmd [list | git diff-index -p -c $PARENT $path]
+ lappend cmd -c
}
_O {
if {[catch {
}
}
+ lappend cmd $PARENT
+ lappend cmd --
+ lappend cmd $path
+
if {[catch {set fd [open $cmd r]} err]} {
set diff_active 0
unlock_index
proc read_diff {fd} {
global ui_diff ui_status_value diff_3way diff_active
- global cfg_trust_mtime
+ global repo_config
while {[gets $fd line] >= 0} {
if {[string match {diff --git *} $line]} continue
unlock_index
set ui_status_value {Ready.}
- if {$cfg_trust_mtime && [$ui_diff index end] == {2.0}} {
+ if {$repo_config(gui.trustmtime) eq {true}
+ && [$ui_diff index end] eq {2.0}} {
handle_empty_diff
}
}
proc load_last_commit {} {
global HEAD PARENT commit_type ui_comm
- if {$commit_type == {amend}} return
- if {$commit_type != {normal}} {
+ if {$commit_type eq {amend}} return
+ if {$commit_type ne {normal}} {
error_popup "Can't amend a $commit_type commit."
return
}
proc commit_tree {} {
global tcl_platform HEAD gitdir commit_type file_states
- global commit_active ui_status_value
- global ui_comm
+ global pch_error
+ global ui_status_value ui_comm
- if {$commit_active || ![lock_index update]} return
+ if {![lock_index update]} return
# -- Our in memory state should match the repository.
#
repository_state curHEAD cur_type
- if {$commit_type == {amend}
- && $cur_type == {normal}
- && $curHEAD == $HEAD} {
- } elseif {$commit_type != $cur_type || $HEAD != $curHEAD} {
+ if {$commit_type eq {amend}
+ && $cur_type eq {normal}
+ && $curHEAD eq $HEAD} {
+ } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
error_popup {Last scanned state does not match repository state.
Its highly likely that another Git program modified the
# -- A message is required.
#
set msg [string trim [$ui_comm get 1.0 end]]
- if {$msg == {}} {
+ if {$msg eq {}} {
error_popup {Please supply a commit message.
A good commit message has the following format:
# -- Ask the pre-commit hook for the go-ahead.
#
set pchook [file join $gitdir hooks pre-commit]
- if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} {
- set pchook [list sh -c \
- "if test -x \"$pchook\"; then exec \"$pchook\"; fi"]
+ if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
+ set pchook [list sh -c [concat \
+ "if test -x \"$pchook\";" \
+ "then exec \"$pchook\" 2>&1;" \
+ "fi"]]
} elseif {[file executable $pchook]} {
- set pchook [list $pchook]
+ set pchook [list $pchook |& cat]
} else {
set pchook {}
}
- if {$pchook != {} && [catch {eval exec $pchook} err]} {
- hook_failed_popup pre-commit $err
- unlock_index
- return
+ if {$pchook ne {}} {
+ set ui_status_value {Calling pre-commit hook...}
+ set pch_error {}
+ set fd_ph [open "| $pchook" r]
+ fconfigure $fd_ph -blocking 0 -translation binary
+ fileevent $fd_ph readable \
+ [list commit_stage1 $fd_ph $curHEAD $msg]
+ } else {
+ commit_stage2 $curHEAD $msg
}
+}
+
+proc commit_stage1 {fd_ph curHEAD msg} {
+ global pch_error ui_status_value
+
+ append pch_error [read $fd_ph]
+ fconfigure $fd_ph -blocking 1
+ if {[eof $fd_ph]} {
+ if {[catch {close $fd_ph}]} {
+ set ui_status_value {Commit declined by pre-commit hook.}
+ hook_failed_popup pre-commit $pch_error
+ unlock_index
+ } else {
+ commit_stage2 $curHEAD $msg
+ }
+ set pch_error {}
+ } else {
+ fconfigure $fd_ph -blocking 0
+ }
+}
+
+proc commit_stage2 {curHEAD msg} {
+ global ui_status_value
# -- Write the tree in the background.
#
- set commit_active 1
set ui_status_value {Committing changes...}
-
set fd_wt [open "| git write-tree" r]
- fileevent $fd_wt readable [list commit_stage2 $fd_wt $curHEAD $msg]
+ fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg]
}
-proc commit_stage2 {fd_wt curHEAD msg} {
- global single_commit gitdir HEAD PARENT commit_type
- global commit_active ui_status_value ui_comm
+proc commit_stage3 {fd_wt curHEAD msg} {
+ global single_commit gitdir HEAD PARENT commit_type tcl_platform
+ global ui_status_value ui_comm
global file_states
gets $fd_wt tree_id
- if {$tree_id == {} || [catch {close $fd_wt} err]} {
+ if {$tree_id eq {} || [catch {close $fd_wt} err]} {
error_popup "write-tree failed:\n\n$err"
- set commit_active 0
set ui_status_value {Commit failed.}
unlock_index
return
# -- Create the commit.
#
set cmd [list git commit-tree $tree_id]
- if {$PARENT != {}} {
+ if {$PARENT ne {}} {
lappend cmd -p $PARENT
}
- if {$commit_type == {merge}} {
+ if {$commit_type eq {merge}} {
if {[catch {
set fd_mh [open [file join $gitdir MERGE_HEAD] r]
while {[gets $fd_mh merge_head] >= 0} {
close $fd_mh
} err]} {
error_popup "Loading MERGE_HEAD failed:\n\n$err"
- set commit_active 0
set ui_status_value {Commit failed.}
unlock_index
return
}
}
- if {$PARENT == {}} {
+ if {$PARENT eq {}} {
# git commit-tree writes to stderr during initial commit.
lappend cmd 2>/dev/null
}
lappend cmd << $msg
if {[catch {set cmt_id [eval exec $cmd]} err]} {
error_popup "commit-tree failed:\n\n$err"
- set commit_active 0
set ui_status_value {Commit failed.}
unlock_index
return
# -- Update the HEAD ref.
#
set reflogm commit
- if {$commit_type != {normal}} {
+ if {$commit_type ne {normal}} {
append reflogm " ($commit_type)"
}
set i [string first "\n" $msg]
set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD]
if {[catch {eval exec $cmd} err]} {
error_popup "update-ref failed:\n\n$err"
- set commit_active 0
set ui_status_value {Commit failed.}
unlock_index
return
catch {exec git rerere}
}
+ # -- Run the post-commit hook.
+ #
+ set pchook [file join $gitdir hooks post-commit]
+ if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
+ set pchook [list sh -c [concat \
+ "if test -x \"$pchook\";" \
+ "then exec \"$pchook\";" \
+ "fi"]]
+ } elseif {![file executable $pchook]} {
+ set pchook {}
+ }
+ if {$pchook ne {}} {
+ catch {exec $pchook &}
+ }
+
$ui_comm delete 0.0 end
$ui_comm edit modified false
$ui_comm edit reset
# -- Update status without invoking any git commands.
#
- set commit_active 0
set commit_type normal
set HEAD $cmt_id
set PARENT $cmt_id
D? {set m _[string index $m 1]}
}
- if {$m == {__}} {
+ if {$m eq {__}} {
unset file_states($path)
} else {
lset file_states($path) 0 $m
}
proc pull_remote {remote branch} {
- global HEAD commit_type
- global file_states
+ global HEAD commit_type file_states repo_config
if {![lock_index update]} return
# -- Our in memory state should match the repository.
#
repository_state curHEAD cur_type
- if {$commit_type != $cur_type || $HEAD != $curHEAD} {
+ if {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
error_popup {Last scanned state does not match repository state.
Its highly likely that another Git program modified the
set w [new_console "pull $remote $branch" \
"Pulling new changes from branch $branch in $remote"]
set cmd [list git pull]
+ if {$repo_config(gui.pullsummary) eq {false}} {
+ lappend cmd --no-summary
+ }
lappend cmd $remote
lappend cmd $branch
console_exec $w $cmd [list post_pull_remote $remote $branch]
set icon [lindex $info 1]
}
- if {$s0 == {_}} {
+ if {$s0 eq {_}} {
set s0 [string index $state 0]
- } elseif {$s0 == {*}} {
+ } elseif {$s0 eq {*}} {
set s0 _
}
- if {$s1 == {_}} {
+ if {$s1 eq {_}} {
set s1 [string index $state 1]
- } elseif {$s1 == {*}} {
+ } elseif {$s1 eq {*}} {
set s1 _
}
set old_w [mapcol $old_m $path]
set new_icon [mapicon $new_m $path]
- if {$new_w != $old_w} {
+ if {$new_w ne $old_w} {
set lno [lsearch -sorted $file_lists($old_w) $path]
if {$lno >= 0} {
incr lno
-image $new_icon
$new_w insert $lno.1 "[escape_path $path]\n"
$new_w conf -state disabled
- } elseif {$new_icon != [mapicon $old_m $path]} {
+ } elseif {$new_icon ne [mapicon $old_m $path]} {
$new_w conf -state normal
$new_w image conf [lindex $s 1] -image $new_icon
$new_w conf -state disabled
$ui_other conf -state disabled
}
-proc with_update_index {body} {
- global update_index_fd
+proc update_index {pathList} {
+ global update_index_cp update_index_rsd ui_status_value
- if {$update_index_fd == {}} {
- if {![lock_index update]} return
- set update_index_fd [open \
- "| git update-index --add --remove -z --stdin" \
- w]
- fconfigure $update_index_fd -translation binary
- uplevel 1 $body
- close $update_index_fd
- set update_index_fd {}
- unlock_index
- } else {
- uplevel 1 $body
- }
-}
+ if {![lock_index update]} return
-proc update_index {path} {
- global update_index_fd
+ set update_index_cp 0
+ set update_index_rsd 0
+ set pathList [lsort $pathList]
+ set totalCnt [llength $pathList]
+ set batch [expr {int($totalCnt * .01) + 1}]
+ if {$batch > 25} {set batch 25}
+
+ set ui_status_value "Including files ... 0/$totalCnt 0%"
+ set ui_status_value [format \
+ "Including files ... %i/%i files (%.2f%%)" \
+ $update_index_cp \
+ $totalCnt \
+ 0.0]
+ set fd [open "| git update-index --add --remove -z --stdin" w]
+ fconfigure $fd \
+ -blocking 0 \
+ -buffering full \
+ -buffersize 512 \
+ -translation binary
+ fileevent $fd writable [list \
+ write_update_index \
+ $fd \
+ $pathList \
+ $totalCnt \
+ $batch \
+ ]
+}
+
+proc write_update_index {fd pathList totalCnt batch} {
+ global update_index_cp update_index_rsd ui_status_value
+ global file_states ui_fname_value
- if {$update_index_fd == {}} {
- error {not in with_update_index}
- } else {
- puts -nonewline $update_index_fd "$path\0"
+ if {$update_index_cp >= $totalCnt} {
+ close $fd
+ unlock_index
+ if {$update_index_rsd} {
+ reshow_diff
+ } else {
+ set ui_status_value {Ready.}
+ }
+ return
}
-}
-
-proc toggle_mode {path} {
- global file_states ui_fname_value
- set s $file_states($path)
- set m [lindex $s 0]
+ for {set i $batch} \
+ {$update_index_cp < $totalCnt && $i > 0} \
+ {incr i -1} {
+ set path [lindex $pathList $update_index_cp]
+ incr update_index_cp
+
+ switch -- [lindex $file_states($path) 0] {
+ AM -
+ _O {set new A*}
+ _M -
+ MM {set new M*}
+ AD -
+ _D {set new D*}
+ default {continue}
+ }
- switch -- $m {
- AM -
- _O {set new A*}
- _M -
- MM {set new M*}
- AD -
- _D {set new D*}
- default {return}
+ puts -nonewline $fd $path
+ puts -nonewline $fd "\0"
+ display_file $path $new
+ if {$ui_fname_value eq $path} {
+ set update_index_rsd 1
+ }
}
- with_update_index {update_index $path}
- display_file $path $new
- if {$ui_fname_value == $path} {
- show_diff $path
- }
+ set ui_status_value [format \
+ "Including files ... %i/%i files (%.2f%%)" \
+ $update_index_cp \
+ $totalCnt \
+ [expr {100.0 * $update_index_cp / $totalCnt}]]
}
######################################################################
foreach remote $all_remotes {
set rb {}
- if {[array get repo_config remote.$remote.url] != {}} {
- if {[array get repo_config remote.$remote.fetch] != {}} {
+ if {[array get repo_config remote.$remote.url] ne {}} {
+ if {[array get repo_config remote.$remote.fetch] ne {}} {
regexp {^([^:]+):} \
[lindex $repo_config(remote.$remote.fetch) 0] \
line rb
set rb_short $rb
regsub ^refs/heads/ $rb {} rb_short
- if {$rb_short != {}} {
+ if {$rb_short ne {}} {
$m add command \
-label "Branch $rb_short from $remote..." \
-command [list pull_remote $remote $rb] \
if {$max_status_desc < [string length [lindex $i 3]]} {
set max_status_desc [string length [lindex $i 3]]
}
- if {[lindex $i 1] == {i}} {
+ if {[lindex $i 1] eq {i}} {
set all_cols([lindex $i 0]) $ui_index
} else {
set all_cols([lindex $i 0]) $ui_other
proc is_MacOSX {} {
global tcl_platform tk_library
- if {$tcl_platform(platform) == {unix}
- && $tcl_platform(os) == {Darwin}
+ if {$tcl_platform(platform) eq {unix}
+ && $tcl_platform(os) eq {Darwin}
&& [string match /Library/Frameworks/* $tk_library]} {
return 1
}
set w .hookfail
toplevel $w
- wm transient $w .
frame $w.m
label $w.m.l1 -text "$hook hook failed:" \
# -- Windows tosses the enviroment when we exec our child.
# But most users need that so we have to relogin. :-(
#
- if {$tcl_platform(platform) == {windows}} {
+ if {$tcl_platform(platform) eq {windows}} {
set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"]
}
global console_cr console_data
set buf [read $fd]
- if {$buf != {}} {
+ if {$buf ne {}} {
if {![winfo exists $w]} {console_init $w}
$w.m.t conf -state normal
set c 0
}
array unset console_cr $w
array unset console_data $w
- if {$after != {}} {
+ if {$after ne {}} {
uplevel #0 $after $ok
}
return
set ui_status_value $starting_gitk_msg
after 10000 {
- if {$ui_status_value == $starting_gitk_msg} {
+ if {$ui_status_value eq $starting_gitk_msg} {
set ui_status_value {Ready.}
}
}
- if {$tcl_platform(platform) == {windows}} {
+ if {$tcl_platform(platform) eq {windows}} {
exec sh -c gitk &
} else {
exec gitk &
set is_quitting 0
proc do_quit {} {
- global gitdir ui_comm is_quitting
+ global gitdir ui_comm is_quitting repo_config
if {$is_quitting} return
set is_quitting 1
+ # -- Stash our current commit buffer.
+ #
set save [file join $gitdir GITGUI_MSG]
set msg [string trim [$ui_comm get 0.0 end]]
- if {[$ui_comm edit modified] && $msg != {}} {
+ if {[$ui_comm edit modified] && $msg ne {}} {
catch {
set fd [open $save w]
puts $fd [string trim [$ui_comm get 0.0 end]]
close $fd
}
- } elseif {$msg == {} && [file exists $save]} {
+ } elseif {$msg eq {} && [file exists $save]} {
file delete $save
}
- save_my_config
+ # -- Stash our current window geometry into this repository.
+ #
+ set cfg_geometry [list]
+ lappend cfg_geometry [wm geometry .]
+ lappend cfg_geometry [lindex [.vpane sash coord 0] 1]
+ lappend cfg_geometry [lindex [.vpane.files sash coord 0] 0]
+ if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
+ set rc_geometry {}
+ }
+ if {$cfg_geometry ne $rc_geometry} {
+ catch {exec git repo-config gui.geometry $cfg_geometry}
+ }
+
destroy .
}
}
proc do_include_all {} {
- global update_active ui_status_value
-
- if {$update_active || ![lock_index begin-update]} return
-
- set update_active 1
- set ui_status_value {Including all modified files...}
- after 1 {
- with_update_index {
- foreach path [array names file_states] {
- set s $file_states($path)
- set m [lindex $s 0]
- switch -- $m {
- AM -
- MM -
- _M -
- _D {toggle_mode $path}
- }
- }
+ global file_states
+
+ if {![lock_index begin-update]} return
+
+ set pathList [list]
+ foreach path [array names file_states] {
+ set s $file_states($path)
+ set m [lindex $s 0]
+ switch -- $m {
+ AM -
+ MM -
+ _M -
+ _D {lappend pathList $path}
}
- set update_active 0
- set ui_status_value {Ready.}
+ }
+ if {$pathList eq {}} {
+ unlock_index
+ } else {
+ update_index $pathList
}
}
proc do_signoff {} {
global ui_comm GIT_COMMITTER_IDENT
- if {$GIT_COMMITTER_IDENT == {}} {
+ if {$GIT_COMMITTER_IDENT eq {}} {
if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
error_popup "Unable to obtain your identity:\n\n$err"
return
set sob "Signed-off-by: $GIT_COMMITTER_IDENT"
set last [$ui_comm get {end -1c linestart} {end -1c}]
- if {$last != $sob} {
+ if {$last ne $sob} {
$ui_comm edit separator
- if {$last != {}
+ if {$last ne {}
&& ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} {
$ui_comm insert end "\n"
}
commit_tree
}
+proc do_options {} {
+ global appname gitdir font_descs
+ global repo_config global_config
+ global repo_config_new global_config_new
+
+ array unset repo_config_new
+ array unset global_config_new
+ foreach name [array names repo_config] {
+ set repo_config_new($name) $repo_config($name)
+ }
+ load_config 1
+ foreach name [array names repo_config] {
+ switch -- $name {
+ gui.diffcontext {continue}
+ }
+ set repo_config_new($name) $repo_config($name)
+ }
+ foreach name [array names global_config] {
+ set global_config_new($name) $global_config($name)
+ }
+ set reponame [lindex [file split \
+ [file normalize [file dirname $gitdir]]] \
+ end]
+
+ set w .options_editor
+ toplevel $w
+ wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
+
+ label $w.header -text "$appname Options" \
+ -font font_uibold
+ pack $w.header -side top -fill x
+
+ frame $w.buttons
+ button $w.buttons.restore -text {Restore Defaults} \
+ -font font_ui \
+ -command do_restore_defaults
+ pack $w.buttons.restore -side left
+ button $w.buttons.save -text Save \
+ -font font_ui \
+ -command [list do_save_config $w]
+ pack $w.buttons.save -side right
+ button $w.buttons.cancel -text {Cancel} \
+ -font font_ui \
+ -command [list destroy $w]
+ pack $w.buttons.cancel -side right
+ pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+ labelframe $w.repo -text "$reponame Repository" \
+ -font font_ui \
+ -relief raised -borderwidth 2
+ labelframe $w.global -text {Global (All Repositories)} \
+ -font font_ui \
+ -relief raised -borderwidth 2
+ pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5
+ pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5
+
+ foreach option {
+ {b pullsummary {Show Pull Summary}}
+ {b trustmtime {Trust File Modification Timestamps}}
+ {i diffcontext {Number of Diff Context Lines}}
+ } {
+ set type [lindex $option 0]
+ set name [lindex $option 1]
+ set text [lindex $option 2]
+ foreach f {repo global} {
+ switch $type {
+ b {
+ checkbutton $w.$f.$name -text $text \
+ -variable ${f}_config_new(gui.$name) \
+ -onvalue true \
+ -offvalue false \
+ -font font_ui
+ pack $w.$f.$name -side top -anchor w
+ }
+ i {
+ frame $w.$f.$name
+ label $w.$f.$name.l -text "$text:" -font font_ui
+ pack $w.$f.$name.l -side left -anchor w -fill x
+ spinbox $w.$f.$name.v \
+ -textvariable ${f}_config_new(gui.$name) \
+ -from 1 -to 99 -increment 1 \
+ -width 3 \
+ -font font_ui
+ pack $w.$f.$name.v -side right -anchor e
+ pack $w.$f.$name -side top -anchor w -fill x
+ }
+ }
+ }
+ }
+
+ set all_fonts [lsort [font families]]
+ foreach option $font_descs {
+ set name [lindex $option 0]
+ set font [lindex $option 1]
+ set text [lindex $option 2]
+
+ set global_config_new(gui.$font^^family) \
+ [font configure $font -family]
+ set global_config_new(gui.$font^^size) \
+ [font configure $font -size]
+
+ frame $w.global.$name
+ label $w.global.$name.l -text "$text:" -font font_ui
+ pack $w.global.$name.l -side left -anchor w -fill x
+ eval tk_optionMenu $w.global.$name.family \
+ global_config_new(gui.$font^^family) \
+ $all_fonts
+ spinbox $w.global.$name.size \
+ -textvariable global_config_new(gui.$font^^size) \
+ -from 2 -to 80 -increment 1 \
+ -width 3 \
+ -font font_ui
+ pack $w.global.$name.size -side right -anchor e
+ pack $w.global.$name.family -side right -anchor e
+ pack $w.global.$name -side top -anchor w -fill x
+ }
+
+ bind $w <Visibility> "grab $w; focus $w"
+ bind $w <Key-Escape> "destroy $w"
+ wm title $w "$appname ($reponame): Options"
+ tkwait window $w
+}
+
+proc do_restore_defaults {} {
+ global font_descs default_config repo_config
+ global repo_config_new global_config_new
+
+ foreach name [array names default_config] {
+ set repo_config_new($name) $default_config($name)
+ set global_config_new($name) $default_config($name)
+ }
+
+ foreach option $font_descs {
+ set name [lindex $option 0]
+ set repo_config(gui.$name) $default_config(gui.$name)
+ }
+ apply_config
+
+ foreach option $font_descs {
+ set name [lindex $option 0]
+ set font [lindex $option 1]
+ set global_config_new(gui.$font^^family) \
+ [font configure $font -family]
+ set global_config_new(gui.$font^^size) \
+ [font configure $font -size]
+ }
+}
+
+proc do_save_config {w} {
+ if {[catch {save_config} err]} {
+ error_popup "Failed to completely save options:\n\n$err"
+ }
+ reshow_diff
+ destroy $w
+}
+
# shift == 1: left click
# 3: right click
proc click {w x y shift wx wy} {
set lno [lindex $pos 0]
set col [lindex $pos 1]
set path [lindex $file_lists($w) [expr $lno - 1]]
- if {$path == {}} return
+ if {$path eq {}} return
if {$col > 0 && $shift == 1} {
show_diff $path $w $lno
set lno [lindex $pos 0]
set col [lindex $pos 1]
set path [lindex $file_lists($w) [expr $lno - 1]]
- if {$path == {}} return
+ if {$path eq {}} return
if {$col == 0} {
- toggle_mode $path
+ update_index [list $path]
}
}
######################################################################
##
-## ui init
+## config defaults
-set cursor_ptr left_ptr
+set cursor_ptr arrow
font create font_diff -family Courier -size 10
font create font_ui
catch {
destroy .dummy
}
-eval font create font_uibold [font configure font_ui]
-font configure font_uibold -weight bold
-eval font create font_diffbold [font configure font_diff]
-font configure font_diffbold -weight bold
+font create font_uibold
+font create font_diffbold
set M1B M1
set M1T M1
-if {$tcl_platform(platform) == {windows}} {
+if {$tcl_platform(platform) eq {windows}} {
set M1B Control
set M1T Ctrl
} elseif {[is_MacOSX]} {
set M1T Cmd
}
+proc apply_config {} {
+ global repo_config font_descs
+
+ foreach option $font_descs {
+ set name [lindex $option 0]
+ set font [lindex $option 1]
+ if {[catch {
+ foreach {cn cv} $repo_config(gui.$name) {
+ font configure $font $cn $cv
+ }
+ } err]} {
+ error_popup "Invalid font specified in gui.$name:\n\n$err"
+ }
+ foreach {cn cv} [font configure $font] {
+ font configure ${font}bold $cn $cv
+ }
+ font configure ${font}bold -weight bold
+ }
+}
+
+set default_config(gui.trustmtime) false
+set default_config(gui.pullsummary) true
+set default_config(gui.diffcontext) 5
+set default_config(gui.fontui) [font configure font_ui]
+set default_config(gui.fontdiff) [font configure font_diff]
+set font_descs {
+ {fontui font_ui {Main Font}}
+ {fontdiff font_diff {Diff/Console Font}}
+}
+load_config 0
+apply_config
+
+######################################################################
+##
+## ui construction
+
# -- Menu Bar
menu .mbar -tearoff 0
.mbar add cascade -label Project -menu .mbar.project
.mbar add cascade -label Edit -menu .mbar.edit
.mbar add cascade -label Commit -menu .mbar.commit
-.mbar add cascade -label Fetch -menu .mbar.fetch
-.mbar add cascade -label Pull -menu .mbar.pull
-.mbar add cascade -label Push -menu .mbar.push
-.mbar add cascade -label Options -menu .mbar.options
+if {!$single_commit} {
+ .mbar add cascade -label Fetch -menu .mbar.fetch
+ .mbar add cascade -label Pull -menu .mbar.pull
+ .mbar add cascade -label Push -menu .mbar.push
+}
. configure -menu .mbar
# -- Project Menu
.mbar.project add command -label Visualize \
-command do_gitk \
-font font_ui
-.mbar.project add command -label {Repack Database} \
- -command do_repack \
- -font font_ui
+if {!$single_commit} {
+ .mbar.project add command -label {Repack Database} \
+ -command do_repack \
+ -font font_ui
+}
.mbar.project add command -label Quit \
-command do_quit \
-accelerator $M1T-Q \
-command {catch {[focus] tag add sel 0.0 end}} \
-accelerator $M1T-A \
-font font_ui
+.mbar.edit add separator
+.mbar.edit add command -label {Options...} \
+ -command do_options \
+ -font font_ui
# -- Commit Menu
menu .mbar.commit
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
-# -- Fetch Menu
-menu .mbar.fetch
-
-# -- Pull Menu
-menu .mbar.pull
+if {!$single_commit} {
+ # -- Fetch Menu
+ menu .mbar.fetch
-# -- Push Menu
-menu .mbar.push
+ # -- Pull Menu
+ menu .mbar.pull
-# -- Options Menu
-menu .mbar.options
-.mbar.options add checkbutton \
- -label {Trust File Modification Timestamps} \
- -font font_ui \
- -offvalue false \
- -onvalue true \
- -variable cfg_trust_mtime
+ # -- Push Menu
+ menu .mbar.push
+}
# -- Main Window Layout
panedwindow .vpane -orient vertical
$ui_other tag conf in_diff -font font_uibold
# -- Diff and Commit Area
-frame .vpane.lower -height 400 -width 400
+frame .vpane.lower -height 300 -width 400
frame .vpane.lower.commarea
frame .vpane.lower.diff -relief sunken -borderwidth 1
pack .vpane.lower.commarea -side top -fill x
$ui_diff.ctxm add command -label "Increase Font Size" \
-font font_ui \
-command {incr_font_size font_diff 1}
+$ui_diff.ctxm add separator
+$ui_diff.ctxm add command -label "Show Less Context" \
+ -font font_ui \
+ -command {if {$ui_fname_value ne {}
+ && $repo_config(gui.diffcontext) >= 2} {
+ incr repo_config(gui.diffcontext) -1
+ reshow_diff
+ }}
+$ui_diff.ctxm add command -label "Show More Context" \
+ -font font_ui \
+ -command {if {$ui_fname_value ne {}} {
+ incr repo_config(gui.diffcontext)
+ reshow_diff
+ }}
+$ui_diff.ctxm add separator
+$ui_diff.ctxm add command -label {Options...} \
+ -font font_ui \
+ -command do_options
bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y"
# -- Status Bar
# -- Load geometry
catch {
-set gm [lindex $repo_config(gui.geometry) 0]
+set gm $repo_config(gui.geometry)
wm geometry . [lindex $gm 0]
.vpane sash place 0 \
[lindex [.vpane sash coord 0] 0] \
wm title . "$appname ([file normalize [file dirname $gitdir]])"
focus -force $ui_comm
-load_all_remotes
-populate_remote_menu .mbar.fetch From fetch_from
-populate_remote_menu .mbar.push To push_to
-populate_pull_menu .mbar.pull
-update_status
+if {!$single_commit} {
+ load_all_remotes
+ populate_remote_menu .mbar.fetch From fetch_from
+ populate_remote_menu .mbar.push To push_to
+ populate_pull_menu .mbar.pull
+}
+after 1 update_status