| 1 | # ChangeLog: |
|---|
| 2 | # |
|---|
| 3 | # 9/13/2007: |
|---|
| 4 | # Patch from venks on irc.freenode.net to restore puts functionality |
|---|
| 5 | # in the slave which was lost in a slightly-to-naive alias. |
|---|
| 6 | |
|---|
| 7 | if {[info exists purple::tk_available] && !$purple::tk_available} { |
|---|
| 8 | purple::notify -error {Purple Commander} {Purple Commander cannot be loaded} \ |
|---|
| 9 | {Purple Commander requires Tk support to load properly.} |
|---|
| 10 | error {Tk not available} |
|---|
| 11 | } |
|---|
| 12 | |
|---|
| 13 | load {} Tk |
|---|
| 14 | |
|---|
| 15 | proc slave_init { slave pshell } { |
|---|
| 16 | interp alias $slave purple_puts {} slave_puts $pshell |
|---|
| 17 | $slave eval { |
|---|
| 18 | rename ::puts ::purple_orig_puts |
|---|
| 19 | proc ::puts { args } { |
|---|
| 20 | set len [llength $args] |
|---|
| 21 | if {$len == 1} { |
|---|
| 22 | return [::purple_puts [lindex $args 0]] |
|---|
| 23 | } elseif {$len == 2} { |
|---|
| 24 | if {[lindex $args 0] == "-nonewline"} { |
|---|
| 25 | return [::purple_puts -nonewline \ |
|---|
| 26 | [lindex $args 1]] |
|---|
| 27 | } else { |
|---|
| 28 | return [::purple_orig_puts \ |
|---|
| 29 | [lindex $args 0] \ |
|---|
| 30 | [lindex $args 1]] |
|---|
| 31 | } |
|---|
| 32 | } else { |
|---|
| 33 | return [eval ::purple_orig_puts $args] |
|---|
| 34 | } |
|---|
| 35 | } |
|---|
| 36 | catch { load {} purple } |
|---|
| 37 | catch { source "${purple::user_dir}/commanderrc" } |
|---|
| 38 | } |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | proc slave_puts { pshell args } { |
|---|
| 42 | upvar $pshell shell |
|---|
| 43 | set nonewline 0 |
|---|
| 44 | |
|---|
| 45 | if {[llength $args] < 1} { |
|---|
| 46 | error "wrong # args: puts ?-nonewline? string" |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | if {[string match [lindex $args 0] "-nonewline"]} { |
|---|
| 50 | set nonewline 1 |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | if {[llength $args] > [expr {1 + $nonewline}]} { |
|---|
| 54 | error "wrong # args: puts ?-nonewline string" |
|---|
| 55 | } else { |
|---|
| 56 | $shell(text) insert end [lindex $args $nonewline] puts |
|---|
| 57 | if {!$nonewline} { |
|---|
| 58 | $shell(text) insert end "\n" puts |
|---|
| 59 | } |
|---|
| 60 | } |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | proc shell_reset { pshell } { |
|---|
| 64 | upvar $pshell shell |
|---|
| 65 | |
|---|
| 66 | interp delete $shell(interp) |
|---|
| 67 | set shell(interp) [interp create] |
|---|
| 68 | set shell(current) "" |
|---|
| 69 | set shell(histindex) 1 |
|---|
| 70 | set shell(tmphist) "" |
|---|
| 71 | $shell(text) delete 0.0 end |
|---|
| 72 | slave_init $shell(interp) $pshell |
|---|
| 73 | shell_prompt $pshell |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | proc shell_create { pshell root } { |
|---|
| 77 | upvar $pshell shell |
|---|
| 78 | |
|---|
| 79 | set shell(prompt) "purple] " |
|---|
| 80 | set shell(continue) "+ " |
|---|
| 81 | set shell(current) "" |
|---|
| 82 | set shell(histindex) 1 |
|---|
| 83 | set shell(tmphist) "" |
|---|
| 84 | set shell(interp) [interp create] |
|---|
| 85 | frame ${root}.frame |
|---|
| 86 | set shell(text) [text ${root}.frame.shell -wrap word -background white \ |
|---|
| 87 | -yscrollcommand "${root}.frame.scroll set"] |
|---|
| 88 | scrollbar ${root}.frame.scroll -command "$shell(text) yview" |
|---|
| 89 | |
|---|
| 90 | bindtags $shell(text) "$shell(text) Shell Text ShellAfter . all" |
|---|
| 91 | bind $shell(text) <Return> "shell_return $pshell; break" |
|---|
| 92 | bind $shell(text) <Control-p> "shell_prevcmd $pshell; break" |
|---|
| 93 | bind $shell(text) <Control-n> "shell_nextcmd $pshell; break" |
|---|
| 94 | $shell(text) tag configure error -foreground red |
|---|
| 95 | $shell(text) tag configure prompt -foreground blue |
|---|
| 96 | $shell(text) tag configure puts -foreground purple |
|---|
| 97 | $shell(text) tag configure return -foreground grey |
|---|
| 98 | |
|---|
| 99 | slave_init $shell(interp) $pshell |
|---|
| 100 | |
|---|
| 101 | shell_prompt $pshell |
|---|
| 102 | $shell(text) mark gravity endprompt left |
|---|
| 103 | $shell(text) mark gravity startcmd left |
|---|
| 104 | |
|---|
| 105 | pack $shell(text) -fill x -fill y -side left |
|---|
| 106 | pack ${root}.frame.scroll -fill y -side right |
|---|
| 107 | pack ${root}.frame |
|---|
| 108 | focus $shell(text) |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | proc shell_new { } { |
|---|
| 112 | global shells |
|---|
| 113 | |
|---|
| 114 | incr shells |
|---|
| 115 | set w ".shell$shells" |
|---|
| 116 | toplevel $w |
|---|
| 117 | wm title $w "Purple Commander $shells" |
|---|
| 118 | shell_create "::shell$shells" $w |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | proc shell_prompt { pshell } { |
|---|
| 122 | upvar $pshell shell |
|---|
| 123 | |
|---|
| 124 | $shell(text) insert end $shell(prompt) prompt |
|---|
| 125 | $shell(text) mark set endprompt insert |
|---|
| 126 | $shell(text) mark set startcmd endprompt |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | proc shell_return { pshell } { |
|---|
| 130 | upvar $pshell shell |
|---|
| 131 | |
|---|
| 132 | $shell(text) mark set insert end |
|---|
| 133 | $shell(text) insert end "\n" |
|---|
| 134 | set shell(current) "$shell(current)[$shell(text) get endprompt end]" |
|---|
| 135 | if {[info complete $shell(current)]} { |
|---|
| 136 | exec_command $pshell |
|---|
| 137 | $shell(text) insert end $shell(prompt) prompt |
|---|
| 138 | $shell(text) mark set endprompt insert |
|---|
| 139 | $shell(text) mark set startcmd endprompt |
|---|
| 140 | set shell(current) "" |
|---|
| 141 | set shell(histindex) 1 |
|---|
| 142 | set shell(tmphist) "" |
|---|
| 143 | } else { |
|---|
| 144 | $shell(text) insert end $shell(continue) prompt |
|---|
| 145 | $shell(text) mark set endprompt insert |
|---|
| 146 | } |
|---|
| 147 | $shell(text) see end |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | proc shell_prevcmd { pshell } { |
|---|
| 151 | upvar $pshell shell |
|---|
| 152 | |
|---|
| 153 | if {$shell(histindex) == 1} { |
|---|
| 154 | set curcmd [concat $shell(current) [$shell(text) get endprompt end]] |
|---|
| 155 | set shell(tmphist) $curcmd |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | incr shell(histindex) -1 |
|---|
| 159 | set newcmd [$shell(interp) eval [list history event $shell(histindex)]] |
|---|
| 160 | if {[string length $newcmd]} { |
|---|
| 161 | set shell(current) "" |
|---|
| 162 | $shell(text) delete startcmd end |
|---|
| 163 | $shell(text) mark set prompt startcmd |
|---|
| 164 | $shell(text) insert end $newcmd |
|---|
| 165 | } |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | proc shell_nextcmd { pshell } { |
|---|
| 169 | upvar $pshell shell |
|---|
| 170 | |
|---|
| 171 | if {$shell(histindex) == 1} { return } |
|---|
| 172 | |
|---|
| 173 | incr shell(histindex) |
|---|
| 174 | if {$shell(histindex) == 1} { |
|---|
| 175 | set newcmd $shell(tmphist) |
|---|
| 176 | set shell(tmphist) "" |
|---|
| 177 | } else { |
|---|
| 178 | set newcmd [$shell(interp) eval [list history event $shell(histindex)]] |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | set shell(current) "" |
|---|
| 182 | $shell(text) delete startcmd end |
|---|
| 183 | $shell(text) mark set prompt startcmd |
|---|
| 184 | $shell(text) insert end $newcmd |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | |
|---|
| 188 | proc exec_command { pshell } { |
|---|
| 189 | upvar $pshell shell |
|---|
| 190 | |
|---|
| 191 | if {[string length $shell(current)]} { |
|---|
| 192 | $shell(interp) eval [list history add $shell(current)] |
|---|
| 193 | if {[catch { $shell(interp) eval $shell(current) } result]} { |
|---|
| 194 | $shell(text) insert end "$result\n" error |
|---|
| 195 | } elseif {[string length $result]} { |
|---|
| 196 | $shell(text) insert end "$result\n" return |
|---|
| 197 | } |
|---|
| 198 | } |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | proc acct_insert { pshell pacct } { |
|---|
| 202 | upvar $pshell shell |
|---|
| 203 | upvar $pacct acct |
|---|
| 204 | |
|---|
| 205 | $shell(text) insert insert [lindex $acct(accounts) [$acct(listbox) index active]] |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | proc account_dialog { toplevel pshell } { |
|---|
| 209 | global acct_dialog |
|---|
| 210 | |
|---|
| 211 | if {[expr {$acct_dialog(posted) != 0}]} { |
|---|
| 212 | destroy $acct_dialog(toplevel) |
|---|
| 213 | set acct_dialog(posted) 0 |
|---|
| 214 | set acct_dialog(checkbox) 0 |
|---|
| 215 | return |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | set acct_dialog(toplevel) $toplevel |
|---|
| 219 | set acct_dialog(accounts) [purple::account list] |
|---|
| 220 | set acct_dialog(list) {} |
|---|
| 221 | |
|---|
| 222 | set d [toplevel $toplevel] |
|---|
| 223 | wm title $d "Accounts" |
|---|
| 224 | bind $d <Destroy> { |
|---|
| 225 | global acct_dialog |
|---|
| 226 | set acct_dialog(posted) 0 |
|---|
| 227 | set acct_dialog(checkbox) 0 |
|---|
| 228 | set acct_dialog(list) {} |
|---|
| 229 | } |
|---|
| 230 | |
|---|
| 231 | frame ${d}.top |
|---|
| 232 | set l [listbox ${d}.top.listbox -foreground grey -background white \ |
|---|
| 233 | -yscrollcommand "${d}.top.listscroll set" -listvar ::acct_dialog(list)] |
|---|
| 234 | scrollbar ${d}.top.listscroll -command "$l yview" |
|---|
| 235 | |
|---|
| 236 | set i 0 |
|---|
| 237 | foreach account $acct_dialog(accounts) { |
|---|
| 238 | set acct_dialog(list) [linsert $acct_dialog(list) $i [purple::account username $account]] |
|---|
| 239 | if {[purple::account isconnected $account]} { |
|---|
| 240 | $l itemconfigure $i -foreground black |
|---|
| 241 | } |
|---|
| 242 | incr i |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | bind $l <Double-1> "acct_insert $pshell ::acct_dialog" |
|---|
| 246 | |
|---|
| 247 | pack $l -side left -expand yes -fill both |
|---|
| 248 | pack ${d}.top.listscroll -side right -fill y |
|---|
| 249 | pack ${d}.top |
|---|
| 250 | |
|---|
| 251 | set acct_dialog(posted) 1 |
|---|
| 252 | set acct_dialog(checkbox) 1 |
|---|
| 253 | set acct_dialog(listbox) $l |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | bind Shell <BackSpace> { |
|---|
| 257 | if [%W compare insert <= endprompt] { |
|---|
| 258 | break |
|---|
| 259 | } |
|---|
| 260 | } |
|---|
| 261 | bind Shell <Key> { |
|---|
| 262 | if [%W compare insert < endprompt] { |
|---|
| 263 | %W mark set insert end |
|---|
| 264 | } |
|---|
| 265 | } |
|---|
| 266 | bind Shell <Control-u> { %W delete endprompt end; break } |
|---|
| 267 | bind ShellAfter <Key> { |
|---|
| 268 | if [%W compare insert < endprompt] { |
|---|
| 269 | %W mark set insert endprompt |
|---|
| 270 | } |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | set acct_dialog(posted) 0 |
|---|
| 274 | set shells 1 |
|---|
| 275 | |
|---|
| 276 | menu .menu -type menubar -tearoff no -borderwidth 0 |
|---|
| 277 | menu .menu.commander -tearoff no |
|---|
| 278 | .menu.commander add command -label New -command { shell_new } |
|---|
| 279 | .menu.commander add command -label Reset -command { shell_reset ::shell } |
|---|
| 280 | .menu.commander add separator |
|---|
| 281 | .menu.commander add command -label Unload -command { purple::unload } |
|---|
| 282 | .menu add cascade -menu .menu.commander -label Commander |
|---|
| 283 | menu .menu.dialogs -tearoff no |
|---|
| 284 | .menu.dialogs add check -label Accounts -command { account_dialog .acctdialog ::shell } -variable acct_dialog(checkbox) |
|---|
| 285 | .menu add cascade -menu .menu.dialogs -label Dialogs |
|---|
| 286 | . configure -menu .menu |
|---|
| 287 | |
|---|
| 288 | shell_create ::shell {} |
|---|
| 289 | |
|---|
| 290 | if {[info exists purple::version]} { |
|---|
| 291 | purple::signal connect [purple::connection handle] signed-on { gc } { |
|---|
| 292 | global acct_dialog |
|---|
| 293 | |
|---|
| 294 | if {!$acct_dialog(posted)} { return } |
|---|
| 295 | |
|---|
| 296 | set account [lsearch -exact $acct_dialog(accounts) [purple::connection account $gc]] |
|---|
| 297 | $acct_dialog(listbox) itemconfigure $account -foreground black |
|---|
| 298 | } |
|---|
| 299 | purple::signal connect [purple::connection handle] signing-off { gc } { |
|---|
| 300 | global acct_dialog |
|---|
| 301 | |
|---|
| 302 | if {!$acct_dialog(posted)} { return } |
|---|
| 303 | |
|---|
| 304 | set account [lsearch -exact $acct_dialog(accounts) [purple::connection account $gc]] |
|---|
| 305 | $acct_dialog(listbox) itemconfigure $account -foreground grey |
|---|
| 306 | } |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | wm title . "Purple Commander" |
|---|
| 310 | wm deiconify . |
|---|
| 311 | |
|---|
| 312 | proc plugin_init { } { |
|---|
| 313 | list "Purple Commander" \ |
|---|
| 314 | "$purple::version" \ |
|---|
| 315 | "An interactive Tcl interpreter" \ |
|---|
| 316 | "Purple Commander provides an interactive command interpreter for the Purple Tcl programming interface. Among other things, it can be used to load and debug Purple Tcl scripts on the fly." \ |
|---|
| 317 | "Ethan Blanton <elb@pidgin.im>" \ |
|---|
| 318 | "http://www.pidgin.im/" |
|---|
| 319 | } |
|---|