prompt

Here is a script that provides a prompt for non-interactive tcl/tk sessions. It uses a fileevent on stdin so as not to block the event loop.

  # ==================================================================== #
  #
  # prompt.tcl --
  # An interactive prompt for non-interactive tcl/tk sessions
  # Copyright (C) 2000-2010, b i n a r i s m . c o m
  #
  # See the file "LICENSE.txt" or "LICENSE.html" for information on usage
  # and distribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  #
  # $Id$
  # $Name$
  #
  # ==================================================================== #

    namespace eval prompt {}

  # ==================================================================== #

  proc prompt::_init {} {

    variable buffer ""
    variable continue 0
    variable prompt1 "% "
    variable prompt2 ""

    return

  }

  # ==================================================================== #

  proc prompt::_getline {line} {

    variable buffer
    variable continue

    set n1 [string length $line]
    set line2 [string trimright $line \\]
    set n2 [string length $line2]
    set cont [expr {($n1 - $n2) % 2 == 1}]
    if { $cont } {
      set line [string range $line 0 end-1]
    }
    if { $continue } {
      append buffer " [string trimleft $line]"
    } elseif { [string length $buffer] } {
      append buffer \n$line
    } else {
      set buffer $line
    }
    set continue $cont
    if { $continue } {
      set complete 0
    } else {
      set complete [info complete $buffer]
    }
    if { !$continue && [info complete $buffer] } {
      set code [catch {uplevel #0 $buffer} result]
      set std [expr {$code > 0 ? "stderr" : "stdout"}]
      if { [string length $result] } {
        puts $std "$result"
      }
      set buffer ""
      _prompt 1
    } else {
      _prompt 2
    }

    return

  }

  # ==================================================================== #

  proc prompt::_readable {chan} {

    variable status

    set code [catch {gets $chan line} chars]

    if { $code > 0 } {
      puts stderr "error reading $chan: $chars"
      set status "error"
    } elseif { $chars > -1 } {
      _getline $line
    } elseif { [eof $chan] } {
      set status "eof"
    } elseif { [fblocked $chan] } {
      return
    } else {
      set status "unknown"
    }

    return

  }

  # ==================================================================== #

  proc prompt::_prompt {n} {

    global tcl_prompt$n
    variable prompt$n

    if { [info exists tcl_prompt$n] } {
      if { [catch {uplevel #0 [set tcl_prompt$n]} result] } {
        puts stderr $result
        flush stderr
      }
    } else {
      puts -nonewline stdout [set prompt$n]
    }
    flush stdout

    return

  }

  # ==================================================================== #

  proc prompt::prompt {} {

    _prompt 1

    fileevent stdin readable [list [namespace current]::_readable stdin]

    vwait [namespace current]::status

    return

  }

  # ==================================================================== #

    prompt::_init

    if { [info exists argv0] && [string equal $argv0 [info script]] } {
  #   set tcl_prompt2 {puts -nonewline "> "}
      set prompt::prompt2 "> "
      prompt::prompt
    }

  # ==================================================================== #

Example usage:

1. Create a file called hello.tcl containing:

  button .b -text "Hello World" -command [list puts "Hello World"]
  pack .b
  source prompt.tcl
  prompt::prompt

1. Run wish with the file:

  > wish hello.tcl

and you should be greeted with a prompt.


See also:


* MHo: This only works on unix, actually.