Version 1 of Integrating Tcl and Emacs on Windows

Updated 2002-02-16 20:56:25

Emacs has the wonderfull "inferior tcl" process which allows us to start Tcl in an Emacs window. Unfortunately, this doesn't work automatically on Windows, Emacs is unable to start an "interactive" Tcl interpreter. The problem is that Tcl calls istty() to determine whether tcl_interactive [L1 ] should be set and prompts should be displayed. But on Windows Emacs can not make istty() return the right value so this doesn't happen and tclsh thinks it's running non-interactive.

One solution is to change the tclsh code, but not everyone can do that. Another solution is to simulate the command loop in pure Tcl. This works without any changes to Tcl or Emacs, so here is some code:

 namespace eval CmdInput {

        # subclass "info", because the "unknown" proc checks
        # that "info script" returns "", before it starts its
        # work
        variable this_script [info script]
        proc info {args} {
                set result [uplevel [concat __org_info $args]]
                set cmd [lindex $args 0]

                variable this_script
                if {"script" == $cmd && "$result" == $this_script} {
                        return ""
                } else {
                        return $result
                }
        }
        rename ::info ::__org_info ;# using a namespace proc here cores
        proc ::info {args} "uplevel \[concat [namespace which info] \$args\]"

        proc loop {} {
                # preparations
                fconfigure stdin  -buffering line
                fconfigure stdout -buffering line
                fconfigure stderr -buffering line
                set ::tcl_interactive 1

                if {[file exists ~/tclshrc.tcl]} {
                        namespace eval :: {uplevel \#0 source ~/tclshrc.tcl}
                }

                # input loop
                while {1} {
                        catch {uplevel \#0 $::tcl_prompt1}
                        flush stdout
                        set cmd {}
                        while {1} {
                                append cmd [gets stdin] "\n"
                                if {[info complete $cmd]} {
                                        break
                                }
                                catch {uplevel \#0 $::tcl_prompt2}
                                flush stdout
                        }
                        catch {uplevel \#0 $cmd} result
                        puts $result
                }
                return ""
        }
 }

 catch {CmdInput::loop} result 
 puts $result
 exit 0

To use this code: Save it to a file called cmd-input.tcl. In Emacs setq or customize the variable tcl-application to read "tclsh83.exe" and the variable tcl-command-switches to '("c:/your-path-here/cmd-input.tcl") .