123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- # history.tcl --
- #
- # Implementation of the history command.
- #
- # Copyright (c) 1997 Sun Microsystems, Inc.
- #
- # See the file "license.terms" for information on usage and redistribution of
- # this file, and for a DISCLAIMER OF ALL WARRANTIES.
- #
- # The tcl::history array holds the history list and some additional
- # bookkeeping variables.
- #
- # nextid the index used for the next history list item.
- # keep the max size of the history list
- # oldest the index of the oldest item in the history.
- namespace eval ::tcl {
- variable history
- if {![info exists history]} {
- array set history {
- nextid 0
- keep 20
- oldest -20
- }
- }
- namespace ensemble create -command ::tcl::history -map {
- add ::tcl::HistAdd
- change ::tcl::HistChange
- clear ::tcl::HistClear
- event ::tcl::HistEvent
- info ::tcl::HistInfo
- keep ::tcl::HistKeep
- nextid ::tcl::HistNextID
- redo ::tcl::HistRedo
- }
- }
- # history --
- #
- # This is the main history command. See the man page for its interface.
- # This does some argument checking and calls the helper ensemble in the
- # tcl namespace.
- proc ::history {args} {
- # If no command given, we're doing 'history info'. Can't be done with an
- # ensemble unknown handler, as those don't fire when no subcommand is
- # given at all.
- if {![llength $args]} {
- set args info
- }
- # Tricky stuff needed to make stack and errors come out right!
- tailcall apply {arglist {tailcall history {*}$arglist} ::tcl} $args
- }
- # (unnamed) --
- #
- # Callback when [::history] is destroyed. Destroys the implementation.
- #
- # Parameters:
- # oldName what the command was called.
- # newName what the command is now called (an empty string).
- # op the operation (= delete).
- #
- # Results:
- # none
- #
- # Side Effects:
- # The implementation of the [::history] command ceases to exist.
- trace add command ::history delete [list apply {{oldName newName op} {
- variable history
- unset -nocomplain history
- foreach c [info procs ::tcl::Hist*] {
- rename $c {}
- }
- rename ::tcl::history {}
- } ::tcl}]
- # tcl::HistAdd --
- #
- # Add an item to the history, and optionally eval it at the global scope
- #
- # Parameters:
- # event the command to add
- # exec (optional) a substring of "exec" causes the command to
- # be evaled.
- # Results:
- # If executing, then the results of the command are returned
- #
- # Side Effects:
- # Adds to the history list
- proc ::tcl::HistAdd {event {exec {}}} {
- variable history
- if {
- [prefix longest {exec {}} $exec] eq ""
- && [llength [info level 0]] == 3
- } then {
- return -code error "bad argument \"$exec\": should be \"exec\""
- }
- # Do not add empty commands to the history
- if {[string trim $event] eq ""} {
- return ""
- }
- # Maintain the history
- set history([incr history(nextid)]) $event
- unset -nocomplain history([incr history(oldest)])
- # Only execute if 'exec' (or non-empty prefix of it) given
- if {$exec eq ""} {
- return ""
- }
- tailcall eval $event
- }
- # tcl::HistKeep --
- #
- # Set or query the limit on the length of the history list
- #
- # Parameters:
- # limit (optional) the length of the history list
- #
- # Results:
- # If no limit is specified, the current limit is returned
- #
- # Side Effects:
- # Updates history(keep) if a limit is specified
- proc ::tcl::HistKeep {{count {}}} {
- variable history
- if {[llength [info level 0]] == 1} {
- return $history(keep)
- }
- if {![string is integer -strict $count] || ($count < 0)} {
- return -code error "illegal keep count \"$count\""
- }
- set oldold $history(oldest)
- set history(oldest) [expr {$history(nextid) - $count}]
- for {} {$oldold <= $history(oldest)} {incr oldold} {
- unset -nocomplain history($oldold)
- }
- set history(keep) $count
- }
- # tcl::HistClear --
- #
- # Erase the history list
- #
- # Parameters:
- # none
- #
- # Results:
- # none
- #
- # Side Effects:
- # Resets the history array, except for the keep limit
- proc ::tcl::HistClear {} {
- variable history
- set keep $history(keep)
- unset history
- array set history [list \
- nextid 0 \
- keep $keep \
- oldest -$keep \
- ]
- }
- # tcl::HistInfo --
- #
- # Return a pretty-printed version of the history list
- #
- # Parameters:
- # num (optional) the length of the history list to return
- #
- # Results:
- # A formatted history list
- proc ::tcl::HistInfo {{count {}}} {
- variable history
- if {[llength [info level 0]] == 1} {
- set count [expr {$history(keep) + 1}]
- } elseif {![string is integer -strict $count]} {
- return -code error "bad integer \"$count\""
- }
- set result {}
- set newline ""
- for {set i [expr {$history(nextid) - $count + 1}]} \
- {$i <= $history(nextid)} {incr i} {
- if {![info exists history($i)]} {
- continue
- }
- set cmd [string map [list \n \n\t] [string trimright $history($i) \ \n]]
- append result $newline[format "%6d %s" $i $cmd]
- set newline \n
- }
- return $result
- }
- # tcl::HistRedo --
- #
- # Fetch the previous or specified event, execute it, and then replace
- # the current history item with that event.
- #
- # Parameters:
- # event (optional) index of history item to redo. Defaults to -1,
- # which means the previous event.
- #
- # Results:
- # Those of the command being redone.
- #
- # Side Effects:
- # Replaces the current history list item with the one being redone.
- proc ::tcl::HistRedo {{event -1}} {
- variable history
- set i [HistIndex $event]
- if {$i == $history(nextid)} {
- return -code error "cannot redo the current event"
- }
- set cmd $history($i)
- HistChange $cmd 0
- tailcall eval $cmd
- }
- # tcl::HistIndex --
- #
- # Map from an event specifier to an index in the history list.
- #
- # Parameters:
- # event index of history item to redo.
- # If this is a positive number, it is used directly.
- # If it is a negative number, then it counts back to a previous
- # event, where -1 is the most recent event.
- # A string can be matched, either by being the prefix of a
- # command or by matching a command with string match.
- #
- # Results:
- # The index into history, or an error if the index didn't match.
- proc ::tcl::HistIndex {event} {
- variable history
- if {![string is integer -strict $event]} {
- for {set i [expr {$history(nextid)-1}]} {[info exists history($i)]} \
- {incr i -1} {
- if {[string match $event* $history($i)]} {
- return $i
- }
- if {[string match $event $history($i)]} {
- return $i
- }
- }
- return -code error "no event matches \"$event\""
- } elseif {$event <= 0} {
- set i [expr {$history(nextid) + $event}]
- } else {
- set i $event
- }
- if {$i <= $history(oldest)} {
- return -code error "event \"$event\" is too far in the past"
- }
- if {$i > $history(nextid)} {
- return -code error "event \"$event\" hasn't occured yet"
- }
- return $i
- }
- # tcl::HistEvent --
- #
- # Map from an event specifier to the value in the history list.
- #
- # Parameters:
- # event index of history item to redo. See index for a description of
- # possible event patterns.
- #
- # Results:
- # The value from the history list.
- proc ::tcl::HistEvent {{event -1}} {
- variable history
- set i [HistIndex $event]
- if {![info exists history($i)]} {
- return ""
- }
- return [string trimright $history($i) \ \n]
- }
- # tcl::HistChange --
- #
- # Replace a value in the history list.
- #
- # Parameters:
- # newValue The new value to put into the history list.
- # event (optional) index of history item to redo. See index for a
- # description of possible event patterns. This defaults to 0,
- # which specifies the current event.
- #
- # Side Effects:
- # Changes the history list.
- proc ::tcl::HistChange {newValue {event 0}} {
- variable history
- set i [HistIndex $event]
- set history($i) $newValue
- }
- # tcl::HistNextID --
- #
- # Returns the number of the next history event.
- #
- # Parameters:
- # None.
- #
- # Side Effects:
- # None.
- proc ::tcl::HistNextID {} {
- variable history
- return [expr {$history(nextid) + 1}]
- }
- return
- # Local Variables:
- # mode: tcl
- # fill-column: 78
- # End:
|