{"thread":{"id":"16355","subject":"[PATCH (GIT-GUI) v2 0/5] Add a customizable Tools menu.","startedAt":"2008-11-16T18:46:46Z","lastAt":"2008-11-16T21:56:15Z","messageCount":7,"participants":["Alexander Gavrilov","Shawn O. Pearce"],"isPatch":true,"patchVersion":2,"patchTotal":5},"messages":[{"id":"95962","messageId":"1226861211-16995-1-git-send-email-angavrilov@gmail.com","threadId":"16355","inReplyTo":null,"subject":"[PATCH (GIT-GUI) v2 0/5] Add a customizable Tools menu.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-11-16T18:46:46Z","receivedAt":"2008-11-16T18:46:46Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"This series adds a customizable Tools menu, that can\nbe used to call any external commands from Git Gui.\nIt reduces the inconvenience of using tools like git-svn\nwith GUI, by removing the need to jump between the\nterminal and the GUI even for simple actions. QGit\nalready has a similar feature.\n\nUPDATES:\n\n  1) Tweaked some of the text strings to make UI look better.\n  2) Added auto-rescan functionality.\n\n  Sorry for sending an incomplete WIP version 3 days ago.\n\n\nSUMMARY:\n\n    git-gui.sh        |   70 +++++++--\n    lib/diff.tcl      |    6 +-\n    lib/option.tcl    |   12 +-\n    lib/tools.tcl     |  159 ++++++++++++++++++++\n    lib/tools_dlg.tcl |  421 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n    5 files changed, 643 insertions(+), 25 deletions(-)\n\n\nPATCHES:\n\n    git-gui: Implement system-wide configuration handling.\n    ---\n    git-gui.sh     |   12 +++++++++---\n    lib/option.tcl |   12 ++++++------\n    2 files changed, 15 insertions(+), 9 deletions(-)\n\n  (NEW) git-gui: Fix the after callback execution in rescan.\n    ---\n    git-gui.sh   |   41 ++++++++++++++++++++++++++++-------------\n    lib/diff.tcl |    6 +++---\n    2 files changed, 31 insertions(+), 16 deletions(-)\n\n    git-gui: Add a Tools menu for arbitrary commands.\n    ---\n    git-gui.sh        |   17 ++++\n    lib/tools.tcl     |  108 ++++++++++++++++++++++++\n    lib/tools_dlg.tcl |  234 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n    3 files changed, 359 insertions(+), 0 deletions(-)\n    create mode 100644 lib/tools.tcl\n    create mode 100644 lib/tools_dlg.tcl\n\n    git-gui: Allow Tools request arguments from the user.\n    ---\n    lib/tools.tcl     |   13 +++-\n    lib/tools_dlg.tcl |  195 +++++++++++++++++++++++++++++++++++++++++++++++++++-\n    2 files changed, 203 insertions(+), 5 deletions(-)\n\n  (NEW) git-gui: Implement automatic rescan after Tool execution.\n    ---\n    lib/tools.tcl |   44 ++++++++++++++++++++++++++++++++++++++++++--\n    1 files changed, 42 insertions(+), 2 deletions(-)\n"},{"id":"95963","messageId":"1226861211-16995-2-git-send-email-angavrilov@gmail.com","threadId":"16355","inReplyTo":"1226861211-16995-1-git-send-email-angavrilov@gmail.com","subject":"[PATCH (GIT-GUI) v2 1/5] git-gui: Implement system-wide configuration handling.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-11-16T18:46:47Z","receivedAt":"2008-11-16T18:46:47Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"With the old implementation any system-wide options appear\nto be set locally in the current repository. This commit\nadds explicit handling of system options, essentially\ninterpreting them as customized default_config.\n\nThe difficulty in interpreting system options stems from\nthe fact that simple 'git config' lists all values, while\n'git config --global' only values set in ~/.gitconfig,\nexcluding both local and system options.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n git-gui.sh     |   12 +++++++++---\n lib/option.tcl |   12 ++++++------\n 2 files changed, 15 insertions(+), 9 deletions(-)\n\ndiff --git a/git-gui.sh b/git-gui.sh\nindex cf9ef6e..34214b6 100755\n--- a/git-gui.sh\n+++ b/git-gui.sh\n@@ -918,19 +918,25 @@ git-version proc _parse_config {arr_name args} {\n }\n \n proc load_config {include_global} {\n-\tglobal repo_config global_config default_config\n+\tglobal repo_config global_config system_config default_config\n \n \tif {$include_global} {\n+\t\t_parse_config system_config --system\n \t\t_parse_config global_config --global\n \t}\n \t_parse_config repo_config\n \n \tforeach name [array names default_config] {\n+\t\tif {[catch {set v $system_config($name)}]} {\n+\t\t\tset system_config($name) $default_config($name)\n+\t\t}\n+\t}\n+\tforeach name [array names system_config] {\n \t\tif {[catch {set v $global_config($name)}]} {\n-\t\t\tset global_config($name) $default_config($name)\n+\t\t\tset global_config($name) $system_config($name)\n \t\t}\n \t\tif {[catch {set v $repo_config($name)}]} {\n-\t\t\tset repo_config($name) $default_config($name)\n+\t\t\tset repo_config($name) $system_config($name)\n \t\t}\n \t}\n }\ndiff --git a/lib/option.tcl b/lib/option.tcl\nindex c80c939..1d55b49 100644\n--- a/lib/option.tcl\n+++ b/lib/option.tcl\n@@ -25,7 +25,7 @@ proc config_check_encodings {} {\n \n proc save_config {} {\n \tglobal default_config font_descs\n-\tglobal repo_config global_config\n+\tglobal repo_config global_config system_config\n \tglobal repo_config_new global_config_new\n \tglobal ui_comm_spell\n \n@@ -49,7 +49,7 @@ proc save_config {} {\n \tforeach name [array names default_config] {\n \t\tset value $global_config_new($name)\n \t\tif {$value ne $global_config($name)} {\n-\t\t\tif {$value eq $default_config($name)} {\n+\t\t\tif {$value eq $system_config($name)} {\n \t\t\t\tcatch {git config --global --unset $name}\n \t\t\t} else {\n \t\t\t\tregsub -all \"\\[{}\\]\" $value {\"} value\n@@ -284,17 +284,17 @@ proc do_options {} {\n }\n \n proc do_restore_defaults {} {\n-\tglobal font_descs default_config repo_config\n+\tglobal font_descs default_config repo_config system_config\n \tglobal repo_config_new global_config_new\n \n \tforeach name [array names default_config] {\n-\t\tset repo_config_new($name) $default_config($name)\n-\t\tset global_config_new($name) $default_config($name)\n+\t\tset repo_config_new($name) $system_config($name)\n+\t\tset global_config_new($name) $system_config($name)\n \t}\n \n \tforeach option $font_descs {\n \t\tset name [lindex $option 0]\n-\t\tset repo_config(gui.$name) $default_config(gui.$name)\n+\t\tset repo_config(gui.$name) $system_config(gui.$name)\n \t}\n \tapply_config\n \n-- \n1.6.0.3.15.gb8d36\n"},{"id":"95964","messageId":"1226861211-16995-3-git-send-email-angavrilov@gmail.com","threadId":"16355","inReplyTo":"1226861211-16995-2-git-send-email-angavrilov@gmail.com","subject":"[PATCH (GIT-GUI) v2 2/5] git-gui: Fix the after callback execution in rescan.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-11-16T18:46:48Z","receivedAt":"2008-11-16T18:46:48Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"The rescan function receives a callback command\nas its parameter, which is supposed to be executed\nafter the scan finishes. It is generally used to\nupdate status. However, rescan may initiate a\nloading of a diff, which always calls ui_ready after\ncompletion. If the after handler is called before\nthat, ui_ready will override the new status.\n\nThis commit ensures that the after callback is\nproperly threaded through the diff machinery.\n\nSince it uncovered the fact that force_first_diff\nactually didn't work due to an undeclared global\nvariable, and the desired effects appeared only\nbecause of the race condition between the diff\nsystem and the rescan callback, I also reimplement\nthis function to make it behave as originally\nintended.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n git-gui.sh   |   41 ++++++++++++++++++++++++++++-------------\n lib/diff.tcl |    6 +++---\n 2 files changed, 31 insertions(+), 16 deletions(-)\n\ndiff --git a/git-gui.sh b/git-gui.sh\nindex 34214b6..2709f6e 100755\n--- a/git-gui.sh\n+++ b/git-gui.sh\n@@ -1469,10 +1469,8 @@ proc rescan_done {fd buf after} {\n \tprune_selection\n \tunlock_index\n \tdisplay_all_files\n-\tif {$current_diff_path ne {}} reshow_diff\n-\tif {$current_diff_path eq {}} select_first_diff\n-\n-\tuplevel #0 $after\n+\tif {$current_diff_path ne {}} { reshow_diff $after }\n+\tif {$current_diff_path eq {}} { select_first_diff $after }\n }\n \n proc prune_selection {} {\n@@ -1984,16 +1982,16 @@ proc do_rescan {} {\n }\n \n proc ui_do_rescan {} {\n-\trescan {force_first_diff; ui_ready}\n+\trescan {force_first_diff ui_ready}\n }\n \n proc do_commit {} {\n \tcommit_tree\n }\n \n-proc next_diff {} {\n+proc next_diff {{after {}}} {\n \tglobal next_diff_p next_diff_w next_diff_i\n-\tshow_diff $next_diff_p $next_diff_w {}\n+\tshow_diff $next_diff_p $next_diff_w {} {} $after\n }\n \n proc find_anchor_pos {lst name} {\n@@ -2078,25 +2076,42 @@ proc next_diff_after_action {w path {lno {}} {mmask {}}} {\n \t}\n }\n \n-proc select_first_diff {} {\n+proc select_first_diff {after} {\n \tglobal ui_workdir\n \n \tif {[find_next_diff $ui_workdir {} 1 {^_?U}] ||\n \t    [find_next_diff $ui_workdir {} 1 {[^O]$}]} {\n-\t\tnext_diff\n+\t\tnext_diff $after\n+\t} else {\n+\t\tuplevel #0 $after\n \t}\n }\n \n-proc force_first_diff {} {\n-\tglobal current_diff_path\n+proc force_first_diff {after} {\n+\tglobal ui_workdir current_diff_path file_states\n \n \tif {[info exists file_states($current_diff_path)]} {\n \t\tset state [lindex $file_states($current_diff_path) 0]\n+\t} else {\n+\t\tset state {OO}\n+\t}\n \n-\t\tif {[string index $state 1] ne {O}} return\n+\tset reselect 0\n+\tif {[string first {U} $state] >= 0} {\n+\t\t# Already a conflict, do nothing\n+\t} elseif {[find_next_diff $ui_workdir $current_diff_path {} {^_?U}]} {\n+\t\tset reselect 1\n+\t} elseif {[string index $state 1] ne {O}} {\n+\t\t# Already a diff & no conflicts, do nothing\n+\t} elseif {[find_next_diff $ui_workdir $current_diff_path {} {[^O]$}]} {\n+\t\tset reselect 1\n \t}\n \n-\tselect_first_diff\n+\tif {$reselect} {\n+\t\tnext_diff $after\n+\t} else {\n+\t\tuplevel #0 $after\n+\t}\n }\n \n proc toggle_or_diff {w x y} {\ndiff --git a/lib/diff.tcl b/lib/diff.tcl\nindex 94ee38c..bbbf15c 100644\n--- a/lib/diff.tcl\n+++ b/lib/diff.tcl\n@@ -16,7 +16,7 @@ proc clear_diff {} {\n \t$ui_workdir tag remove in_diff 0.0 end\n }\n \n-proc reshow_diff {} {\n+proc reshow_diff {{after {}}} {\n \tglobal file_states file_lists\n \tglobal current_diff_path current_diff_side\n \tglobal ui_diff\n@@ -30,13 +30,13 @@ proc reshow_diff {} {\n \t\t|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {\n \n \t\tif {[find_next_diff $current_diff_side $p {} {[^O]}]} {\n-\t\t\tnext_diff\n+\t\t\tnext_diff $after\n \t\t} else {\n \t\t\tclear_diff\n \t\t}\n \t} else {\n \t\tset save_pos [lindex [$ui_diff yview] 0]\n-\t\tshow_diff $p $current_diff_side {} $save_pos\n+\t\tshow_diff $p $current_diff_side {} $save_pos $after\n \t}\n }\n \n-- \n1.6.0.3.15.gb8d36\n"},{"id":"95966","messageId":"1226861211-16995-4-git-send-email-angavrilov@gmail.com","threadId":"16355","inReplyTo":"1226861211-16995-3-git-send-email-angavrilov@gmail.com","subject":"[PATCH (GIT-GUI) v2 3/5] git-gui: Add a Tools menu for arbitrary commands.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-11-16T18:46:49Z","receivedAt":"2008-11-16T18:46:49Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"Due to the emphasis on scriptability in the git\ndesign, it is impossible to provide 100% complete\nGUI. Currently unaccounted areas include git-svn\nand other source control system interfaces, TopGit,\nall custom scripts.\n\nThis problem can be mitigated by providing basic\ncustomization capabilities in Git Gui. This commit\nadds a new Tools menu, which can be configured\nto contain items invoking arbitrary shell commands.\n\nThe interface is powerful enough to allow calling\nboth batch text programs like git-svn, and GUI editors.\nTo support the latter use, the commands have access\nto the name of the currently selected file through\nthe environment.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n git-gui.sh        |   17 ++++\n lib/tools.tcl     |  108 ++++++++++++++++++++++++\n lib/tools_dlg.tcl |  234 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 359 insertions(+), 0 deletions(-)\n create mode 100644 lib/tools.tcl\n create mode 100644 lib/tools_dlg.tcl\n\ndiff --git a/git-gui.sh b/git-gui.sh\nindex 2709f6e..0751211 100755\n--- a/git-gui.sh\n+++ b/git-gui.sh\n@@ -2267,6 +2267,9 @@ if {[is_enabled transport]} {\n \t.mbar add cascade -label [mc Merge] -menu .mbar.merge\n \t.mbar add cascade -label [mc Remote] -menu .mbar.remote\n }\n+if {[is_enabled multicommit] || [is_enabled singlecommit]} {\n+\t.mbar add cascade -label [mc Tools] -menu .mbar.tools\n+}\n . configure -menu .mbar\n \n # -- Repository Menu\n@@ -2541,6 +2544,20 @@ if {[is_MacOSX]} {\n \t\t-command do_options\n }\n \n+# -- Tools Menu\n+#\n+if {[is_enabled multicommit] || [is_enabled singlecommit]} {\n+\tset tools_menubar .mbar.tools\n+\tmenu $tools_menubar\n+\t$tools_menubar add separator\n+\t$tools_menubar add command -label [mc \"Add...\"] -command tools_add::dialog\n+\t$tools_menubar add command -label [mc \"Remove...\"] -command tools_remove::dialog\n+\tset tools_tailcnt 3\n+\tif {[array names repo_config guitool.*.cmd] ne {}} {\n+\t\ttools_populate_all\n+\t}\n+}\n+\n # -- Help Menu\n #\n .mbar add cascade -label [mc Help] -menu .mbar.help\ndiff --git a/lib/tools.tcl b/lib/tools.tcl\nnew file mode 100644\nindex 0000000..00d46dd\n--- /dev/null\n+++ b/lib/tools.tcl\n@@ -0,0 +1,108 @@\n+# git-gui Tools menu implementation\n+\n+proc tools_list {} {\n+\tglobal repo_config\n+\n+\tset names {}\n+\tforeach item [array names repo_config guitool.*.cmd] {\n+\t\tlappend names [string range $item 8 end-4]\n+\t}\n+\treturn [lsort $names]\n+}\n+\n+proc tools_populate_all {} {\n+\tglobal tools_menubar tools_menutbl\n+\tglobal tools_tailcnt\n+\n+\tset mbar_end [$tools_menubar index end]\n+\tset mbar_base [expr {$mbar_end - $tools_tailcnt}]\n+\tif {$mbar_base >= 0} {\n+\t\t$tools_menubar delete 0 $mbar_base\n+\t}\n+\n+\tarray unset tools_menutbl\n+\n+\tforeach fullname [tools_list] {\n+\t\ttools_populate_one $fullname\n+\t}\n+}\n+\n+proc tools_create_item {parent args} {\n+\tglobal tools_menubar tools_tailcnt\n+\tif {$parent eq $tools_menubar} {\n+\t\tset pos [expr {[$parent index end]-$tools_tailcnt+1}]\n+\t\teval [list $parent insert $pos] $args\n+\t} else {\n+\t\teval [list $parent add] $args\n+\t}\n+}\n+\n+proc tools_populate_one {fullname} {\n+\tglobal tools_menubar tools_menutbl tools_id\n+\n+\tif {![info exists tools_id]} {\n+\t\tset tools_id 0\n+\t}\n+\n+\tset names [split $fullname '/']\n+\tset parent $tools_menubar\n+\tfor {set i 0} {$i < [llength $names]-1} {incr i} {\n+\t\tset subname [join [lrange $names 0 $i] '/']\n+\t\tif {[info exists tools_menutbl($subname)]} {\n+\t\t\tset parent $tools_menutbl($subname)\n+\t\t} else {\n+\t\t\tset subid $parent.t$tools_id\n+\t\t\ttools_create_item $parent cascade \\\n+\t\t\t\t\t-label [lindex $names $i] -menu $subid\n+\t\t\tmenu $subid\n+\t\t\tset tools_menutbl($subname) $subid\n+\t\t\tset parent $subid\n+\t\t\tincr tools_id\n+\t\t}\n+\t}\n+\n+\ttools_create_item $parent command \\\n+\t\t-label [lindex $names end] \\\n+\t\t-command [list tools_exec $fullname]\n+}\n+\n+proc tools_exec {fullname} {\n+\tglobal repo_config env current_diff_path\n+\tglobal current_branch is_detached\n+\n+\tif {[is_config_true \"guitool.$fullname.needsfile\"]} {\n+\t\tif {$current_diff_path eq {}} {\n+\t\t\terror_popup [mc \"Running %s requires a selected file.\" $fullname]\n+\t\t\treturn\n+\t\t}\n+\t}\n+\n+\tif {[is_config_true \"guitool.$fullname.confirm\"]} {\n+\t\tif {[ask_popup [mc \"Are you sure you want to run %s?\" $fullname]] ne {yes}} {\n+\t\t\treturn\n+\t\t}\n+\t}\n+\n+\tset env(GIT_GUITOOL) $fullname\n+\tset env(FILENAME) $current_diff_path\n+\tif {$is_detached} {\n+\t\tset env(CUR_BRANCH) \"\"\n+\t} else {\n+\t\tset env(CUR_BRANCH) $current_branch\n+\t}\n+\n+\tset cmdline $repo_config(guitool.$fullname.cmd)\n+\tif {[is_config_true \"guitool.$fullname.noconsole\"]} {\n+\t\texec sh -c $cmdline &\n+\t} else {\n+\t\tregsub {/} $fullname { / } title\n+\t\tset w [console::new \\\n+\t\t\t[mc \"Tool: %s\" $title] \\\n+\t\t\t[mc \"Running: %s\" $cmdline]]\n+\t\tconsole::exec $w [list sh -c $cmdline]\n+\t}\n+\n+\tunset env(GIT_GUITOOL)\n+\tunset env(FILENAME)\n+\tunset env(CUR_BRANCH)\n+}\ndiff --git a/lib/tools_dlg.tcl b/lib/tools_dlg.tcl\nnew file mode 100644\nindex 0000000..c221ba9\n--- /dev/null\n+++ b/lib/tools_dlg.tcl\n@@ -0,0 +1,234 @@\n+# git-gui Tools menu dialogs\n+\n+class tools_add {\n+\n+field w              ; # widget path\n+field w_name         ; # new remote name widget\n+field w_cmd          ; # new remote location widget\n+\n+field name         {}; # name of the tool\n+field command      {}; # command to execute\n+field add_global    0; # add to the --global config\n+field no_console    0; # disable using the console\n+field needs_file    0; # ensure filename is set\n+field confirm       0; # ask for confirmation\n+\n+constructor dialog {} {\n+\tglobal repo_config\n+\n+\tmake_toplevel top w\n+\twm title $top [append \"[appname] ([reponame]): \" [mc \"Add Tool\"]]\n+\tif {$top ne {.}} {\n+\t\twm geometry $top \"+[winfo rootx .]+[winfo rooty .]\"\n+\t\twm transient $top .\n+\t}\n+\n+\tlabel $w.header -text [mc \"Add New Tool Command\"] -font font_uibold\n+\tpack $w.header -side top -fill x\n+\n+\tframe $w.buttons\n+\tcheckbutton $w.buttons.global \\\n+\t\t-text [mc \"Add globally\"] \\\n+\t\t-variable @add_global\n+\tpack $w.buttons.global -side left -padx 5\n+\tbutton $w.buttons.create -text [mc Add] \\\n+\t\t-default active \\\n+\t\t-command [cb _add]\n+\tpack $w.buttons.create -side right\n+\tbutton $w.buttons.cancel -text [mc Cancel] \\\n+\t\t-command [list destroy $w]\n+\tpack $w.buttons.cancel -side right -padx 5\n+\tpack $w.buttons -side bottom -fill x -pady 10 -padx 10\n+\n+\tlabelframe $w.desc -text [mc \"Tool Details\"]\n+\n+\tlabel $w.desc.name_cmnt -anchor w\\\n+\t\t-text [mc \"Use '/' separators to create a submenu tree:\"]\n+\tgrid x $w.desc.name_cmnt -sticky we -padx {0 5} -pady {0 2}\n+\tlabel $w.desc.name_l -text [mc \"Name:\"]\n+\tset w_name $w.desc.name_t\n+\tentry $w_name \\\n+\t\t-borderwidth 1 \\\n+\t\t-relief sunken \\\n+\t\t-width 40 \\\n+\t\t-textvariable @name \\\n+\t\t-validate key \\\n+\t\t-validatecommand [cb _validate_name %d %S]\n+\tgrid $w.desc.name_l $w_name -sticky we -padx {0 5}\n+\n+\tlabel $w.desc.cmd_l -text [mc \"Command:\"]\n+\tset w_cmd $w.desc.cmd_t\n+\tentry $w_cmd \\\n+\t\t-borderwidth 1 \\\n+\t\t-relief sunken \\\n+\t\t-width 40 \\\n+\t\t-textvariable @command\n+\tgrid $w.desc.cmd_l $w_cmd -sticky we -padx {0 5} -pady {0 3}\n+\n+\tgrid columnconfigure $w.desc 1 -weight 1\n+\tpack $w.desc -anchor nw -fill x -pady 5 -padx 5\n+\n+\tcheckbutton $w.confirm \\\n+\t\t-text [mc \"Ask for confirmation before running\"] \\\n+\t\t-variable @confirm\n+\tpack $w.confirm -anchor w -pady {5 0} -padx 5\n+\n+\tcheckbutton $w.noconsole \\\n+\t\t-text [mc \"Don't show the command output window\"] \\\n+\t\t-variable @no_console\n+\tpack $w.noconsole -anchor w -padx 5\n+\n+\tcheckbutton $w.needsfile \\\n+\t\t-text [mc \"Run only if a diff is selected (\\$FILENAME not empty)\"] \\\n+\t\t-variable @needs_file\n+\tpack $w.needsfile -anchor w -padx 5\n+\n+\tbind $w <Visibility> [cb _visible]\n+\tbind $w <Key-Escape> [list destroy $w]\n+\tbind $w <Key-Return> [cb _add]\\;break\n+\ttkwait window $w\n+}\n+\n+method _add {} {\n+\tglobal repo_config\n+\n+\tif {$name eq {}} {\n+\t\terror_popup [mc \"Please supply a name for the tool.\"]\n+\t\tfocus $w_name\n+\t\treturn\n+\t}\n+\n+\tset item \"guitool.$name.cmd\"\n+\n+\tif {[info exists repo_config($item)]} {\n+\t\terror_popup [mc \"Tool '%s' already exists.\" $name]\n+\t\tfocus $w_name\n+\t\treturn\n+\t}\n+\n+\tset cmd [list git config]\n+\tif {$add_global} { lappend cmd --global }\n+\tset items {}\n+\tif {$no_console} { lappend items \"guitool.$name.noconsole\" }\n+\tif {$confirm}    { lappend items \"guitool.$name.confirm\" }\n+\tif {$needs_file} { lappend items \"guitool.$name.needsfile\" }\n+\n+\tif {[catch {\n+\t\teval $cmd [list $item $command]\n+\t\tforeach citem $items { eval $cmd [list $citem yes] }\n+\t    } err]} {\n+\t\terror_popup [mc \"Could not add tool:\\n%s\" $err]\n+\t} else {\n+\t\tset repo_config($item) $command\n+\t\tforeach citem $items { set repo_config($citem) yes }\n+\n+\t\ttools_populate_all\n+\t}\n+\n+\tdestroy $w\n+}\n+\n+method _validate_name {d S} {\n+\tif {$d == 1} {\n+\t\tif {[regexp {[~?*&\\[\\0\\\"\\\\\\{]} $S]} {\n+\t\t\treturn 0\n+\t\t}\n+\t}\n+\treturn 1\n+}\n+\n+method _visible {} {\n+\tgrab $w\n+\t$w_name icursor end\n+\tfocus $w_name\n+}\n+\n+}\n+\n+class tools_remove {\n+\n+field w              ; # widget path\n+field w_names        ; # name list\n+\n+constructor dialog {} {\n+\tglobal repo_config global_config system_config\n+\n+\tload_config 1\n+\n+\tmake_toplevel top w\n+\twm title $top [append \"[appname] ([reponame]): \" [mc \"Remove Tool\"]]\n+\tif {$top ne {.}} {\n+\t\twm geometry $top \"+[winfo rootx .]+[winfo rooty .]\"\n+\t\twm transient $top .\n+\t}\n+\n+\tlabel $w.header -text [mc \"Remove Tool Commands\"] -font font_uibold\n+\tpack $w.header -side top -fill x\n+\n+\tframe $w.buttons\n+\tbutton $w.buttons.create -text [mc Remove] \\\n+\t\t-default active \\\n+\t\t-command [cb _remove]\n+\tpack $w.buttons.create -side right\n+\tbutton $w.buttons.cancel -text [mc Cancel] \\\n+\t\t-command [list destroy $w]\n+\tpack $w.buttons.cancel -side right -padx 5\n+\tpack $w.buttons -side bottom -fill x -pady 10 -padx 10\n+\n+\tframe $w.list\n+\tset w_names $w.list.l\n+\tlistbox $w_names \\\n+\t\t-height 10 \\\n+\t\t-width 30 \\\n+\t\t-selectmode extended \\\n+\t\t-exportselection false \\\n+\t\t-yscrollcommand [list $w.list.sby set]\n+\tscrollbar $w.list.sby -command [list $w.list.l yview]\n+\tpack $w.list.sby -side right -fill y\n+\tpack $w.list.l -side left -fill both -expand 1\n+\tpack $w.list -fill both -expand 1 -pady 5 -padx 5\n+\n+\tset local_cnt 0\n+\tforeach fullname [tools_list] {\n+\t\t# Cannot delete system tools\n+\t\tif {[info exists system_config(guitool.$fullname.cmd)]} continue\n+\n+\t\t$w_names insert end $fullname\n+\t\tif {![info exists global_config(guitool.$fullname.cmd)]} {\n+\t\t\t$w_names itemconfigure end -foreground blue\n+\t\t\tincr local_cnt\n+\t\t}\n+\t}\n+\n+\tif {$local_cnt > 0} {\n+\t\tlabel $w.colorlbl -foreground blue \\\n+\t\t\t-text [mc \"(Blue denotes repository-local tools)\"]\n+\t\tpack $w.colorlbl -fill x -pady 5 -padx 5\n+\t}\n+\n+\tbind $w <Visibility> [cb _visible]\n+\tbind $w <Key-Escape> [list destroy $w]\n+\tbind $w <Key-Return> [cb _remove]\\;break\n+\ttkwait window $w\n+}\n+\n+method _remove {} {\n+\tforeach i [$w_names curselection] {\n+\t\tset name [$w_names get $i]\n+\n+\t\tcatch { git config --remove-section guitool.$name }\n+\t\tcatch { git config --global --remove-section guitool.$name }\n+\t}\n+\n+\tload_config 0\n+\ttools_populate_all\n+\n+\tdestroy $w\n+}\n+\n+method _visible {} {\n+\tgrab $w\n+\tfocus $w_names\n+}\n+\n+}\n-- \n1.6.0.3.15.gb8d36\n"},{"id":"95965","messageId":"1226861211-16995-5-git-send-email-angavrilov@gmail.com","threadId":"16355","inReplyTo":"1226861211-16995-4-git-send-email-angavrilov@gmail.com","subject":"[PATCH (GIT-GUI) v2 4/5] git-gui: Allow Tools request arguments from the user.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-11-16T18:46:50Z","receivedAt":"2008-11-16T18:46:50Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"While static commands are already useful, some tools need\nadditional parameters to reach maximum usability. This\ncommit adds support for passing them one revision name\nparameter, and one arbitrary string. With this addition,\nthe tools menu becomes flexible enough to implement basic\nrebase support:\n\n[core]\n        editor = kwrite\n[guitool \"Rebase/Abort\"]\n        cmd = git rebase --abort\n        confirm = yes\n[guitool \"Rebase/Continue\"]\n        cmd = git rebase --continue\n[guitool \"Rebase/Skip Commit\"]\n        cmd = git rebase --skip\n        confirm = yes\n[guitool \"Rebase/Start...\"]\n        cmd = git rebase $ARGS $REVISION $CUR_BRANCH\n        title = Start Rebase\n        prompt = Rebase Current Branch\n        argprompt = Flags\n        revprompt = New Base\n        revunmerged = yes\n\nSome of the options, like title or prompt, are intentionally\nnot included in the Add dialog to avoid clutter. Also, the\ndialog handles argprompt and revprompt as boolean vars.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n lib/tools.tcl     |   13 +++-\n lib/tools_dlg.tcl |  195 +++++++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 203 insertions(+), 5 deletions(-)\n\ndiff --git a/lib/tools.tcl b/lib/tools.tcl\nindex 00d46dd..044432e 100644\n--- a/lib/tools.tcl\n+++ b/lib/tools.tcl\n@@ -77,7 +77,16 @@ proc tools_exec {fullname} {\n \t\t}\n \t}\n \n-\tif {[is_config_true \"guitool.$fullname.confirm\"]} {\n+\tcatch { unset env(ARGS) }\n+\tcatch { unset env(REVISION) }\n+\n+\tif {[get_config \"guitool.$fullname.revprompt\"] ne {} ||\n+\t    [get_config \"guitool.$fullname.argprompt\"] ne {}} {\n+\t\tset dlg [tools_askdlg::dialog $fullname]\n+\t\tif {![tools_askdlg::execute $dlg]} {\n+\t\t\treturn\n+\t\t}\n+\t} elseif {[is_config_true \"guitool.$fullname.confirm\"]} {\n \t\tif {[ask_popup [mc \"Are you sure you want to run %s?\" $fullname]] ne {yes}} {\n \t\t\treturn\n \t\t}\n@@ -105,4 +114,6 @@ proc tools_exec {fullname} {\n \tunset env(GIT_GUITOOL)\n \tunset env(FILENAME)\n \tunset env(CUR_BRANCH)\n+\tcatch { unset env(ARGS) }\n+\tcatch { unset env(REVISION) }\n }\ndiff --git a/lib/tools_dlg.tcl b/lib/tools_dlg.tcl\nindex c221ba9..5f7f08e 100644\n--- a/lib/tools_dlg.tcl\n+++ b/lib/tools_dlg.tcl\n@@ -12,6 +12,8 @@ field add_global    0; # add to the --global config\n field no_console    0; # disable using the console\n field needs_file    0; # ensure filename is set\n field confirm       0; # ask for confirmation\n+field ask_branch    0; # ask for a revision\n+field ask_args      0; # ask for additional args\n \n constructor dialog {} {\n \tglobal repo_config\n@@ -69,9 +71,22 @@ constructor dialog {} {\n \tpack $w.desc -anchor nw -fill x -pady 5 -padx 5\n \n \tcheckbutton $w.confirm \\\n-\t\t-text [mc \"Ask for confirmation before running\"] \\\n-\t\t-variable @confirm\n-\tpack $w.confirm -anchor w -pady {5 0} -padx 5\n+\t\t-text [mc \"Show a dialog before running\"] \\\n+\t\t-variable @confirm -command [cb _check_enable_dlg]\n+\n+\tlabelframe $w.dlg -labelwidget $w.confirm\n+\n+\tcheckbutton $w.dlg.askbranch \\\n+\t\t-text [mc \"Ask the user to select a revision (sets \\$REVISION)\"] \\\n+\t\t-variable @ask_branch -state disabled\n+\tpack $w.dlg.askbranch -anchor w -padx 15\n+\n+\tcheckbutton $w.dlg.askargs \\\n+\t\t-text [mc \"Ask the user for additional arguments (sets \\$ARGS)\"] \\\n+\t\t-variable @ask_args -state disabled\n+\tpack $w.dlg.askargs -anchor w -padx 15\n+\n+\tpack $w.dlg -anchor nw -fill x -pady {0 8} -padx 5\n \n \tcheckbutton $w.noconsole \\\n \t\t-text [mc \"Don't show the command output window\"] \\\n@@ -89,6 +104,16 @@ constructor dialog {} {\n \ttkwait window $w\n }\n \n+method _check_enable_dlg {} {\n+\tif {$confirm} {\n+\t\t$w.dlg.askbranch configure -state normal\n+\t\t$w.dlg.askargs configure -state normal\n+\t} else {\n+\t\t$w.dlg.askbranch configure -state disabled\n+\t\t$w.dlg.askargs configure -state disabled\n+\t}\n+}\n+\n method _add {} {\n \tglobal repo_config\n \n@@ -110,8 +135,14 @@ method _add {} {\n \tif {$add_global} { lappend cmd --global }\n \tset items {}\n \tif {$no_console} { lappend items \"guitool.$name.noconsole\" }\n-\tif {$confirm}    { lappend items \"guitool.$name.confirm\" }\n \tif {$needs_file} { lappend items \"guitool.$name.needsfile\" }\n+\tif {$confirm} {\n+\t\tif {$ask_args}   { lappend items \"guitool.$name.argprompt\" }\n+\t\tif {$ask_branch} { lappend items \"guitool.$name.revprompt\" }\n+\t\tif {!$ask_args && !$ask_branch} {\n+\t\t\tlappend items \"guitool.$name.confirm\"\n+\t\t}\n+\t}\n \n \tif {[catch {\n \t\teval $cmd [list $item $command]\n@@ -232,3 +263,159 @@ method _visible {} {\n }\n \n }\n+\n+class tools_askdlg {\n+\n+field w              ; # widget path\n+field w_rev        {}; # revision browser\n+field w_args       {}; # arguments\n+\n+field is_ask_args   0; # has arguments field\n+field is_ask_revs   0; # has revision browser\n+\n+field is_ok         0; # ok to start\n+field argstr       {}; # arguments\n+\n+constructor dialog {fullname} {\n+\tglobal M1B\n+\n+\tset title [get_config \"guitool.$fullname.title\"]\n+\tif {$title eq {}} {\n+\t\tregsub {/} $fullname { / } title\n+\t}\n+\n+\tmake_toplevel top w -autodelete 0\n+\twm title $top [append \"[appname] ([reponame]): \" $title]\n+\tif {$top ne {.}} {\n+\t\twm geometry $top \"+[winfo rootx .]+[winfo rooty .]\"\n+\t\twm transient $top .\n+\t}\n+\n+\tset prompt [get_config \"guitool.$fullname.prompt\"]\n+\tif {$prompt eq {}} {\n+\t\tset command [get_config \"guitool.$fullname.cmd\"]\n+\t\tset prompt [mc \"Run Command: %s\" $command]\n+\t}\n+\n+\tlabel $w.header -text $prompt -font font_uibold\n+\tpack $w.header -side top -fill x\n+\n+\tset argprompt [get_config \"guitool.$fullname.argprompt\"]\n+\tset revprompt [get_config \"guitool.$fullname.revprompt\"]\n+\n+\tset is_ask_args [expr {$argprompt ne {}}]\n+\tset is_ask_revs [expr {$revprompt ne {}}]\n+\n+\tif {$is_ask_args} {\n+\t\tif {$argprompt eq {yes} || $argprompt eq {true} || $argprompt eq {1}} {\n+\t\t\tset argprompt [mc \"Arguments\"]\n+\t\t}\n+\n+\t\tlabelframe $w.arg -text $argprompt\n+\n+\t\tset w_args $w.arg.txt\n+\t\tentry $w_args \\\n+\t\t\t-borderwidth 1 \\\n+\t\t\t-relief sunken \\\n+\t\t\t-width 40 \\\n+\t\t\t-textvariable @argstr\n+\t\tpack $w_args -padx 5 -pady 5 -fill both\n+\t\tpack $w.arg -anchor nw -fill both -pady 5 -padx 5\n+\t}\n+\n+\tif {$is_ask_revs} {\n+\t\tif {$revprompt eq {yes} || $revprompt eq {true} || $revprompt eq {1}} {\n+\t\t\tset revprompt [mc \"Revision\"]\n+\t\t}\n+\n+\t\tif {[is_config_true \"guitool.$fullname.revunmerged\"]} {\n+\t\t\tset w_rev [::choose_rev::new_unmerged $w.rev $revprompt]\n+\t\t} else {\n+\t\t\tset w_rev [::choose_rev::new $w.rev $revprompt]\n+\t\t}\n+\n+\t\tpack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5\n+\t}\n+\n+\tframe $w.buttons\n+\tif {$is_ask_revs} {\n+\t\tbutton $w.buttons.visualize \\\n+\t\t\t-text [mc Visualize] \\\n+\t\t\t-command [cb _visualize]\n+\t\tpack $w.buttons.visualize -side left\n+\t}\n+\tbutton $w.buttons.ok \\\n+\t\t-text [mc OK] \\\n+\t\t-command [cb _start]\n+\tpack $w.buttons.ok -side right\n+\tbutton $w.buttons.cancel \\\n+\t\t-text [mc \"Cancel\"] \\\n+\t\t-command [cb _cancel]\n+\tpack $w.buttons.cancel -side right -padx 5\n+\tpack $w.buttons -side bottom -fill x -pady 10 -padx 10\n+\n+\tbind $w <$M1B-Key-Return> [cb _start]\n+\tbind $w <Key-Return> [cb _start]\n+\tbind $w <Key-Escape> [cb _cancel]\n+\twm protocol $w WM_DELETE_WINDOW [cb _cancel]\n+\n+\tbind $w <Visibility> [cb _visible]\n+\treturn $this\n+}\n+\n+method execute {} {\n+\ttkwait window $w\n+\tset rv $is_ok\n+\tdelete_this\n+\treturn $rv\n+}\n+\n+method _visible {} {\n+\tgrab $w\n+\tif {$is_ask_args} {\n+\t\tfocus $w_args\n+\t} elseif {$is_ask_revs} {\n+\t\t$w_rev focus_filter\n+\t}\n+}\n+\n+method _cancel {} {\n+\twm protocol $w WM_DELETE_WINDOW {}\n+\tdestroy $w\n+}\n+\n+method _rev {} {\n+\tif {[catch {$w_rev commit_or_die}]} {\n+\t\treturn {}\n+\t}\n+\treturn [$w_rev get]\n+}\n+\n+method _visualize {} {\n+\tglobal current_branch\n+\tset rev [_rev $this]\n+\tif {$rev ne {}} {\n+\t\tdo_gitk [list --left-right \"$current_branch...$rev\"]\n+\t}\n+}\n+\n+method _start {} {\n+\tglobal env\n+\n+\tif {$is_ask_revs} {\n+\t\tset name [_rev $this]\n+\t\tif {$name eq {}} {\n+\t\t\treturn\n+\t\t}\n+\t\tset env(REVISION) $name\n+\t}\n+\n+\tif {$is_ask_args} {\n+\t\tset env(ARGS) $argstr\n+\t}\n+\n+\tset is_ok 1\n+\t_cancel $this\n+}\n+\n+}\n-- \n1.6.0.3.15.gb8d36\n"},{"id":"95967","messageId":"1226861211-16995-6-git-send-email-angavrilov@gmail.com","threadId":"16355","inReplyTo":"1226861211-16995-5-git-send-email-angavrilov@gmail.com","subject":"[PATCH (GIT-GUI) v2 5/5] git-gui: Implement automatic rescan after Tool execution.","fromName":"Alexander Gavrilov","fromEmail":"angavrilov@gmail.com","sentAt":"2008-11-16T18:46:51Z","receivedAt":"2008-11-16T18:46:51Z","isPatch":true,"sender":{"key":"angavrilov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42666?v=4"},"body":"The Tools menu is generally intended for commands that\naffect the working directory or repository state. Thus,\nthe user would usually want to initiate rescan after\nexecution of a tool. This commit implements it.\n\nIn case somebody would want to avoid rescanning after\ncertain tools, it also adds an option that controls it,\nalthough it is not made available through the Add dialog.\n\nSigned-off-by: Alexander Gavrilov <angavrilov@gmail.com>\n---\n lib/tools.tcl |   44 ++++++++++++++++++++++++++++++++++++++++++--\n 1 files changed, 42 insertions(+), 2 deletions(-)\n\ndiff --git a/lib/tools.tcl b/lib/tools.tcl\nindex 044432e..51366b0 100644\n--- a/lib/tools.tcl\n+++ b/lib/tools.tcl\n@@ -102,13 +102,15 @@ proc tools_exec {fullname} {\n \n \tset cmdline $repo_config(guitool.$fullname.cmd)\n \tif {[is_config_true \"guitool.$fullname.noconsole\"]} {\n-\t\texec sh -c $cmdline &\n+\t\ttools_run_silent [list sh -c $cmdline] \\\n+\t\t\t\t [list tools_complete $fullname {}]\n \t} else {\n \t\tregsub {/} $fullname { / } title\n \t\tset w [console::new \\\n \t\t\t[mc \"Tool: %s\" $title] \\\n \t\t\t[mc \"Running: %s\" $cmdline]]\n-\t\tconsole::exec $w [list sh -c $cmdline]\n+\t\tconsole::exec $w [list sh -c $cmdline] \\\n+\t\t\t\t [list tools_complete $fullname $w]\n \t}\n \n \tunset env(GIT_GUITOOL)\n@@ -117,3 +119,41 @@ proc tools_exec {fullname} {\n \tcatch { unset env(ARGS) }\n \tcatch { unset env(REVISION) }\n }\n+\n+proc tools_run_silent {cmd after} {\n+\tlappend cmd 2>@1\n+\tset fd [_open_stdout_stderr $cmd]\n+\t\n+\tfconfigure $fd -blocking 0 -translation binary\n+\tfileevent $fd readable [list tools_consume_input $fd $after]\n+}\n+\n+proc tools_consume_input {fd after} {\n+\tread $fd\n+\tif {[eof $fd]} {\n+\t\tfconfigure $fd -blocking 1\n+\t\tif {[catch {close $fd}]} {\n+\t\t\tuplevel #0 $after 0\n+\t\t} else {\n+\t\t\tuplevel #0 $after 1\n+\t\t}\n+\t}\n+}\n+\n+proc tools_complete {fullname w {ok 1}} {\n+\tif {$w ne {}} {\n+\t\tconsole::done $w $ok\n+\t}\n+\n+\tif {$ok} {\n+\t\tset msg [mc \"Tool completed succesfully: %s\" $fullname]\n+\t} else {\n+\t\tset msg [mc \"Tool failed: %s\" $fullname]\n+\t}\n+\n+\tif {[is_config_true \"guitool.$fullname.norescan\"]} {\n+\t\tui_status $msg\n+\t} else {\n+\t\trescan [list ui_status $msg]\n+\t}\n+}\n-- \n1.6.0.3.15.gb8d36\n"},{"id":"95977","messageId":"20081116215615.GE2932@spearce.org","threadId":"16355","inReplyTo":"1226861211-16995-1-git-send-email-angavrilov@gmail.com","subject":"Re: [PATCH (GIT-GUI) v2 0/5] Add a customizable Tools menu.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-11-16T21:56:15Z","receivedAt":"2008-11-16T21:56:15Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Alexander Gavrilov <angavrilov@gmail.com> wrote:\n> This series adds a customizable Tools menu, that can\n> be used to call any external commands from Git Gui.\n> It reduces the inconvenience of using tools like git-svn\n> with GUI, by removing the need to jump between the\n> terminal and the GUI even for simple actions. QGit\n> already has a similar feature.\n\nThanks.  This is really slick.  Its in my tree now.\n\nGiven that 1.6.1 is entering rc mode, I'm probably not going to be\naccepting any more new features into my master branch until 1.6.1\nfreezes.  Everything after this will wind up in `pu` until I cut\ngit-gui 0.12.0.\n \n-- \nShawn.\n"}]}