Class ::nsshell::CurrentThreadHandler (public)

 ::nx::Class ::nsshell::CurrentThreadHandler[i]

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
[ hide source ] | [ make this the default ]
Show another procedure: