X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-gui;h=ca7f8dbc414b365a70489a5323f6e9ee440eb5c5;hb=fce89e466ae75961018ab88fec7000568f981d46;hp=f8c51590b04a664bb5dd149d330d6ef44d37c665;hpb=390adaeafbefc49a88d06c3a2ad68bc00fe0c614;p=git.git diff --git a/git-gui b/git-gui index f8c51590b..ca7f8dbc4 100755 --- a/git-gui +++ b/git-gui @@ -14,49 +14,108 @@ set gitdir {} ## ## 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 + } } } @@ -64,7 +123,7 @@ proc error_popup {msg} { global gitdir appname set title $appname - if {$gitdir != {}} { + if {$gitdir ne {}} { append title { (} append title [lindex \ [file split [file normalize [file dirname $gitdir]]] \ @@ -79,6 +138,25 @@ proc error_popup {msg} { -message $msg } +proc info_popup {msg} { + global gitdir appname + + set title $appname + if {$gitdir ne {}} { + append title { (} + append title [lindex \ + [file split [file normalize [file dirname $gitdir]]] \ + end] + append title {)} + } + tk_messageBox \ + -parent . \ + -icon error \ + -type ok \ + -title $title \ + -message $msg +} + ###################################################################### ## ## repository setup @@ -89,27 +167,22 @@ if { [catch {set cdup [exec git rev-parse --show-cdup]} err] 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 @@ -121,13 +194,13 @@ set commit_type {} 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 } @@ -164,14 +237,14 @@ proc update_status {{final Ready.}} { 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 @@ -181,7 +254,7 @@ proc update_status {{final Ready.}} { 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]} { @@ -190,12 +263,17 @@ proc update_status {{final Ready.}} { $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 set ui_status_value {Refreshing file status...} - set fd_rf [open "| git update-index -q --unmerged --refresh" r] + set cmd [list git update-index] + lappend cmd -q + lappend cmd --unmerged + lappend cmd --ignore-missing + lappend cmd --refresh + set fd_rf [open "| $cmd" r] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ [list update_status_stage2 $fd_rf $final] @@ -208,7 +286,7 @@ proc update_status_stage2 {fd final} { global status_active global buf_rdi buf_rdf buf_rlo - if {$fd != {}} { + if {$fd ne {}} { read $fd if {![eof $fd]} return close $fd @@ -364,7 +442,7 @@ proc clear_diff {} { 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 { @@ -372,15 +450,51 @@ proc reshow_diff {} { } } +proc handle_empty_diff {} { + global ui_fname_value file_states file_lists + + set path $ui_fname_value + set s $file_states($path) + if {[lindex $s 0] ne {_M}} return + + info_popup "No differences detected. + +[short_path $path] has no changes. + +The modification date of this file was updated by another +application and you currently have the Trust File Modification +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 +prevent possible confusion. +" + if {[catch {exec git update-index -- $path} err]} { + error_popup "Failed to refresh index:\n\n$err" + } + + clear_diff + set old_w [mapcol [lindex $file_states($path) 0] $path] + set lno [lsearch -sorted $file_lists($old_w) $path] + if {$lno >= 0} { + set file_lists($old_w) \ + [lreplace $file_lists($old_w) $lno $lno] + incr lno + $old_w conf -state normal + $old_w delete $lno.0 [expr $lno + 1].0 + $old_w conf -state disabled + } +} + 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} { @@ -389,7 +503,7 @@ proc show_diff {path {w {}} {lno {}}} { } } } - if {$w != {} && $lno >= 1} { + if {$w ne {} && $lno >= 1} { $w tag add in_diff $lno.0 [expr $lno + 1].0 } @@ -397,14 +511,20 @@ proc show_diff {path {w {}} {lno {}}} { set m [lindex $s 0] set diff_3way 0 set diff_active 1 - set ui_fname_value [escape_path $path] + set ui_fname_value $path 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 { @@ -428,6 +548,10 @@ proc show_diff {path {w {}} {lno {}}} { } } + lappend cmd $PARENT + lappend cmd -- + lappend cmd $path + if {[catch {set fd [open $cmd r]} err]} { set diff_active 0 unlock_index @@ -442,6 +566,7 @@ proc show_diff {path {w {}} {lno {}}} { proc read_diff {fd} { global ui_diff ui_status_value diff_3way diff_active + global repo_config while {[gets $fd line] >= 0} { if {[string match {diff --git *} $line]} continue @@ -488,6 +613,11 @@ proc read_diff {fd} { set diff_active 0 unlock_index set ui_status_value {Ready.} + + if {$repo_config(gui.trustmtime) eq {true} + && [$ui_diff index end] eq {2.0}} { + handle_empty_diff + } } } @@ -498,8 +628,8 @@ proc read_diff {fd} { 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 } @@ -543,18 +673,18 @@ proc load_last_commit {} { 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 @@ -579,7 +709,7 @@ before committing. U? { error_popup "Unmerged files cannot be committed. -File [escape_path $path] has merge conflicts. +File [short_path $path] has merge conflicts. You must resolve them and include the file before committing. " unlock_index @@ -588,7 +718,7 @@ You must resolve them and include the file before committing. default { error_popup "Unknown file state [lindex $s 0] detected. -File [escape_path $path] cannot be committed by this program. +File [short_path $path] cannot be committed by this program. " } } @@ -605,7 +735,7 @@ You must include at least 1 file before you can commit. # -- 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: @@ -621,38 +751,65 @@ 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 @@ -661,10 +818,10 @@ proc commit_stage2 {fd_wt curHEAD msg} { # -- 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} { @@ -673,20 +830,18 @@ proc commit_stage2 {fd_wt curHEAD msg} { 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 @@ -695,7 +850,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { # -- 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] @@ -707,7 +862,6 @@ proc commit_stage2 {fd_wt curHEAD 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 @@ -726,6 +880,21 @@ proc commit_stage2 {fd_wt curHEAD msg} { 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 @@ -734,7 +903,6 @@ proc commit_stage2 {fd_wt curHEAD msg} { # -- Update status without invoking any git commands. # - set commit_active 0 set commit_type normal set HEAD $cmt_id set PARENT $cmt_id @@ -748,7 +916,7 @@ proc commit_stage2 {fd_wt curHEAD msg} { D? {set m _[string index $m 1]} } - if {$m == {__}} { + if {$m eq {__}} { unset file_states($path) } else { lset file_states($path) 0 $m @@ -775,15 +943,14 @@ proc fetch_from {remote} { } 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 @@ -812,6 +979,9 @@ Commit or throw away all changes before starting a pull operation. 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] @@ -879,6 +1049,10 @@ proc escape_path {path} { return $path } +proc short_path {path} { + return [escape_path [lindex [file split $path] end]] +} + set next_icon_id 0 proc merge_state {path new_state} { @@ -895,15 +1069,15 @@ proc merge_state {path new_state} { 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 _ } @@ -912,7 +1086,6 @@ proc merge_state {path new_state} { } proc display_file {path state} { - global ui_index ui_other global file_states file_lists status_active set old_m [merge_state $path $state] @@ -924,7 +1097,7 @@ proc display_file {path state} { 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 @@ -944,7 +1117,7 @@ proc display_file {path state} { -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 @@ -960,7 +1133,9 @@ proc display_all_files {} { $ui_index delete 0.0 end $ui_other delete 0.0 end - array unset file_lists + set file_lists($ui_index) [list] + set file_lists($ui_other) [list] + foreach path [lsort [array names file_states]] { set s $file_states($path) set m [lindex $s 0] @@ -977,55 +1152,83 @@ proc display_all_files {} { $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}]] } ###################################################################### @@ -1055,22 +1258,22 @@ proc load_all_remotes {} { } proc populate_remote_menu {m pfx op} { - global all_remotes font_ui + global all_remotes foreach remote $all_remotes { $m add command -label "$pfx $remote..." \ -command [list $op $remote] \ - -font $font_ui + -font font_ui } } proc populate_pull_menu {m} { - global gitdir repo_config all_remotes font_ui disable_on_lock + global gitdir repo_config all_remotes disable_on_lock 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 @@ -1089,11 +1292,11 @@ proc populate_pull_menu {m} { 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] \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list $m entryconf [$m index last] -state] } @@ -1182,17 +1385,17 @@ set max_status_desc 0 foreach i { {__ i plain "Unmodified"} {_M i mod "Modified"} - {M_ i fulltick "Checked in"} + {M_ i fulltick "Included in commit"} {MM i parttick "Partially included"} {_O o plain "Untracked"} - {A_ o fulltick "Added"} + {A_ o fulltick "Added by commit"} {AM o parttick "Partially added"} {AD o question "Added (but now gone)"} {_D i question "Missing"} - {D_ i removed "Removed"} - {DD i removed "Removed"} + {D_ i removed "Removed by commit"} + {DD i removed "Removed by commit"} {DO i removed "Removed (still exists)"} {UM i merge "Merge conflicts"} @@ -1201,7 +1404,7 @@ foreach i { 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 @@ -1215,29 +1418,52 @@ unset filemask i ## ## util +proc is_MacOSX {} { + global tcl_platform tk_library + if {$tcl_platform(platform) eq {unix} + && $tcl_platform(os) eq {Darwin} + && [string match /Library/Frameworks/* $tk_library]} { + return 1 + } + return 0 +} + +proc bind_button3 {w cmd} { + bind $w $cmd + if {[is_MacOSX]} { + bind $w $cmd + } +} + +proc incr_font_size {font {amt 1}} { + set sz [font configure $font -size] + incr sz $amt + font configure $font -size $sz + font configure ${font}bold -size $sz +} + proc hook_failed_popup {hook msg} { - global gitdir font_ui font_diff appname + global gitdir appname set w .hookfail toplevel $w - wm transient $w . frame $w.m label $w.m.l1 -text "$hook hook failed:" \ -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold text $w.m.t \ -background white -borderwidth 1 \ -relief sunken \ -width 80 -height 10 \ - -font $font_diff \ + -font font_diff \ -yscrollcommand [list $w.m.sby set] label $w.m.l2 \ -text {You must correct the above errors before committing.} \ -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x pack $w.m.l2 -side bottom -fill x @@ -1250,9 +1476,9 @@ proc hook_failed_popup {hook msg} { button $w.ok -text OK \ -width 15 \ - -font $font_ui \ + -font font_ui \ -command "destroy $w" - pack $w.ok -side bottom + pack $w.ok -side bottom -anchor e -pady 10 -padx 10 bind $w "grab $w; focus $w" bind $w "destroy $w" @@ -1273,7 +1499,7 @@ proc new_console {short_title long_title} { proc console_init {w} { global console_cr console_data - global gitdir appname font_ui font_diff + global gitdir appname M1B set console_cr($w) 1.0 toplevel $w @@ -1281,17 +1507,18 @@ proc console_init {w} { label $w.m.l1 -text "[lindex $console_data($w) 1]:" \ -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold text $w.m.t \ -background white -borderwidth 1 \ -relief sunken \ -width 80 -height 10 \ - -font $font_diff \ + -font font_diff \ -state disabled \ -yscrollcommand [list $w.m.sby set] - label $w.m.s -anchor w \ + label $w.m.s -text {Working... please wait...} \ + -anchor w \ -justify left \ - -font [concat $font_ui bold] + -font font_uibold scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x pack $w.m.s -side bottom -fill x @@ -1299,13 +1526,30 @@ proc console_init {w} { pack $w.m.t -side left -fill both -expand 1 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10 - button $w.ok -text {Running...} \ - -width 15 \ - -font $font_ui \ + menu $w.ctxm -tearoff 0 + $w.ctxm add command -label "Copy" \ + -font font_ui \ + -command "tk_textCopy $w.m.t" + $w.ctxm add command -label "Select All" \ + -font font_ui \ + -command "$w.m.t tag add sel 0.0 end" + $w.ctxm add command -label "Copy All" \ + -font font_ui \ + -command " + $w.m.t tag add sel 0.0 end + tk_textCopy $w.m.t + $w.m.t tag remove sel 0.0 end + " + + button $w.ok -text {Close} \ + -font font_ui \ -state disabled \ -command "destroy $w" - pack $w.ok -side bottom + pack $w.ok -side bottom -anchor e -pady 10 -padx 10 + bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y" + bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break" + bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break" bind $w "focus $w" wm title $w "$appname ([lindex [file split \ [file normalize [file dirname $gitdir]]] \ @@ -1319,7 +1563,7 @@ proc console_exec {w cmd {after {}}} { # -- 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 { }]"] } @@ -1337,7 +1581,7 @@ proc console_read {w fd after} { 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 @@ -1370,18 +1614,16 @@ proc console_read {w fd after} { if {[catch {close $fd}]} { if {![winfo exists $w]} {console_init $w} $w.m.s conf -background red -text {Error: Command Failed} - $w.ok conf -text Close $w.ok conf -state normal set ok 0 } elseif {[winfo exists $w]} { $w.m.s conf -background green -text {Success} - $w.ok conf -text Close $w.ok conf -state normal set ok 1 } array unset console_cr $w array unset console_data $w - if {$after != {}} { + if {$after ne {}} { uplevel #0 $after $ok } return @@ -1400,12 +1642,12 @@ proc do_gitk {} { 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 & @@ -1420,27 +1662,41 @@ proc do_repack {} { 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 != {}} { + 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 . } @@ -1449,27 +1705,25 @@ proc do_rescan {} { } 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 } } @@ -1478,7 +1732,7 @@ set GIT_COMMITTER_IDENT {} 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 @@ -1490,10 +1744,15 @@ proc do_signoff {} { } } - set str "Signed-off-by: $GIT_COMMITTER_IDENT" - if {[$ui_comm get {end -1c linestart} {end -1c}] != $str} { + set sob "Signed-off-by: $GIT_COMMITTER_IDENT" + set last [$ui_comm get {end -1c linestart} {end -1c}] + if {$last ne $sob} { $ui_comm edit separator - $ui_comm insert end "\n$str" + if {$last ne {} + && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} { + $ui_comm insert end "\n" + } + $ui_comm insert end "\n$sob" $ui_comm edit separator $ui_comm see end } @@ -1507,6 +1766,162 @@ proc do_commit {} { 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 "grab $w; focus $w" + bind $w "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} { @@ -1516,7 +1931,7 @@ 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 @@ -1530,50 +1945,101 @@ proc unclick {w x y} { 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 arrow +font create font_diff -family Courier -size 10 +font create font_ui +catch { + label .dummy + eval font configure font_ui [font actual [.dummy cget -font]] + destroy .dummy +} + +font create font_uibold +font create font_diffbold + +set M1B M1 +set M1T M1 +if {$tcl_platform(platform) eq {windows}} { + set M1B Control + set M1T Ctrl +} elseif {[is_MacOSX]} { + set M1B M1 + set M1T Cmd +} + +proc apply_config {} { + global repo_config font_descs -set font_ui {Helvetica 10} -set font_diff {Courier 10} -set maincursor [. cget -cursor] + 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 + } +} -switch -glob -- "$tcl_platform(platform),$tcl_platform(os)" { -windows,* {set M1B Control; set M1T Ctrl} -unix,Darwin {set M1B M1; set M1T Cmd} -* {set M1B M1; set M1T M1} +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 menu .mbar.project .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 + -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 \ - -font $font_ui + -font font_ui # -- Edit Menu # @@ -1581,80 +2047,78 @@ menu .mbar.edit .mbar.edit add command -label Undo \ -command {catch {[focus] edit undo}} \ -accelerator $M1T-Z \ - -font $font_ui + -font font_ui .mbar.edit add command -label Redo \ -command {catch {[focus] edit redo}} \ -accelerator $M1T-Y \ - -font $font_ui + -font font_ui .mbar.edit add separator .mbar.edit add command -label Cut \ -command {catch {tk_textCut [focus]}} \ -accelerator $M1T-X \ - -font $font_ui + -font font_ui .mbar.edit add command -label Copy \ -command {catch {tk_textCopy [focus]}} \ -accelerator $M1T-C \ - -font $font_ui + -font font_ui .mbar.edit add command -label Paste \ -command {catch {tk_textPaste [focus]; [focus] see insert}} \ -accelerator $M1T-V \ - -font $font_ui + -font font_ui .mbar.edit add command -label Delete \ -command {catch {[focus] delete sel.first sel.last}} \ -accelerator Del \ - -font $font_ui + -font font_ui .mbar.edit add separator .mbar.edit add command -label {Select All} \ -command {catch {[focus] tag add sel 0.0 end}} \ -accelerator $M1T-A \ - -font $font_ui + -font font_ui +.mbar.edit add separator +.mbar.edit add command -label {Options...} \ + -command do_options \ + -font font_ui # -- Commit Menu menu .mbar.commit .mbar.commit add command -label Rescan \ -command do_rescan \ -accelerator F5 \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Amend Last Commit} \ -command do_amend_last \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Include All Files} \ -command do_include_all \ -accelerator $M1T-I \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] .mbar.commit add command -label {Sign Off} \ -command do_signoff \ -accelerator $M1T-S \ - -font $font_ui + -font font_ui .mbar.commit add command -label Commit \ -command do_commit \ -accelerator $M1T-Return \ - -font $font_ui + -font font_ui lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] -# -- Fetch Menu -menu .mbar.fetch +if {!$single_commit} { + # -- Fetch Menu + menu .mbar.fetch -# -- Pull Menu -menu .mbar.pull + # -- Pull Menu + menu .mbar.pull -# -- Push Menu -menu .mbar.push - -# -- Options Menu -menu .mbar.options -.mbar.options add checkbutton \ - -label {Trust File Modification Timestamps} \ - -offvalue false \ - -onvalue true \ - -variable cfg_trust_mtime + # -- Push Menu + menu .mbar.push +} # -- Main Window Layout panedwindow .vpane -orient vertical @@ -1666,12 +2130,12 @@ pack .vpane -anchor n -side top -fill both -expand 1 frame .vpane.files.index -height 100 -width 400 label .vpane.files.index.title -text {Modified Files} \ -background green \ - -font $font_ui + -font font_ui text $ui_index -background white -borderwidth 0 \ -width 40 -height 10 \ - -font $font_ui \ + -font font_ui \ + -cursor $cursor_ptr \ -yscrollcommand {.vpane.files.index.sb set} \ - -cursor $maincursor \ -state disabled scrollbar .vpane.files.index.sb -command [list $ui_index yview] pack .vpane.files.index.title -side top -fill x @@ -1683,12 +2147,12 @@ pack $ui_index -side left -fill both -expand 1 frame .vpane.files.other -height 100 -width 100 label .vpane.files.other.title -text {Untracked Files} \ -background red \ - -font $font_ui + -font font_ui text $ui_other -background white -borderwidth 0 \ -width 40 -height 10 \ - -font $font_ui \ + -font font_ui \ + -cursor $cursor_ptr \ -yscrollcommand {.vpane.files.other.sb set} \ - -cursor $maincursor \ -state disabled scrollbar .vpane.files.other.sb -command [list $ui_other yview] pack .vpane.files.other.title -side top -fill x @@ -1696,11 +2160,11 @@ pack .vpane.files.other.sb -side right -fill y pack $ui_other -side left -fill both -expand 1 .vpane.files add .vpane.files.other -sticky nsew -$ui_index tag conf in_diff -font [concat $font_ui bold] -$ui_other tag conf in_diff -font [concat $font_ui bold] +$ui_index tag conf in_diff -font font_uibold +$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 @@ -1712,39 +2176,39 @@ frame .vpane.lower.commarea.buttons label .vpane.lower.commarea.buttons.l -text {} \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.l -side top -fill x pack .vpane.lower.commarea.buttons -side left -fill y button .vpane.lower.commarea.buttons.rescan -text {Rescan} \ -command do_rescan \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.rescan conf -state} button .vpane.lower.commarea.buttons.amend -text {Amend Last} \ -command do_amend_last \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.amend -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.amend conf -state} button .vpane.lower.commarea.buttons.incall -text {Include All} \ -command do_include_all \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.incall -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.incall conf -state} button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \ -command do_signoff \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.signoff -side top -fill x button .vpane.lower.commarea.buttons.commit -text {Commit} \ -command do_commit \ - -font $font_ui + -font font_ui pack .vpane.lower.commarea.buttons.commit -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.commit conf -state} @@ -1756,7 +2220,7 @@ set ui_coml .vpane.lower.commarea.buffer.l label $ui_coml -text {Commit Message:} \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui trace add variable commit_type write {uplevel #0 { switch -glob $commit_type \ initial {$ui_coml conf -text {Initial Commit Message:}} \ @@ -1770,9 +2234,8 @@ text $ui_comm -background white -borderwidth 1 \ -autoseparators true \ -relief sunken \ -width 75 -height 9 -wrap none \ - -font $font_diff \ - -yscrollcommand {.vpane.lower.commarea.buffer.sby set} \ - -cursor $maincursor + -font font_diff \ + -yscrollcommand {.vpane.lower.commarea.buffer.sby set} scrollbar .vpane.lower.commarea.buffer.sby \ -command [list $ui_comm yview] pack $ui_coml -side top -fill x @@ -1780,41 +2243,82 @@ pack .vpane.lower.commarea.buffer.sby -side right -fill y pack $ui_comm -side left -fill y pack .vpane.lower.commarea.buffer -side left -fill y +# -- Commit Message Buffer Context Menu +# +menu $ui_comm.ctxm -tearoff 0 +$ui_comm.ctxm add command -label "Cut" \ + -font font_ui \ + -command "tk_textCut $ui_comm" +$ui_comm.ctxm add command -label "Copy" \ + -font font_ui \ + -command "tk_textCopy $ui_comm" +$ui_comm.ctxm add command -label "Paste" \ + -font font_ui \ + -command "tk_textPaste $ui_comm" +$ui_comm.ctxm add command -label "Delete" \ + -font font_ui \ + -command "$ui_comm delete sel.first sel.last" +$ui_comm.ctxm add separator +$ui_comm.ctxm add command -label "Select All" \ + -font font_ui \ + -command "$ui_comm tag add sel 0.0 end" +$ui_comm.ctxm add command -label "Copy All" \ + -font font_ui \ + -command " + $ui_comm tag add sel 0.0 end + tk_textCopy $ui_comm + $ui_comm tag remove sel 0.0 end + " +$ui_comm.ctxm add separator +$ui_comm.ctxm add command -label "Sign Off" \ + -font font_ui \ + -command do_signoff +bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y" + # -- Diff Header set ui_fname_value {} set ui_fstatus_value {} frame .vpane.lower.diff.header -background orange -label .vpane.lower.diff.header.l1 -text {File:} \ - -background orange \ - -font $font_ui -label .vpane.lower.diff.header.l2 -textvariable ui_fname_value \ +label .vpane.lower.diff.header.l4 \ + -textvariable ui_fstatus_value \ -background orange \ + -width $max_status_desc \ -anchor w \ -justify left \ - -font $font_ui -label .vpane.lower.diff.header.l3 -text {Status:} \ + -font font_ui +label .vpane.lower.diff.header.l1 -text {File:} \ -background orange \ - -font $font_ui -label .vpane.lower.diff.header.l4 -textvariable ui_fstatus_value \ + -font font_ui +set ui_fname .vpane.lower.diff.header.l2 +label $ui_fname \ + -textvariable ui_fname_value \ -background orange \ - -width $max_status_desc \ -anchor w \ -justify left \ - -font $font_ui + -font font_ui +menu $ui_fname.ctxm -tearoff 0 +$ui_fname.ctxm add command -label "Copy" \ + -font font_ui \ + -command { + clipboard clear + clipboard append \ + -format STRING \ + -type STRING \ + -- $ui_fname_value + } +bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y" +pack .vpane.lower.diff.header.l4 -side left pack .vpane.lower.diff.header.l1 -side left -pack .vpane.lower.diff.header.l2 -side left -fill x -pack .vpane.lower.diff.header.l4 -side right -pack .vpane.lower.diff.header.l3 -side right +pack $ui_fname -fill x # -- Diff Body frame .vpane.lower.diff.body set ui_diff .vpane.lower.diff.body.t text $ui_diff -background white -borderwidth 0 \ -width 80 -height 15 -wrap none \ - -font $font_diff \ + -font font_diff \ -xscrollcommand {.vpane.lower.diff.body.sbx set} \ -yscrollcommand {.vpane.lower.diff.body.sby set} \ - -cursor $maincursor \ -state disabled scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ -command [list $ui_diff xview] @@ -1828,10 +2332,53 @@ pack .vpane.lower.diff.body -side bottom -fill both -expand 1 $ui_diff tag conf dm -foreground red $ui_diff tag conf dp -foreground blue -$ui_diff tag conf da -font [concat $font_diff bold] -$ui_diff tag conf di -foreground "#00a000" -$ui_diff tag conf dni -foreground "#a000a0" -$ui_diff tag conf bold -font [concat $font_diff bold] +$ui_diff tag conf di -foreground {#00a000} +$ui_diff tag conf dni -foreground {#a000a0} +$ui_diff tag conf da -font font_diffbold +$ui_diff tag conf bold -font font_diffbold + +# -- Diff Body Context Menu +# +menu $ui_diff.ctxm -tearoff 0 +$ui_diff.ctxm add command -label "Copy" \ + -font font_ui \ + -command "tk_textCopy $ui_diff" +$ui_diff.ctxm add command -label "Select All" \ + -font font_ui \ + -command "$ui_diff tag add sel 0.0 end" +$ui_diff.ctxm add command -label "Copy All" \ + -font font_ui \ + -command " + $ui_diff tag add sel 0.0 end + tk_textCopy $ui_diff + $ui_diff tag remove sel 0.0 end + " +$ui_diff.ctxm add separator +$ui_diff.ctxm add command -label "Decrease Font Size" \ + -font font_ui \ + -command {incr_font_size font_diff -1} +$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 set ui_status_value {Initializing...} @@ -1840,12 +2387,12 @@ label .status -textvariable ui_status_value \ -justify left \ -borderwidth 1 \ -relief sunken \ - -font $font_ui + -font font_ui pack .status -anchor w -side bottom -fill x # -- 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] \ @@ -1897,15 +2444,20 @@ bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} foreach i [list $ui_index $ui_other] { bind $i {click %W %x %y 1 %X %Y; break} - bind $i {click %W %x %y 3 %X %Y; break} bind $i {unclick %W %x %y; break} + bind_button3 $i {click %W %x %y 3 %X %Y; break} } -unset i M1B M1T +unset i + +set file_lists($ui_index) [list] +set file_lists($ui_other) [list] 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