Class ::nsshell::CurrentThreadHandler (public)
::nx::Class ::nsshell::CurrentThreadHandler
Defined in /usr/local/ns/tcl/nsshell/shell.tcl
- Testcases:
- No testcase defined.
Source code: :property {supported:1..n {eval autocomplete heartbeat}} :method init {} { nsv_array set shell_kernels {} nsv_array set shell_conn {} } :public method "context require" {kernel channel} { # Update kernel timestamp as well as latest channel nsv_set shell_kernels $kernel [ns_time] nsv_set shell_conn $kernel,channel $channel if {![nsv_exists shell_conn $kernel,snapshot]} { nsv_set -default shell_conn $kernel,snapshot "" } #ns_log notice "==== REQUIRE nsv_set -default shell_conn $kernel exists?[namespace exists $kernel]" if {![namespace exists $kernel]} { # # Create temporary namespace named "$kernel" for executing # command in current thread. # namespace eval $kernel { # Santiphap: Create substitute "ns_conn", since original "ns_conn" in kernel will return "no connection" proc ns_conn {args} { set kernel [lindex [split [namespace current] ::] end] if {[nsv_exists shell_conn "$kernel,$args"]} { return [nsv_get shell_conn "$kernel,$args"] } else { return -code error "bad option \"$args\": must be acceptedcompression, auth, authpassword, authuser, contentfile, contentlength, contentsentlength, driver, files, flags, form, headers, host, id, isconnected, location, method, outputheaders, peeraddr, peerport, pool, port, protocol, query, partialtimes, request, server, sock, start, timeout, url, urlc, urlv, version, or zipaccepted" } } # Santiphap: Create snapshot object, see shell.tcl ::ws::snapshot::Snapshot create snapshot -namespace [namespace current] } # Restore snapshot #ns_log notice "SNAPSHOT $kernel restore <[nsv_get shell_conn $kernel,snapshot]>" namespace eval $kernel [nsv_get shell_conn $kernel,snapshot] } } :public method _eval {arg kernel channel} { # # Light weight "eval" method for querying the current # content of the workspace/snapshot. This method does # NOT update the snapshot, but is intended for # e.g. autocompletion and the like. # :context require $kernel $channel # # Qualify cmd and reject certain commands (should be # configurable). # set cmd "" regexp {^\s*(\S+)\s?} $arg - cmd set cmd [namespace which $cmd] if {$cmd in {::return ::exit}} { set status error set result "command rejected: '$arg'" } else { try { # # Execute command in temporary unique namespace # based on kernelId (nsshell::kernelId) # namespace eval $kernel $arg } on ok {result} { set status ok } on error {result} { set status error } } return [list status $status result $result] } :public method eval {arg kernel channel} { # # Full featured "eval" method that updates the associated # snapshot after the command after success. # ns_log notice "CurrentThreadHandler.eval called with <$arg> [namespace exists $kernel]" set result [:_eval $arg $kernel $channel] if {[dict get $result status] eq "ok"} { nsv_set shell_conn $kernel,snapshot [namespace eval $kernel {snapshot get_delta}] #ns_log notice "SNAPSHOT $kernel saved, is now: <[ns_get shell_conn $kernel,snapshot]>" } # # Delete context (temporary namespace) and return result # namespace delete $kernel ns_log notice "CurrentThreadHandler.eval <$arg> returns $result" return $result } :public method info_complete {arg kernel channel} { # # Check, whether the passed in command in "$arg" is a # complete Tcl command. # ns_log notice "=====info_complete===== arg <$arg>" return [list status ok result [info complete $arg]] } :method completion_elements {arg kernel channel} { # # completion_elements: call ":eval" and return elements if # command was successful # set result [:_eval $arg $kernel $channel] if {[dict get $result status] eq "ok"} { return [dict get $result result] } return "" } :public method autocomplete {arg kernel channel} { # # Try to autocomplete the value provided in "$arg". This # method returns a dict with the "status" and a "result" # consisting of potential completions. # ns_log notice "===== Autocomplete ===== arg <$arg>" set result {} set type "" set words [split $arg " "] set lastWord [lindex $words end] # Santiphap: Variable autocomplete if last word start with $ if { [string match {$*} $lastWord] } { ns_log notice "Autocomplete variable: $arg" set type variables # Santiphap: Get var prefix without $ set var_prefix [string range $lastWord 1 end] # Santiphap: Get matched variable set var_result [:completion_elements "info vars $var_prefix*" $kernel $channel] # Santiphap: Get matched namespace set namespace_parent [join [lreplace [split $var_prefix :] end-1 end] ::] set namespace_pattern [lindex [split $var_prefix :] end] set namespace_result [:completion_elements "namespace children ${namespace_parent}:: $namespace_pattern*" $kernel $channel] # # Prepend dollar "$" to variable names for the result # set var_result [lmap v $var_result {set _ "\$$v"}] set namespace_result [lmap v $namespace_result {set _ "\$${v}::"}] set result [join [lsort -unique [concat $var_result $namespace_result]]] } else { # Santiphap: Get last word of the last command set sub_arg [string trimleft [lindex [split $arg "\["] end]] #ns_log notice "===== arg <$arg> sub_arg <$sub_arg>" # Santiphap: Command autocomplete set words [split $sub_arg " "] if { [llength $words] == 1} { # # A single word was provided, try to autocomplete # it as a command. # set type commands ns_log notice "===== Autocomplete single word command: <$sub_arg>" set providedNs [namespace qualifiers $sub_arg] set checkNs [expr {$providedNs eq "" ? "::" : $providedNs}] lappend cmds {*}[:completion_elements [list info commands $sub_arg*] $kernel $channel] {*}[:completion_elements [list namespace children $checkNs $sub_arg*] $kernel $channel] set result [lsort -unique $cmds] } elseif { [llength $words] eq 2} { # # Two words # lassign $words main sub if {$main in {set unset}} { set result [:completion_elements "info vars $sub*" $kernel $channel] set type variables # # We could add here as well namespace # completion for namespaced vars. # } else { set type subcommands ns_log notice "Autocomplete subcommand: <$sub_arg>" try { # # Get matched class/object methods. We use # here the nsf primitive "lookupmethods", # since this works for NX and XOTcl. # :completion_elements [list $main ::nsf::methods::object::info::lookupmethods $sub*] $kernel $channel } on error {errorMsg} { ns_log notice "lookupmethods failed: $errorMsg" set methods {} } on ok {result} { set methods $result } # # In case, we found no XOTcl/NX methods, # check, if there are Tcl/NaviServer commands # with subcommands. In order to avoid # collateral damage, we do this just for # asserted commands. # if {[llength $methods] == 0} { ns_log notice "NO methods for <$sub*>" if { $main in { array binary chan clock encoding file info namespace package string trace ns_asynclogfile ns_chan ns_conn ns_connchan ns_crypto::eckey ns_driver ns_hmac ns_http ns_ictl ns_info ns_job ns_logctl ns_md ns_server ns_set ns_thread ns_urlspace ns_writer nsv_array }} { try { $main "" } on error {errMsg} { if {[regexp {: must be (.*)$} $errMsg . subcmds]} { regsub -all ", or " $subcmds "" subcmds set methods [lmap c [split $subcmds ,] { set m [string trim $c] if {![string match $sub* $m]} continue set m }] } } } } # Sort & unique #ns_log notice "RESULT for <$sub*> -> [concat $methods]" set result [lsort -unique [concat $methods]] } } } if {[namespace exists $kernel]} { # # Clean up after the _eval commands # namespace delete $kernel } # Santiphap: Return autocomplete option type and list return [list status autocomplete result [concat $type $result]] } # Santiphap: Receiving heartbeat from client :public method heartbeat {kernel channel} { # Santiphap: Update kernel timestamp debug "heartbeat: $kernel" nsv_set shell_kernels $kernel [ns_time] return [list status noreply result ""] }XQL Not present: Generic, PostgreSQL, Oracle