%3 ::nsshell::CurrentThreadHandler ::nsshell::CurrentThreadHandler _eval autocomplete completion_elements context require eval heartbeat info_complete init ::nsshell::Handler ::nsshell::Handler ::nsshell::CurrentThreadHandler->::nsshell::Handler ::nsshell::KernelThreadHandler ::nsshell::KernelThreadHandler dropKernel eval init useKernel ::nsshell::KernelThreadHandler->::nsshell::Handler ::nx::Object ::nx::Object ::nsshell::Handler->::nx::Object

Class ::nsshell::CurrentThreadHandler

::nsshell::CurrentThreadHandler[i] create ... \
           [ -supported:1..n (default "eval autocomplete heartbeat") ]

Defined in /usr/local/ns/tcl/nsshell/shell.tcl

Class Relations

  • class: ::nx::Class[i]
  • superclass: ::nsshell::Handler[i]
::nx::Class create ::nsshell::CurrentThreadHandler \
     -superclass ::nsshell::Handler

Methods (to be applied on instances)

  • _eval (scripted, public)

     <instance of nsshell::CurrentThreadHandler[i]> _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.

    Parameters:
    arg (required)
    kernel (required)
    channel (required)

    Testcases:
    No testcase defined.
    :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]
  • autocomplete (scripted, public)

     <instance of nsshell::CurrentThreadHandler[i]> 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.

    Parameters:
    arg (required)
    kernel (required)
    channel (required)

    Testcases:
    No testcase defined.
    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]]
  • context require (scripted, public)

     <instance of nsshell::CurrentThreadHandler[i]> context require \
        kernel channel

    Update kernel timestamp as well as latest channel

    Parameters:
    kernel (required)
    channel (required)

    Testcases:
    No testcase defined.
    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]
    }
  • eval (scripted, public)

     <instance of nsshell::CurrentThreadHandler[i]> eval arg kernel \
        channel

    Full featured "eval" method that updates the associated snapshot after the command after success.

    Parameters:
    arg (required)
    kernel (required)
    channel (required)

    Testcases:
    No testcase defined.
    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
  • heartbeat (scripted, public)

     <instance of nsshell::CurrentThreadHandler[i]> heartbeat kernel \
        channel

    Santiphap: Update kernel timestamp

    Parameters:
    kernel (required)
    channel (required)

    Testcases:
    No testcase defined.
    debug "heartbeat: $kernel"
    nsv_set shell_kernels $kernel [ns_time]
    return [list status noreply result ""]
  • info_complete (scripted, public)

     <instance of nsshell::CurrentThreadHandler[i]> info_complete arg \
        kernel channel

    Check, whether the passed in command in "$arg" is a complete Tcl command.

    Parameters:
    arg (required)
    kernel (required)
    channel (required)

    Testcases:
    No testcase defined.
    ns_log notice "=====info_complete===== arg <$arg>"
    return [list status ok result [info complete $arg]]