[APN] 2015-04-13: Doing more [TclOO] stuff, I wanted to be able to expand method names interactively in the same manner that proc names are expanded. Turned out the tkcon already had that for nx, xotcl, nsf so I patched in support for TclOO. The patch also fixes some limitations in the original code. In particular, it also expands method names when the cursor is not at the end of the line, or within a multi command line like `first command ; obj methodcall` or when the object is accessed via a variable like `$obj methodcall`. The patch below is against tkcon.tcl CVS file version 1.122 (that is the *CVS* file version, not the tkcon version). Tested with Tcl 8.5 and 8.6. Will fail on 8.4 (no apply command) but I cannot be bothered with old Tcl versions. ====== *** tkcon.tcl.orig Sat Mar 21 07:44:37 2015 --- tkcon.tcl Mon Apr 13 09:11:42 2015 *************** proc ::tkcon::Init {args} { *** 119,125 **** if {![info exists COLOR($key)]} { set COLOR($key) $default } } - # expandorder could also include 'Methodname' for XOTcl/NSF methods foreach {key default} { autoload {} blinktime 500 --- 119,124 ---- *************** proc ::tkcon::Init {args} { *** 131,137 **** debugPrompt {(level \#$level) debug [history nextid] > } dead {} edit edit ! expandorder {Pathname Variable Procname} font {} history 48 hoterrors 1 --- 130,136 ---- debugPrompt {(level \#$level) debug [history nextid] > } dead {} edit edit ! expandorder {Methodname Pathname Variable Procname} font {} history 48 hoterrors 1 *************** proc ::tkcon::Init {args} { *** 323,332 **** -main - -e - -eval { append OPT(maineval) \n$val\n } -package - -load { lappend OPT(autoload) $val - if {$val eq "nsf" || $val eq "nx" || $val eq "XOTcl" } { - # If xotcl is loaded, prepend expand order for it - set OPT(expandorder) [concat Methodname $OPT(expandorder)] - } } -slave { append OPT(slaveeval) \n$val\n } -nontcl { set OPT(nontcl) [regexp -nocase $truth $val]} --- 322,327 ---- *************** proc ::tkcon::ExpandProcname str { *** 5836,5851 **** # possible further matches ## proc ::tkcon::ExpandMethodname str { - # In a first step, obtain the typed-in cmd from the console - set typedCmd [::tkcon::CmdGet $::tkcon::PRIV(console)] set obj [lindex $typedCmd 0] if {$obj eq $typedCmd} { # just a single word, can't be a method expansion return -code continue } # Get the full string after the object ! set sub [string trimleft [string range $typedCmd [string length [list $obj]] end]] if {[EvalAttached [list info exists ::nsf::version]]} { # Next Scripting Framework is loaded if {![EvalAttached [list ::nsf::object::exists $obj]]} {return -code continue} --- 5831,5861 ---- # possible further matches ## proc ::tkcon::ExpandMethodname str { + # Locate the start of the current command looking back from the insert + # cursor to the end of the prompt (mark "limit"). Note the start of the + # command may be following a ";", "[", not necessarily the beginning. + set start [$::tkcon::PRIV(console) search -backwards -regexp {^|[;\[]\s*} insert-1c limit-1c] + if {[string compare {} $start]} { + append start +1c + } else { + set start limit + } + set typedCmd [string trimleft [$::tkcon::PRIV(console) get $start insert]] set obj [lindex $typedCmd 0] if {$obj eq $typedCmd} { # just a single word, can't be a method expansion return -code continue } # Get the full string after the object ! set sub [string trimleft [string range $typedCmd [string length $obj] end]] ! ! # Deal with cases where the object is actually stored in a variable ! # extract the real object name (ie. $x methodcall). ! if {[string index $obj 0] eq "\$"} { ! set obj [EvalAttached [list set [string range $obj 1 end]]] ! } ! if {[EvalAttached [list info exists ::nsf::version]]} { # Next Scripting Framework is loaded if {![EvalAttached [list ::nsf::object::exists $obj]]} {return -code continue} *************** proc ::tkcon::ExpandMethodname str { *** 5860,5870 **** # XOTcl < 2.* is loaded if {![EvalAttached [list ::xotcl::Object isobject $obj]]} {return -code continue} set cmd [list $obj info methods $sub*] } else { # No NSF/XOTcl loaded return -code continue } - set match [EvalAttached $cmd] if {[llength $match] > 1} { regsub -all {([^\\]) } [ExpandBestMatch $match $str] {\1\\ } bestMatch --- 5870,5893 ---- # XOTcl < 2.* is loaded if {![EvalAttached [list ::xotcl::Object isobject $obj]]} {return -code continue} set cmd [list $obj info methods $sub*] + } elseif {[llength [EvalAttached [list ::info commands oo::define]]]} { + if {![EvalAttached "::info object isa object $obj"]} { + return -code continue + } + set cmd [list apply { + {obj sub} { + set matches {} + foreach meth [::info object methods $obj -all] { + if {[string match $sub* $meth]} { + lappend matches $meth + } + } + return $matches + }} $obj $sub] } else { # No NSF/XOTcl loaded return -code continue } set match [EvalAttached $cmd] if {[llength $match] > 1} { regsub -all {([^\\]) } [ExpandBestMatch $match $str] {\1\\ } bestMatch ====== <>Application