home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
OL.LZH
/
PROCS.LZH
/
COMPLETE.ICN
< prev
next >
Wrap
Text File
|
1991-09-05
|
6KB
|
158 lines
############################################################################
#
# Name: complete.icn
#
# Title: complete partial input string
#
# Author: Richard L. Goerwitz
#
# Version: 1.6
#
# Date: June 1, 1991
#
############################################################################
#
# This file contains a single procedure, complete(s,st), which
# completes a string (s) relative to a set or list of strings (st).
# Put differently, complete() lets you supply a partial string, s,
# and get back those strings in st that s is either equal to or a
# substring of.
#
# Lots of command interfaces allow completion of partial input.
# Complete() simply represents my personal sentiments about how this
# might best be done in Icon. If you strip away the profuse comments
# below, you end up with only about thirty lines of actual source
# code.
#
# I have arranged things so that only that portion of an automaton
# which is needed to complete a given string is actually created and
# stored. Storing automata for later use naturally makes complete()
# eat up more memory. The performance gains can make it worth the
# trouble, though. If, for some reason, there comes a time when it
# is advisable to reclaim the space occupied by complete's static
# structures, you can just call it without arguments. This
# "resets" complete() and forces an immediate garbage collection.
#
# Example code:
#
# commands := ["run","stop","quit","save","load","continue"]
# while line := read(&input) do {
# cmds := list()
# every put(cmds, complete(line, commands))
# case *cmds of {
# 0 : input_error(line)
# 1 : do_command(cmds[1])
# default : display_possible_completions(cmds)
# }
# etc...
#
# More Iconish methods might include displaying successive
# alternatives each time the user presses the tab key (this would,
# however, require using the nonportable getch() routine). Another
# method might be to use the first string suspended by complete().
#
# Note: This entire shebang could be replaced with a slightly slower
# and much smaller program suggested to me by Jerry Nowlin and Bob
# Alexander.
#
# procedure terscompl(s, st)
# suspend match(s, p := !st) & p
# end
#
# This program will work fine for lists with just a few members, and
# also for cases where s is fairly large. It will also use much less
# memory.
#
############################################################################
procedure complete(s,st)
local dfstn, c, l, old_char, newtbl, str, strset
static t
initial t := table()
# No-arg invocation wipes out static structures & causes an
# immediate garbage collection.
if /s & /st then {
t := table()
collect() # do it NOW
fail
}
type(st) == ("list"|"set") |
stop("error (complete): list or set expected for arg2")
# Seriously, all that's being done here is that possible states
# are being represented by sets containing possible completions of
# s relative to st. Each time a character is snarfed from s, we
# check to see what strings in st might represent possible
# completions, and store these in yet another set. At some
# point, we either run into a character in s that makes comple-
# tion impossible (fail), or we run out of characters in s (in
# which case we succeed, & suspend each of the possible
# completions).
# Store any sets we have to create in a static structure for later
# re-use.
/t[st] := table()
# We'll call the table entry for the current set dfstn. (It really
# does enable us to do things deterministically.)
dfstn := t[st]
# Snarf one character at a time from s.
every c := !s do {
# The state we're in is represented by the set of all possible
# completions before c was read. If we haven't yet seen char
# c in this state, run through the current-possible-completion
# set, popping off the first character of each possible
# completion, and then construct a table which uses these
# initial chars as keys, and makes the completions that are
# possible for each of these characters into the values for
# those keys.
if /dfstn[st] then {
# To get strings that start with the same char together,
# sort the current string set (st).
l := sort(st)
newtbl := table()
old_chr := ""
# Now pop off each member of the sorted string set. Use
# first characters as keys, and then divvy up the full strings
# into sets of strings having the same initial letter.
every str := !l do {
str ? { chr := move(1) | next; str := tab(0) }
if old_chr ~==:= chr then {
strset := set([str])
insert(newtbl, chr, strset)
}
else insert(strset, str)
}
insert(dfstn, st, newtbl)
}
# What we've done essentially is to create a table in which
# the keys represent labeled arcs out of the current state,
# and the values represent possible completion sets for those
# paths. What we need to do now is store that table in dfstn
# as the value of the current state-set (i.e. the current
# range of possible completions). Once stored, we can then
# see if there is any arc from the current state (dfstn[st])
# with the label c (dfstn[st][c]). If so, its value becomes
# the new current state (st), and we cycle around again for
# yet another c.
st := \dfstn[st][c] | fail
if *st = 1 & match(s,!st)
then break
}
# Eventually we run out of characters in c. The current state
# (i.e. the set of possible completions) can simply be suspended
# one element at a time, with s prefixed to each element. If, for
# instance, st had contained ["hello","help","hear"] at the outset
# and s was equal to "hel", we would now be suspending "hel" ||
# !set(["lo","p"]).
suspend s || !st
end