home *** CD-ROM | disk | FTP | other *** search
- # Complete Modules by Ian Frechette
- # Last updated 2-2-94
- # example modules
- # Don't let the size scare you. This is a whole collection of
- # examples and comments about the design of modules
- # meat of all this are the interface functions to 'complete'
- # compl.add, and compl.list (soon to be compl.del)
- # the function that does the work is compl.parse which is very small
- # and whatever parsing routine it calls.
-
- # These should actually all be in their individual modules
- # but this is just an example file..
-
- # Note.. compl.list is internal to complete.. shoulnd't normally be used
- if (compl.list == [])
- {
- # Note here.. Currently, if you compl.add /blah blahparse
- # followed by compl.add /blah otherparse only the latter will
- # called. No conflict message is shown unless you replace the
- # default 'null' and 'nomatch' parsers.
- compl.add -null -nomatch /m messparse
- compl.add /msg messparse
- compl.add /connect connparse
- compl.add /tr connparse
- compl.add /load loadparse
- compl.add /test testparse
- compl.add /con expand.con
- compl.add /conbunch expand.con
- }
-
-
- # message parser module.. Compatible with included tabscript
- # currently calls the tabkey script under 3 conditions
- # the input line has more than 2 argments on it.. '/msg bob thud<TAB>'
- # the input line has nothing on it '<TAB>'
- # the input line has only one argument and the character before the
- # cursor is a space '/msg bob <TAB>'
- # plus it now does nickname completion
- # /m D<TAB> expands to /m Daemon and so on
- alias messparse {
- if (([$1] != []) && ([$2] == []))
- {
- if (right(1 $*) != [ ])
- {
- # this is the simple match.. just match first occurance
- # and expand
- if (mp.cnt = match($(1)* $tk.msglist))
- {
- parsekey delete_previous_word
- # in case one does /m =ni<TAB> it must delete the =
- if (index(#=% $1) >= 0) {parsekey backspace}
- type $word(${mp.cnt - 1} $tk.msglist)
- type ${[ ]}
- }
- }
- {
- ^tk.getmsg 1 $tk.msglist
- }
- }
- {
- ^tk.getmsg 1 $tk.msglist
- }
- }
-
-
- # connect module for opers.. easily changeable to kicks, bans.. etc..
- # simply use /connect <TAB> for list or /connect <uniqid tag><TAB>
- # eg. /connect pen<TAB> expands to /connect penfold.ece.uiuc.edu
- # It always expands first matching string. Look at testparse for
- # a more intelligent way to do it.
-
- @ connlist = [irc.uiuc.edu goren1.u.washington.edu ircserver.iastate.edu w6yx.stanford.edu hamblin.math.byu.edu freedom.nmsu.edu dreamtime.unm.edu ircserver.santafe.edu irc.netsys.com irc-2.mit.edu cs-mail.bu.edu]
-
- alias connparse {
- if ([$1] != [])
- {
- @ cp.line = [$*]
- if ((right(1 $*) == [ ]) && ([$2] == [])&& ([$0] == [/connect]))
- {
- type 6667;type ${[ ]}
- # note.. if converted to use smartparse.. the port number must
- # be removed here.. the above logic conflicts with SP
- }
- {
- # expand only the first match found (See 'testparse' for better way
- if (cp.cnt = match($(${#cp.line -1})* $connlist))
- {
- delword
- type $word(${cp.cnt - 1} $connlist)
- type ${[ ]}
- }
- {
- echo *** connlist $connlist
- }
- }
- }
- {
- echo *** connlist $connlist
- }
- }
-
- # Load module
- # /load net<TAB> expand to /load netsplit and so on.
- # Note the problem right now is that it only finds and expands the first
- # name in the list I think we can get around this.
- @ loadlist = [netsplit ircgrep cut-paste compl.mods]
- alias loadparse {
- if ([$1] != []) {
- if (lp.cnt = match($(1)* $loadlist))
- {
- parsekey delete_previous_word
- type $word(${lp.cnt - 1} $loadlist)
- }
- }
- {
- echo *** loadlist = $loadlist
- }
- ^assign -lp.cnt
- }
-
- # ############ stuff related to SMARTPARSE ###################
- # The new testparse rewritten to use the
- # extremely awsome smartparse routine.
-
- if (!match(/test $compl.list)) {compl.add /test testparse}
-
- # just a quick alias for making LINKS lists.. /makelist testlist *.edu
- # will make a list of all *.edu servers.. Note that just * is
- # generally too big a list for ircII
- alias makelist {
- if ([$1])
- {
- ^on ^364 * push $0 $$1
- links $1-
- wait -cmd eval ^on 364 -\;echo *** makelist finished
- }
- }
-
- @ testlist = [aone atwo athree bone btwo bthree ircserver.iastate.edu ircserver.santafe.edu]
-
- # testparse <cmd> <stuff....pat>
- # this is called by the complete routines.
- @ tp.tmp = [0 :]
- # [0 :] represents a count of 0.. and a null pattern :<pat>
- alias testparse {
- # ignore this first line..
- @ tp.cnt = [$*]
- @ tp.cnt = #tp.cnt
- ^assign -tp.pat
- # all the cnt stuff is in case you do /command word1 word2 pattern<tab>
- if (tp.cnt > 1)
- {
- @ tp.pat = [$(${tp.cnt - 1})]
- # '/command pattern ' leaves <pat> null
- # '/command pattern' sets <pat> to a new pattern
- # important because smartparse may leave a space
- if (right(1 $L) != [ ]) {@ tp.tmp = [0 :$tp.pat]}
-
- # Uncomment the following line to see how it works from here.. debugging
- # echo smartparse\($tp.tmp testlist $tp.pat\)
-
- # call testparse with current cnt :<pat> <listname> <newpat>
- @ tp.tmp = smartparse($tp.tmp testlist $tp.pat)
- # note tp.tmp accounts for two arguments.. and is modified and saved
-
- if (left(1 $word(1 $tp.tmp)) == [,])
- {echo *** no match for pattern [$tp.pat] found in list}
- {if (left(1 $word(1 $tp.tmp)) == [.])
- {echo *** testlist: $testlist}}
- }
- {
- echo *** testlist : $testlist
- }
- }
-
- alias test echo *** TEST: You've matched: $*
-
- # test module
- # Trying to make some sort of intelligent handling of the tab lists.
- @ sp.cnt = 0
-
- # call it with smartparse <cnt> :<pat> <listname> <newpat>
- # $0 $1 $2 $3
- # returns <counter> [:,.]<pattern>
- # : == successful match , == no match . == null
- #
- # Look at how testparse uses it.. you shouldn't have to touch any
- # smartparse vars.. It's all handled through the interface.. basically
- # you're telling it where to start looking in the list and how
- # long the list is.. Each time smartparse is called it returns a counter
- # value indicating where it left off last time. You can save it
- # or not.. testparse saves it.. and passes it back as the new
- # starting position <cnt>
- #
- # Assuming the counter, pattern, and list are maintained through each call
- # it'll assume you're searching forward in the list from some place
- # after the last word matched in the list..
- #
- # If you feed it a <newpat> for which <pat> is not a subset, it'll reassign
- # <pat> to <newpat> and restart the process..
- # It defaults to expansion.. so.. <pat> = blah
- # will match blahone, blahtwo etc. Works with wildcards.. *a* matches a lot
- # Try it.
-
- ^assign -sp.tmp
- alias smartparse {
- # int sp.tmp - index of last match found
- # int sp.cnt - position in list
- # int sp.max - max number of elements in list
- # string sp.pat - match pattern
- if ([$3] != [])
- {
- # Extract <pat> from :<pat> Note.. It may be null
- @ sp.pat = mid(1 50 $1)
- @ sp.max = [$(#$2)]
- @ sp.cnt = [$0]
- # set pattern. Determine if we've changed the base pattern or not
- if (sp.pat == [])
- {@ sp.pat = [$3]}
- { if (!match($(sp.pat)* $3)) {@sp.pat = [$3]} }
- @ sp.run = 1
-
- while (((sp.list = words($sp.cnt $sp.max $($2))) != []) && (!sp.tmp) && sp.run)
- {
- # look for match in list
- if (sp.tmp = match($(sp.pat)* $sp.list))
- {
- # sp.cnt is absolute position in list. Jump over found item.
- # to set up for the next call to smartparse
- @ sp.cnt = sp.cnt + sp.tmp
-
- # parsekey delete_previous_word
- delword
- type $word(${sp.tmp - 1} $sp.list)
- type ${[ ]}
- }
- {
- # nothing found.. drop out of loop
- # for this condidtion to occur we must be at the beginning
- # of the loop... either first pass.. or just looped back
- if (!sp.cnt && !sp.tmp)
- {
- # notfound condition set for return value later
- @ sp.notfound = [$sp.cnt ,$sp.pat]
- @ sp.run = 0
- # echo *** smartparse: no matching pattern
- }
- # loop back
- @ sp.cnt = 0
- }
- }
- ^assign -sp.tmp
- if (!sp.list) {@sp.cnt = 0}
- ^assign -sp.list
- if (sp.notfound == [])
- {@ function_return = [$sp.cnt :$sp.pat]}
- {@ function_return = sp.notfound;^assign -sp.notfound}
- }
- {
- # echo *** sp NULL
- # echo *** $2: $($2)
- @ function_return = [$sp.cnt .$sp.pat]
- }
- ^assign -sp.run
- }
-
- # alias words.. usage $word(<begin> <end> <words>)
- # words(0 2 zero one two three ... ) == 'zero one two' and so on
- alias words {
- @ function_return = [$(${[$0]+2}-${[$1] +2})]
- }
-
- # This is like DELETE_PREVIOUS_WORD except that it delets to the
- # previous space which is much more useful than the current
- # behavior of deleting to the previos non- [a-zA-Z0-9] char. :-?
- alias delword {
- parsekey erase_to_end_of_line
- if ((dw.char = right(1 $L)) != [ ]) {@ dw.nw = 0} {@dw.nw = 1}
- while (((dw.char != [ ]) || dw.nw) && (dw.char != []))
- {
- parsekey backspace
- if ((dw.char = right(1 $L)) != [ ]) {@ dw.nw = 0}
- }
- ^assign -dw.char;^assign -dw.nw
- }
-
-
- # it is of course possible to do command completion with something like
- alias expand.con parsekey erase_to_beg_of_line;type /connect $()
- # /con<tab> expands to /connect
-
- # Be careful though.. note the $() at the end of the line.
- # Without this 'complete' sends expand.con /con and the above
- # alias will add the '/con' back onto the end of the line resulting
- # in /connect /con on the input line when you're done
-
-
- # # # # # # # # # # MODULE WRITING PHILOSOPHY # # # # # # # # # #
- # Some thoughts about using complete and designing complete modules.
- #
- # Basically for any given time you hit TAB there are three states
- # normal, null, and nomatch
- # normal - there is something on the command line to process
- # and the command is in the command list maintained by 'complete'
- # The associated command parser is called with the contents of the
- # input line in it's entirety as the arguments.
- # null - there is nothing at all on the command line and some
- # default action must be taken. No parser need be called at all as well.
- # nomatch - the command at the head of the input line is not
- # found in the list of commands maintained by 'complete'.
- # A default 'nomatch' parser may or may not be called but if it is called
- # it's passed the entire contents of the input line.
- #
- # This is not the end of the story however.
- # If you're writing a completion module of some sort there are the same
- # 3 states plus 1 more. Let's say you want to write something to
- # find a match for a given keyword prefix out of a list when you hit
- # TAB. e.g. /eat ap<TAB> looks for matching words that start with ap
- # The 4 actions are
- # normal - There is a single match for ap and it expands /eat apple
- # multiple matches - There is more than one match for ap and thus
- # a choice must be made. Possible choices include
- # 1. do nothing
- # 2. list possible matches (like ^D) or set showmatch in tcsh shell
- # *** matches for prefix 'ap': apple apricot apendage
- # 3. match only the first occurance Currently what the /connect module
- # does /eat apple
- # 4. cycle through the possible matches for the keyword 'ap'.
- # The 'testparse' modules uses this scheme and it's my favorite
- # albiet a tad more expensive in terms of CPU cycles and responce
- # time. (I'm sure someone could see the diff.. I can't ;)
- # /eat ap<TAB> -> /eat apple<TAB> -> /eat apricot<TAB> etc..
- # 5. display worthless error message
- # *** non-unique matches found
- # nomatch - as as before, nomatching keywords are found, the choices are
- # limited to things like displaying the whole list or just cycling through
- # to the next item in the list like the 'tabkey' script's 'messparse' does.
- # null - This one is more likely to happen only if 'complete' saw the
- # input line as null, but then the null action is ussually special anyway.
- # Otherwise this may occur when you say just /eat<TAB> and the obvious
- # thing to do here is just to display the list of items to choose from
- # in an appropriate format.
-
- # Just remember.. the parsing routine can really do anything it wants..
- # it could simply 'sendline' the line on to the server and push a
- # button to start WWIII when you hit tab.. It doesn't have to mess with the
- # command line but it's more useful that way. Although.. you could write
- # a tab completion module that when tab was hit.. it spell checked
- # the line.. anything is possible..
-