home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ircii30.zip / script / compl.mods < prev    next >
Text File  |  1994-07-30  |  13KB  |  350 lines

  1. # Complete Modules by Ian Frechette
  2. # Last updated 2-2-94
  3. # example modules
  4. # Don't let the size scare you.  This is a whole collection of 
  5. # examples and comments about the design of modules
  6. # meat of all this are the interface functions to 'complete'
  7. # compl.add, and compl.list  (soon to be compl.del)
  8. # the function that does the work is compl.parse  which is very small
  9. #   and whatever parsing routine it calls.
  10.  
  11. # These should actually all be in their individual modules
  12. # but this is just an example file..
  13.  
  14. # Note.. compl.list is internal to complete.. shoulnd't normally be used
  15. if (compl.list == [])
  16. {
  17. # Note here.. Currently, if you compl.add /blah blahparse
  18. # followed by  compl.add /blah otherparse    only the latter will
  19. # called.  No conflict message is shown unless you replace the
  20. # default 'null' and 'nomatch' parsers.
  21.     compl.add -null -nomatch /m messparse
  22.     compl.add /msg messparse
  23.     compl.add /connect connparse
  24.     compl.add /tr connparse
  25.     compl.add /load loadparse
  26.     compl.add /test testparse
  27.     compl.add /con expand.con
  28.     compl.add /conbunch expand.con
  29. }
  30.  
  31.  
  32. # message parser module..   Compatible with included tabscript
  33. # currently calls the tabkey script under 3 conditions
  34. # the input line has more than 2 argments on it.. '/msg bob thud<TAB>'
  35. # the input line has nothing on it '<TAB>'
  36. # the input line has only one argument and the character before the 
  37. #   cursor is a space    '/msg bob <TAB>'
  38. # plus it now does nickname completion
  39. # /m D<TAB>   expands to   /m Daemon   and so on
  40. alias messparse {
  41.     if (([$1] != []) && ([$2] == []))
  42.     {
  43.         if (right(1 $*) != [ ])
  44.         {
  45.             # this is the simple match.. just match first occurance
  46.             # and expand
  47.             if (mp.cnt = match($(1)* $tk.msglist))
  48.             {
  49.                 parsekey delete_previous_word
  50.                 # in case one does  /m =ni<TAB> it must delete the =
  51.                 if (index(#=% $1) >= 0) {parsekey backspace}
  52.                 type $word(${mp.cnt - 1} $tk.msglist)
  53.                 type ${[ ]}
  54.             }
  55.         }
  56.         {
  57.             ^tk.getmsg 1 $tk.msglist
  58.         }
  59.     }
  60.     {
  61.         ^tk.getmsg 1 $tk.msglist
  62.     }
  63. }
  64.  
  65.  
  66. # connect module  for opers..    easily changeable to kicks, bans.. etc..
  67. # simply use  /connect <TAB> for list or /connect <uniqid tag><TAB>
  68. # eg.  /connect pen<TAB>  expands to  /connect penfold.ece.uiuc.edu 
  69. # It always expands first matching string.  Look at testparse for
  70. # a more intelligent way to do it.
  71.  
  72. @ 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]
  73.  
  74. alias connparse {
  75.     if ([$1] != [])
  76.     {
  77.         @ cp.line = [$*]
  78.         if ((right(1 $*) == [ ]) && ([$2] == [])&& ([$0] == [/connect]))
  79.         {
  80.             type 6667;type ${[ ]}
  81.             # note.. if converted to use smartparse.. the port number must
  82.             # be removed here.. the above logic conflicts with SP
  83.         }
  84.         {
  85.             # expand only the first match found (See 'testparse' for better way
  86.             if (cp.cnt = match($(${#cp.line -1})* $connlist))
  87.             {
  88.                 delword
  89.                 type $word(${cp.cnt - 1} $connlist)
  90.                 type ${[ ]}
  91.             }
  92.             {
  93.                 echo *** connlist $connlist
  94.             }
  95.         }
  96.     }
  97.     {
  98.         echo *** connlist $connlist
  99.     }
  100. }
  101.  
  102. # Load module
  103. # /load net<TAB> expand to /load netsplit  and so on.
  104. # Note the problem right now is that it only finds and expands the first
  105. # name in the list  I think we can get around this.
  106. @ loadlist = [netsplit ircgrep cut-paste compl.mods]
  107. alias loadparse {
  108.     if ([$1] != []) {
  109.         if (lp.cnt = match($(1)* $loadlist))
  110.         {
  111.             parsekey delete_previous_word
  112.             type $word(${lp.cnt - 1} $loadlist)
  113.         }
  114.     }
  115.     {
  116.         echo *** loadlist = $loadlist
  117.     }
  118.     ^assign -lp.cnt
  119. }
  120.  
  121. # ############ stuff related to SMARTPARSE ###################
  122. # The new testparse rewritten to use the
  123. # extremely awsome smartparse routine.
  124.  
  125. if (!match(/test $compl.list)) {compl.add /test testparse}
  126.  
  127. # just a quick alias for making LINKS lists..  /makelist testlist *.edu
  128. # will make a list of all *.edu servers..   Note that just * is 
  129. # generally too big a list for ircII
  130. alias makelist {
  131.     if ([$1])
  132.     {
  133.         ^on ^364 * push $0 $$1
  134.         links $1-
  135.         wait -cmd eval ^on 364 -\;echo *** makelist finished
  136.     }
  137. }
  138.  
  139. @ testlist = [aone atwo athree bone btwo bthree ircserver.iastate.edu ircserver.santafe.edu]
  140.  
  141. # testparse <cmd> <stuff....pat>
  142. # this is called by the complete routines.
  143. @ tp.tmp = [0 :]
  144. # [0 :] represents a count of 0.. and a null pattern :<pat> 
  145. alias testparse {
  146.     # ignore this first line.. 
  147.     @ tp.cnt = [$*]
  148.     @ tp.cnt = #tp.cnt
  149.     ^assign -tp.pat 
  150.     # all the cnt stuff is in case you do  /command word1 word2 pattern<tab>
  151.     if (tp.cnt > 1)
  152.     {
  153.         @ tp.pat = [$(${tp.cnt - 1})]
  154.         # '/command pattern ' leaves <pat> null
  155.         # '/command pattern'  sets <pat> to a new pattern
  156.         # important because smartparse may leave a space
  157.         if (right(1 $L) != [ ]) {@ tp.tmp = [0 :$tp.pat]}
  158.  
  159.         # Uncomment the following line to see how it works from here.. debugging
  160.         # echo smartparse\($tp.tmp testlist $tp.pat\)
  161.  
  162.         # call testparse with current cnt :<pat> <listname> <newpat>
  163.         @ tp.tmp = smartparse($tp.tmp testlist $tp.pat)
  164.         # note tp.tmp accounts for two arguments.. and is modified and saved
  165.  
  166.         if (left(1 $word(1 $tp.tmp)) == [,])
  167.         {echo *** no match for pattern [$tp.pat] found in list} 
  168.         {if (left(1 $word(1 $tp.tmp)) == [.])
  169.         {echo *** testlist: $testlist}}
  170.     }
  171.     {
  172.         echo *** testlist : $testlist
  173.     }
  174. }
  175.  
  176. alias test echo *** TEST: You've matched: $*
  177.  
  178. # test module
  179. # Trying to make some sort of intelligent handling of the tab lists.
  180. @ sp.cnt = 0
  181.  
  182. # call it with smartparse <cnt> :<pat> <listname> <newpat>
  183. #                          $0    $1       $2        $3
  184. # returns <counter> [:,.]<pattern>
  185. #                    : == successful match   , == no match  . == null
  186. #
  187. #  Look at how testparse uses it.. you shouldn't have to touch any
  188. # smartparse vars.. It's all handled through the interface.. basically
  189. # you're telling it where to start looking in the list and how
  190. # long the list is..   Each time smartparse is called it returns a counter
  191. # value indicating where it left off last time.  You can save it
  192. # or not..   testparse saves it.. and passes it back as the new
  193. # starting position  <cnt>
  194. #
  195. # Assuming the counter, pattern, and list are maintained through each call
  196. # it'll assume you're searching forward in the list from some place
  197. # after the last word matched in the list..   
  198. #
  199. # If you feed it a <newpat> for which <pat> is not a subset, it'll reassign
  200. # <pat> to <newpat> and restart the process.. 
  201. # It defaults to expansion..  so..  <pat> = blah
  202. # will match blahone, blahtwo etc. Works with wildcards.. *a* matches a lot
  203. # Try it.
  204.  
  205. ^assign -sp.tmp
  206. alias smartparse {
  207. # int sp.tmp     - index of last match found
  208. # int sp.cnt     - position in list
  209. # int sp.max     - max number of elements in list
  210. # string sp.pat  - match pattern 
  211.     if ([$3] != [])
  212.     {
  213.         # Extract <pat> from  :<pat>    Note.. It may be null
  214.         @ sp.pat = mid(1 50 $1)
  215.         @ sp.max = [$(#$2)]
  216.         @ sp.cnt = [$0]
  217.         # set pattern.   Determine if we've changed the base pattern or not
  218.         if (sp.pat == [])
  219.             {@ sp.pat = [$3]}
  220.             { if (!match($(sp.pat)* $3)) {@sp.pat = [$3]} }
  221.         @ sp.run = 1
  222.  
  223.         while (((sp.list = words($sp.cnt $sp.max $($2))) != []) && (!sp.tmp) && sp.run)
  224.         {
  225.             # look for match in list
  226.             if (sp.tmp = match($(sp.pat)* $sp.list))
  227.             {
  228.                 # sp.cnt is absolute position in list.  Jump over found item.
  229.                 # to set up for the next call to smartparse
  230.                 @ sp.cnt = sp.cnt + sp.tmp
  231.  
  232.                 # parsekey delete_previous_word
  233.                 delword
  234.                 type $word(${sp.tmp - 1} $sp.list)
  235.                 type ${[ ]}
  236.             }
  237.             {
  238.                 # nothing found.. drop out of loop
  239.                 # for this condidtion to occur we must be at the beginning
  240.                 # of the loop... either first pass.. or just looped back
  241.                 if (!sp.cnt && !sp.tmp)
  242.                 {
  243.                     # notfound condition set for return value later
  244.                     @ sp.notfound = [$sp.cnt ,$sp.pat]
  245.                     @ sp.run = 0
  246.                     # echo *** smartparse: no matching pattern
  247.                 }
  248.                 # loop back
  249.                 @ sp.cnt = 0
  250.             }
  251.         }
  252.         ^assign -sp.tmp
  253.         if (!sp.list) {@sp.cnt = 0}
  254.         ^assign -sp.list
  255.         if (sp.notfound == [])
  256.             {@ function_return = [$sp.cnt :$sp.pat]}
  257.             {@ function_return = sp.notfound;^assign -sp.notfound}
  258.     }
  259.     {
  260.     # echo *** sp NULL
  261.         # echo *** $2: $($2)
  262.         @ function_return = [$sp.cnt .$sp.pat]
  263.     }
  264.     ^assign -sp.run
  265. }
  266.  
  267. # alias words.. usage   $word(<begin> <end> <words>)
  268. # words(0 2 zero one two three ... ) ==  'zero one two'  and so on
  269. alias words {
  270.     @ function_return = [$(${[$0]+2}-${[$1] +2})]
  271. }
  272.  
  273. # This is like  DELETE_PREVIOUS_WORD except that it delets to the
  274. # previous space which is much more useful than the current
  275. # behavior of deleting to the previos non- [a-zA-Z0-9] char. :-?
  276. alias delword {
  277.     parsekey erase_to_end_of_line
  278.     if ((dw.char = right(1 $L)) != [ ]) {@ dw.nw = 0} {@dw.nw = 1}
  279.     while (((dw.char != [ ]) || dw.nw) && (dw.char != []))
  280.     {
  281.         parsekey backspace
  282.         if ((dw.char = right(1 $L)) != [ ]) {@ dw.nw = 0}
  283.     }
  284.     ^assign -dw.char;^assign -dw.nw
  285. }
  286.  
  287.  
  288. # it is of course possible to do command completion with something like
  289. alias expand.con parsekey erase_to_beg_of_line;type /connect $()
  290. # /con<tab> expands to /connect
  291.  
  292. # Be careful though.. note the $() at the end of the line.
  293. # Without this 'complete' sends expand.con /con   and the above
  294. # alias will add the '/con' back onto the end of the line resulting
  295. # in /connect /con     on the input line when you're done
  296.  
  297.  
  298. # # # # # # # # # # MODULE WRITING PHILOSOPHY # # # # # # # # # #
  299. # Some thoughts about using complete and designing complete modules.
  300. #
  301. # Basically for any given time you hit TAB there are three states
  302. # normal, null, and nomatch
  303. # normal - there is something on the command line to process
  304. #   and the command is in the command list maintained by 'complete'
  305. #   The associated command parser is called with the contents of the
  306. #   input line in it's entirety as the arguments.
  307. # null -  there is nothing at all on the command line and some
  308. #   default action must be taken.  No parser need be called at all as well.
  309. # nomatch - the command at the head of the input line is not
  310. #   found in the list of commands maintained by 'complete'.
  311. #   A default 'nomatch' parser may or may not be called but if it is called
  312. #   it's passed the entire contents of the input line.
  313. #
  314. # This is not the end of the story however.
  315. # If you're writing a completion module of some sort there are the same
  316. # 3 states plus 1 more.  Let's say you want to write something to 
  317. # find a match for a given keyword prefix out of a list when you hit
  318. # TAB.  e.g. /eat ap<TAB>   looks for matching words that start with ap
  319. # The 4 actions are
  320. # normal - There is a single match for ap and it expands /eat apple
  321. # multiple matches - There is more than one match for ap and thus
  322. #   a choice must be made.  Possible choices include
  323. #   1. do nothing
  324. #   2. list possible matches   (like ^D) or set showmatch in tcsh shell
  325. #      *** matches for prefix 'ap': apple apricot apendage
  326. #   3. match only the first occurance  Currently what the /connect module
  327. #      does    /eat apple
  328. #   4. cycle through the possible matches for the keyword 'ap'.
  329. #      The 'testparse' modules uses this scheme and it's my favorite
  330. #      albiet a tad more expensive in terms of CPU cycles and responce
  331. #      time. (I'm sure someone could see the diff.. I can't ;)
  332. #      /eat ap<TAB> -> /eat apple<TAB> -> /eat apricot<TAB> etc.. 
  333. #   5. display worthless error message
  334. #      *** non-unique matches found
  335. # nomatch - as as before, nomatching keywords are found, the choices are
  336. #   limited to things like displaying the whole list or just cycling through
  337. #   to the next item in the list like the 'tabkey' script's 'messparse' does.
  338. # null - This one is more likely to happen only if 'complete' saw the
  339. #   input line as null, but then the null action is ussually special anyway.
  340. #   Otherwise this may occur when you say just /eat<TAB> and the obvious
  341. #   thing to do here is just to display the list of items to choose from
  342. #   in an appropriate format.
  343.  
  344. # Just remember.. the parsing routine can really do anything it wants.. 
  345. # it could simply 'sendline' the line on to the server and push a
  346. # button to start WWIII when you hit tab.. It doesn't have to mess with the
  347. # command line but it's more useful that way.  Although.. you could write
  348. # a tab completion module that when tab was hit.. it spell checked
  349. # the line.. anything is possible.. 
  350.