blob: 826269210646db4288ea4a64120f8d79f6801719 [file] [log] [blame]
# util-expand.tcl --
#
# This file implements package ::Utility::expand, which ...
#
# Copyright (c) 1997-8 Jeffrey Hobbs
#
# See the file "license.terms" for information on usage and
# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
package require ::Utility
package provide ::Utility::expand 1.0
namespace eval ::Utility::expand {;
namespace export -clear expand*
namespace import -force ::Utility::*
##
## NOTE: In places where uplevel is used, it is highly likely that
## a further eval redirect is otherwise necessary for foreign interps
##
# expand --
#
# The string to match is expanded to the longest possible match.
# If data(-showmultiple) is non-zero and the user longest match
# equaled the string to expand, then all possible matches are
# output to stdout. Triggers bell if no matches are found.
#
# Arguments:
# type type of expansion (path / proc / variable)
#
# Returns:
# number of matches found
#
proc expand {args} {
array set opts {
-type any -widget {}
}
set args [get_opts opts $args {-type 1 -widget 1} {-widget widget}]
if {[string match {} $opts(-widget)] && [llength $args]!=1} {
return -code error "wrong # args: should be\
\"[lindex [info level 0] 0] ?-type type?\
?-widget widget || str?"
}
set prefix [namespace current]::expand_
if {[string match {} [set arg [info commands $prefix$opts(-type)]]]} {
set arg [info commands $prefix$opts(-type)*]
}
set result {}
set code ok
if 0 {
set exp "\[^\\]\[ \t\n\r\[\{\"\$]"
set tmp [$w search -backwards -regexp $exp insert-1c limit-1c]
if {[string compare {} $tmp]} {append tmp +2c} else {set tmp limit}
if {[$w compare $tmp >= insert]} return
set str [$w get $tmp insert]
}
switch [llength $arg] {
1 { set code [catch {uplevel $arg $args} result] }
0 {
set arg [info commands $prefix*]
regsub -all $prefix $arg {} arg
return -code error "unknown [lindex [info level 0] 0] type\
\"$opts(-type)\", must be one of: [join [lsort $arg] {, }]"
}
default {
regsub -all $prefix $arg {} arg
return -code error "ambiguous type \"$opts(-type)\",\
could be one of: [join [lsort $arg] {, }]"
}
}
if 0 {
set len [llength $res]
if {$len} {
$w delete $tmp insert
$w insert $tmp [lindex $res 0]
if {$len > 1} {
upvar \#0 [namespace current]::[winfo parent $w] data
if {$data(-showmultiple) && \
![string compare [lindex $res 0] $str]} {
puts stdout [lsort [lreplace $res 0 0]]
}
}
} else { bell }
return [incr len -1]
}
return -code $code [string trimright $result \n]
}
# expand_pathname --
#
# expand a file pathname based on $str
# This is based on UNIX file name conventions
#
# Arguments:
# str partial file pathname to expand
# Results:
# Returns list containing longest unique match followed by all the
# possible further matches
#
proc expand_pathname {str} {
#reval pwd, cd, glob and final cd
set pwd [pwd]
if {[catch {cd [file dirname $str]} err]} {
return -code error $err
}
if {[catch {glob [file tail $str]*} m]} {
set match {}
} else {
if {[llength $m] > 1} {
global tcl_platform
if {[string match windows $tcl_platform(platform)]} {
## Windows is screwy because it can be case insensitive
set tmp [best_match [string tolower [lsort $m]] \
[string tolower [file tail $str]]]
} else {
set tmp [best_match [lsort $m] [file tail $str]]
}
if {[string match ?*/* $str]} {
set tmp [file dirname $str]/$tmp
} elseif {[string match /* $str]} {
set tmp /$tmp
}
regsub -all { } $tmp {\\ } tmp
set match [linsert $m 0 $tmp]
} else {
## This may look goofy, but it handles spaces in path names
eval append match $m
if {[file isdir $match]} {append match /}
if {[string match ?*/* $str]} {
set match [file dirname $str]/$match
} elseif {[string match /* $str]} {
set match /$match
}
regsub -all { } $match {\\ } match
## Why is this one needed and the ones below aren't!!
set match [list $match]
}
}
cd $pwd
return $match
}
# expand_proc --
#
## ExpandProcname - expand a tcl proc name based on $str
# ARGS: str - partial proc name to expand
# Calls: best_match
# Returns: list containing longest unique match followed by all the
# possible further matches
#
# Arguments:
# args comments
# Results:
# Returns ...
#
proc expand_proc {str} {
#reval info
set match [uplevel info commands [list $str]*]
if {[llength $match] > 1} {
regsub -all { } [best_match $match $str] {\\ } str
set match [linsert $match 0 $str]
} else {
regsub -all { } $match {\\ } match
}
return $match
}
# expand_variable --
#
## ExpandVariable - expand a tcl variable name based on $str
# ARGS: str - partial tcl var name to expand
# Calls: best_match
# Returns: list containing longest unique match followed by all the
# possible further matches
#
# Arguments:
# args comments
# Results:
# Returns ...
#
proc expand_variable {str} {
#reval "array names", "info vars"
if {[regexp {([^\(]*)\((.*)} $str junk ary str]} {
## Looks like they're trying to expand an array.
set match [array names $ary $str*]
if {[llength $match] > 1} {
set vars $ary\([best_match $match $str]
foreach var $match {lappend vars $ary\($var\)}
return $vars
} else {set match $ary\($match\)}
## Space transformation avoided for array names.
} else {
set match [info vars $str*]
if {[llength $match] > 1} {
regsub -all { } [best_match $match $str] {\\ } str
set match [linsert $match 0 $str]
} else {
regsub -all { } $match {\\ } match
}
}
return $match
}
}; # end of namespace ::Utility::expand