##
## 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 != $global_config($name)} {
+ if {$value == $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 == $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 != $repo_config($name)} {
+ if {$value == $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
+ }
}
}
}
unset cdup
+set single_commit 0
if {$appname == {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
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
$ui_comm edit reset
}
- if {$cfg_trust_mtime == {true}} {
+ if {$repo_config(gui.trustmtime) == {true}} {
update_status_stage2 {} $final
} else {
set status_active 1
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 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) == {true}
+ && [$ui_diff index end] == {2.0}} {
handle_empty_diff
}
}
}
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
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) == {false}} {
+ lappend cmd --no-summary
+ }
lappend cmd $remote
lappend cmd $branch
console_exec $w $cmd [list post_pull_remote $remote $branch]
$ui_other conf -state disabled
}
-proc with_update_index {body} {
- global update_index_fd
+proc update_index {pathList} {
+ global update_index_cp 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 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 -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 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
+ 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 == $path} {
+ show_diff $path
+ }
}
- 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}]]
}
######################################################################
set w .hookfail
toplevel $w
- wm transient $w .
frame $w.m
label $w.m.l1 -text "$hook hook failed:" \
console_exec $w $cmd
}
-set quitting 0
+set is_quitting 0
proc do_quit {} {
- global gitdir ui_comm quitting
+ global gitdir ui_comm is_quitting repo_config
- if {$quitting} return
- set quitting 1
+ 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 != {}} {
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 != $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 == {}} {
+ unlock_index
+ } else {
+ update_index $pathList
}
}
commit_tree
}
+proc do_options {} {
+ global appname gitdir font_descs
+ global repo_config global_config
+ global repo_config_new global_config_new
+
+ load_config 1
+ array unset repo_config_new
+ array unset global_config_new
+ foreach name [array names repo_config] {
+ 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 {
+ {pullsummary {Show Pull Summary}}
+ {trustmtime {Trust File Modification Timestamps}}
+ } {
+ set name [lindex $option 0]
+ set text [lindex $option 1]
+ foreach f {repo global} {
+ 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
+ }
+ }
+
+ 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"
+ }
+ destroy $w
+}
+
# shift == 1: left click
# 3: right click
proc click {w x y shift wx wy} {
if {$path == {}} 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
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.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 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