home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / sprint / texmac.zip / GLOSS.SPM < prev    next >
Text File  |  1991-11-23  |  21KB  |  720 lines

  1. ; Copyright (c) 1988 Borland International.  All Rights Reserved
  2. ;
  3. ; NAME: GLOSS.SPM
  4. ; VERSION: 1.01
  5. ; DESCRIPTION: Glossary Macro Package for Sprint
  6. ; LAST UPDATE: September 9, 1988, 6/19/91 RDT to ensure HOME dir is used right
  7. ; ALWAYS make sure QA is handled to look in HOME dir if it exists
  8. ; I did this by modifying GlossQDName and trying to always use it
  9. ; instead of QA itself
  10. ;
  11. ; NOTES: This file must be compiled and loaded AFTER CORE.SPM any other macro
  12. ; packages.
  13. ; Should probably merge in all the macrocoll stuff from nother,
  14. ; since it's more logical and useful to only use macro recording under
  15. ; the auspices of Glossary
  16. ; These macros use QB to hold a definition file, and QC to hold a string.
  17. ; The glossary function defaults to a glossary file called "standard.spg".
  18. ; The name is stored in QA.  When a new glossary name is chosen, its name
  19. ; is placed in QA.  It is the responsibility of the UI to insure that
  20. ; QA is initialized to the proper glossary name on Start-up.
  21. ; You should probably not use either one, or at least, if you use QC, set
  22. ; it to be empty when you're done.  (At the expense of speed, you can do the
  23. ; same to QB.)  If the glossary has been modified, you should really write
  24. ; it out (silently): "mark (to QB if modf (write QA))"
  25. ; when the user exits, without asking.  Alternatively, the write can be done
  26. ; (or done with query) each time the glossary is actually modified.  In order
  27. ; for this to work, the macros should not use QB for *anything* else, because
  28. ; a length-test is done to determine if the glossary file has been loaded.
  29. ;
  30. ; The glossary file has the following structure:
  31. ;    char. 255
  32. ;    Item name
  33. ;    char. 255
  34. ;    Hard newline (char. 10)
  35. ;    Item text
  36. ;    Hard newline
  37. ;
  38. ; The first character of the item text may be a '%'.  In that case, it is a
  39. ; flag to indicate that the item text is to be executed as a MACRO, rather than
  40. ; pasting the item text into the file.
  41. ; Macros may have an optional comment at the end, as usually, the comment is
  42. ; separated from the text of the macro by a semicolon. This comment will appear
  43. ; as a description of the macro when using GlossList.
  44. ; An initial value of 254 for the expansion indicates it is a keyboard recording
  45. ; and should be pushed back.
  46. ; Keyboard recordings may have comments too, entered as a description when user
  47. ; ends the record. This description is separated from the the recording by 254
  48. ; character, and will appear in GlossList.
  49. ;
  50. ; Any other character as the first character in the item text is taken to be a 
  51. ; literal character to be inserted.
  52. ; As you can see, this means that strings in the glossary are not allowed to
  53. ; contain character numbers 255/254, or start with a '%'.  Names are restricted
  54. ; to be just tokens.
  55. ;
  56. ; These operations are available:
  57. ;
  58. ;    GlossChange        load new glossary file
  59. ;    GlossDefine1        add new item, ask for name, expansion in clipboard
  60. ;    GlossDefine2        add new item, name in QD, expansion in clipboard
  61. ;    GlossDefineKey        add recording in QF to glossary, ask for name
  62. ;    GlossInsertText    Insert glossary text from QC, reading ruler if present
  63. ;    GlossLookup1        expand item, find name in text
  64. ;    GlossLookup2        expand item, ask for name
  65. ;    GlossLookup3        expand item, name in QD
  66. ;    GlossLookup4        expand item, try from file, else prompt, ENTER = pick
  67. ;    GlossDelete        delete item, ask for name
  68. ;    GlossRename        rename item, ask for name, ask for new name
  69. ;    GlossMakeList        Display menu of items, return name in QC
  70. ;    GlossPickList        Display menu of items, expand picked item
  71. ;    GlossQDName        Take file name in QA, move to QD, prepending home dir
  72. ;    GlossList            list all items
  73. ;    GlossErase        erase all items
  74. ;    GlossSave            save all items if modified and length != 0
  75. ;    GlossWrite        always save all items
  76. ;    GlossEnsure        load all items
  77. ;
  78. ;----------------------------------------------
  79. ; Q register usage: see SP.SPM for table
  80. ;-------------------------------------------===
  81. ;    NUMBERED MARK USAGE:
  82. ;    see SP.SPM
  83. ;----------------------------------------------
  84. ;    CONTENTS:
  85. ;    SECTION:  Routines whose definitions are to be removed.
  86. ;    SECTION:    Routines that MUST exist for the compiler to work
  87. ;    SECTION:    Variables -- all the variables are declared here
  88. ;    SECTION:    Forward declarations -- In order to keep the main list
  89. ;            of macros in alphabetical order, a few of them have to be
  90. ;            declared ahead of time -- like a FORWARD declaration
  91. ;            in Pascal
  92. ;    SECTION:    Automatically-called macro definitions (Main, Init,
  93. ;            EditKeys, MacroKeys, etc.)
  94. ;    SECTION:    General and command macros in alphabetical order
  95. ;    SECTION:    Menus (leaves first, root last)
  96. ;    SECTION:    Control and function keys
  97. ; -----------------------------------------------------------------
  98. ; Deletions
  99.  
  100. ; -----------------------------------------------------------------
  101. ; Compiler-Required Definitions
  102.  
  103. ; -----------------------------------------------------------------
  104. ; Variables
  105.  
  106. int GlossType
  107.  
  108. ; -----------------------------------------------------------------
  109. ; Forward Declarations
  110.  
  111. GlossDefineRest :
  112. GlossDefineStart :
  113. GlossDeleteRest :
  114. GlossFound :
  115. GlossFoundMsg :
  116. GlossGetName :
  117. GlossInsertText :
  118. GlossLookupRest :
  119. GlossMakeList :
  120. GlossPickList :
  121. GlossPrep :
  122. GlossQDName :
  123. GlossSave :
  124. TimeDate :
  125.  
  126. ; -----------------------------------------------------------------
  127. ; Automatically-Called Macro Definitions
  128.  
  129. ; -----------------------------------------------------------------
  130. ; General Macros
  131.  
  132. ; Prompt for new glossary name, create one if name doesn't exist
  133.  
  134. GlossChange : ; RDT, changed
  135.     GlossSave    ; save any existing glossary
  136.     set QB ""    ; force a reread of new file
  137. ;    set QD ""
  138.     GlossQDName  ; put QA in QD and massage
  139.     message "\nGlossary to use: "    set QD  ; allow user to change QD/QA
  140.     if (!length QD) (set QD "*.spg")        ; to force a list if no entry
  141.     set QD fchange "%.SPG" QD
  142.     13 QCap
  143.     if !(2 exist QD) {
  144.         1 Bell
  145.         message "\nCould not find `"
  146.         message QD
  147.         if (ask "'.  Create it? ") {
  148.             set QB ""    ; clear out anything that was in swap file
  149.             open QD
  150.             if !stopped (write "%")
  151.             (set QA QD) else (message "\nIllegal glossary name")
  152.             close
  153.             }
  154.         }
  155.     else (set QA QD) ; result should be pathed .SPG file in QA
  156.  
  157. ; Get a name, and return T or F depending upon whether the name is in
  158. ; the glossary.
  159.  
  160. GlossCheckName :
  161.     GlossGetName
  162.     GlossFoundMsg
  163.  
  164.  
  165. ; Add a new name, asking the user for the name.  If a region is
  166. ; selected, add that text.  Otherwise, use what is in the clipboard.
  167.  
  168. GlossDefine1 :
  169.     GlossDefineStart
  170.     if (select = 1) {
  171.         copy togmark
  172.         Unselect
  173.         }
  174.     else if (select > 1)
  175.         (error "You cannot glossarize columns of text, only regions.")
  176.     message "\nEnter the name for this item: "
  177.     1->GlossType
  178.     GlossGetName
  179.     GlossDefineRest
  180.  
  181.  
  182. ; Add a new name.  The new name is in QD and the expansion is in the
  183. ; clipboard.
  184.  
  185. GlossDefine2 :
  186.     GlossDefineStart
  187.     set QC QD
  188.     1->GlossType
  189.     GlossDefineRest
  190.  
  191. ; Take the keyboard recording in QF and place it in the glossary.
  192. ; Ask for name, Check length of QF, give error if to long (> 1024 keys)
  193. ; Keyboard recording will be marked by having a first character byte value
  194. ; of 254 (feh).
  195.  
  196. GlossDefineKey :
  197.     if (length QF > 1024) error "Recording too long to play back."
  198.     else if (length QF==1) {    ; user canceled immediately
  199.         message "\nRecording Canceled."
  200.         return
  201.         }
  202.     GlossDefineStart                ; check exist QA, if recording was short enough...
  203.     message "\nEnter the name for this recording: "
  204.     GlossGetName
  205.     set QD "" message "\nDescription (Enter for none): "
  206.     set QD                        ; description in QD
  207.     mark {
  208.         to QF
  209.         254 insert                ; mark item as recording
  210.         toend 254 insert insert QD    ; add description
  211.         }
  212.     2->GlossType GlossDefineRest
  213.  
  214. ; Do the rest of the work for GlossDefine*
  215.  
  216. GlossDefineRest :
  217.     if GlossFound {
  218.         message "\nDo you want to replace the existing `"
  219.         message QC
  220.         if (ask "'? ") GlossDeleteRest
  221.         else return
  222.         }
  223.     mark {
  224.         to QB
  225.         f toend
  226.         insert QC                        ; name between 255's
  227.         '^J' insert                    ; new line
  228.         if (GlossType = 2) insert QF         ; keyboard recording: in QF
  229.         else undelete                    ; macro or text: in clipboard
  230.         '^J' insert                    ; new line
  231.         r (to current = 255) c            ; go to start of expansion text
  232.         mark {
  233.             while (255 csearch) del    ; sanitize the text to be glossarized
  234.             }
  235.         if current = '%' {            ; if a macro, remove all NL's and Tabs
  236.             while ('^J' csearch) (32 -> current)
  237.             r to (current = 255) while ('^I' csearch) (32->current)
  238.             }
  239.         }
  240.  
  241.  
  242. ; Set up for GlossDefine*
  243.  
  244. GlossDefineStart : ; RDT, changed
  245. ;    set Q0 "spedit.exe" NeedDisk
  246.     GlossQDName ; massage QA
  247.     if !(2 exist QD) {
  248.         1 Bell
  249.         message "\nCould not find `"
  250.         message QD
  251.         if (ask "'.  Create it? ") {
  252.             ; GlossQDName ; unnecessary now
  253.             open QD
  254.             write "%"
  255.             close
  256.             }
  257.         }
  258.  
  259. ; Ask for a name and delete the glossary entry.
  260.  
  261. GlossDelete :
  262.     message "\nGlossary item to delete (Enter for list): "
  263.     if GlossCheckName {
  264.         GlossDeleteRest
  265.         if (!length QB) {
  266.             mark {
  267.                 to QB
  268.                 GlossQDName 1 write QD
  269.                 }
  270.             }
  271.         draw
  272.         message "\nItem deleted."
  273.         }
  274.  
  275.  
  276. ; Delete the glossary entry contained in QC.  The entry is known to exist.
  277.  
  278. GlossDeleteRest :
  279.     mark {
  280.         to QB
  281.         1 search QC
  282.         mark {
  283.             toeol
  284.             255 csearch
  285.             erase tomark
  286.             }
  287.         }
  288.  
  289.  
  290. ; Make sure that the glossary is loaded.  If not, error out.  Note
  291. ; that a zero-length glossary file will always be reread.
  292.  
  293. GlossEnsure : ; RDT, changed
  294. ;    set Q0 "spedit.exe" NeedDisk
  295.     GlossQDName  ; put QA in QD and massage
  296.     mark {
  297.         to QB
  298.         if (!length && !(2 read QD))
  299.             (error "Glossary file not found.")
  300.         }
  301.  
  302.  
  303. ; Erase the glossary.
  304.  
  305. GlossErase : ; remove gloss file 
  306.     GlossEnsure
  307.     set QB ""
  308.     mark (to QB 0->modf)
  309.     GlossQDName
  310.     fdelete QD
  311.  
  312.  
  313. ; Prepare the name in QC and check whether it exists.  Return T/F
  314.  
  315. GlossFound :
  316.     12 GlossPrep
  317.     GlossEnsure
  318.     mark (to QC while !isend ToLower)    ; convert name to lowercase
  319.     mark {
  320.         to QB
  321.         if (1 search QC) 1
  322.         else 0
  323.         }
  324.  
  325.  
  326. ; Prepare the name in QC and check whether it exists.  Return T/F and
  327. ; print a message if it doesn't.
  328.  
  329. GlossFoundMsg :
  330.     if !GlossFound {
  331.         message "\nNo glossary entry for `"
  332.         message QC
  333.         message "'."
  334.         1 Bell
  335.         0
  336.         }
  337.     else    1
  338.  
  339.  
  340. ; Ask the user for a name of an item and make sure that it is a legal
  341. ; name.
  342.  
  343. GlossGetName :
  344.     set QC ""
  345.     set QC                        ; get the name
  346.     mark {
  347.         to QC                    ; make sure it's a simple name
  348.         while ((f past istoken) && !isend) {
  349.             if stopped {
  350.                 message "\nThat name is invalid.  Please enter another: "
  351.                 set QC ; hope this always works (setting itself inside qswitch!)
  352.                 r toend
  353.                 } abort
  354.             }
  355.         }
  356.     if !length QC {                ; if QC empty get name from list
  357.         if stopped{
  358.             GlossMakeList            ; force a name into QC
  359.             } abort
  360.         }
  361.  
  362.  
  363. ; Insert Glossary expansion.  If it contained a ruler, read it.
  364.  
  365. GlossInsertText :
  366.     insert QC
  367.     mark(to QC '^K' csearch) ? (readruler refill)
  368.  
  369. ; List all the glossary items.  This is going to be put into a fixed
  370. ; file name in a buffer.  We use QC for intermediate storage of the
  371. ; list because of the problem of getting back to where we were in QB
  372. ; if we were to switch into the file to copy the name each time.
  373.  
  374. GlossList :
  375.     GlossEnsure
  376.     status "\nBuilding glossary list..."
  377.     0->append
  378.     set Q0 fchange "%.SPR" QA                    ; under name
  379.     if 0 QWild 10 set Q0 flist Q0
  380.     if (buffind Q0 || open Q0) clear                ; erase if needed
  381. ;    70->rightmargin 0->indent 15->leftmargin insertruler    ; ensure proper alignment
  382.     insert "List for " insert QA insert " as of " TimeDate
  383.     insert "^J^JDefined Glossary Items^J"
  384.     insert "----------------------^J"
  385.     mark {
  386.             to QB
  387.             while (255 csearch) {                ; find entry name
  388.             c copy (to (current = 255)) QC        ; copy name in QC
  389.             toeol c                            ; to entry on next line
  390.             copy (to (current = 255) r c) QD        ; put entry in QD
  391.             mark {to QD                        ; look at entry
  392.                 if (current = '%') {            ; this is a Sprint Macro
  393.                     erase (to current =';')        ; look for comment
  394.                     del erase past iswhite        ; go to text of comment
  395.                     insert "MACRO: "        }            ; insert glossary type
  396.                 if (current = 254)            {    ; this is a record
  397.                     del erase to (current = 254)
  398.                     del insert "RECORDING: " }
  399.                 if (current = '^K') {            ; this is a ruler line
  400.                     del
  401.                     insert "RULER: "
  402.                     toeol c r del
  403.                             }
  404.                 else (r c)                    ; normal text
  405.                 if (to isnl) (erase toend insert "...")    ; too long...
  406.                 buffind Q0 toend insert QC        ; entry name
  407.                 tosol ToUpper toeol                ; Names in init caps
  408.                 '^I' insert insert QD '^J' insert    ; tab and expansion
  409.                 }
  410.                                 }
  411.         }
  412. ;    0->modf                            ; allow quitting with no prompt
  413.     r toend                            ; Top of file.
  414.  
  415.  
  416. ; Pull word out from text, Return True if found, false if no entry
  417.  
  418. GlossLookupStart :
  419.     int GlossTmp
  420.     mark {
  421.         if isgray (r past iswhite)        ; if between words, do prev
  422.         r past istoken
  423.         if inruler {
  424.             set QC ""
  425.             0->GlossTmp
  426.             }
  427.         else mark {
  428.             past istoken
  429.             copy tomark QC                    ; get the word
  430.             GlossFound->GlossTmp
  431.             if GlossTmp (erase tomark)
  432.             }
  433.         }
  434.     GlossTmp
  435.  
  436. ; #1: Find the word just before the cursor, or the word
  437. ; that the cursor is in, and replace it with the glossary entry.
  438.  
  439. GlossLookup1 :
  440.     if GlossLookupStart GlossLookupRest
  441.     else {
  442.         if !length QC message "\nEntry not defined."
  443.         else {
  444.             message "\nNo glossary entry for `"
  445.             message QC
  446.             message "'."
  447.             }
  448.         1 Bell
  449.         }
  450.  
  451.  
  452. ; #2: Ask the user for the name and insert the expansion.
  453.  
  454. GlossLookup2 :
  455.     message "\nGlossary item to insert (Enter for list): "
  456.     if GlossCheckName GlossLookupRest
  457.  
  458.  
  459. ; #3: Use the name in QD and insert name and insert the expansion.
  460.  
  461. GlossLookup3 :
  462.     set QC QD
  463.     if GlossFoundMsg GlossLookupRest
  464.  
  465.  
  466. ; #4: Try #1, if not found, prompt, if user presses [ENTER] give list
  467.  
  468. GlossLookup4 :
  469.     if record (stopped error "Glossary not available while recording" return)
  470.     if GlossLookupStart GlossLookupRest    ;try to expand from file
  471.     else    {                            ; could not expand from file, so ask user
  472. ;        message "\nGlossary item (Enter for list): "
  473. ;        GlossGetName 
  474.         GlossMakeList    ; skip the user input and draw the list
  475.         if GlossFoundMsg GlossLookupRest
  476.         }
  477.  
  478. ; used by GlossLookup*.  This routine locates and inserts the expansion.
  479. ; if it's a macro, it executes it.
  480.  
  481. GlossLookupRest :
  482.     mark {
  483.         to QB                    ; contains the glossary
  484.         1 search QC                ; the name is known to exist
  485.         toeol                    ; end of line name is on
  486.         f c                        ; next line: expansion
  487.         mark {
  488.             255 csearch            ; find end of expansion
  489.             r c                    ; don't take 255
  490.             0->append                ; don't add to QC (just in case)
  491.             copy tomark QC            ; copy expansion to QC
  492.             }
  493.         }
  494.     mark {
  495.         to QC                    ; process this expansion
  496.         current case {
  497.             '%' del 1->GlossType,    ; check if macro, and delete leading '%'
  498.             254 del 2->GlossType    ; keyboard recording
  499.                 if (254 csearch) (erase toend),    ; get rid of description
  500.             $   0->GlossType        ; plain text
  501.             }
  502.         }
  503.     GlossType case {                ; case must do stuff outside of QC
  504.         1 if ((length QC) < 512) {
  505.             set QG QC    ; put it in Q for MacroExecute again, I spose this is dumb
  506.             macro QC
  507.             }
  508.           else error "Macro too long",        ; execute the macro
  509.         2 mark(to QC copy toend QF) keypushback QC,        ; push back the keyboard recording, and place into QF too for macro iterate, RDT
  510.         $ GlossInsertText            ; insert text
  511.         }
  512.  
  513.  
  514. ; Display menu, return the chosen name in QC
  515.  
  516. GlossMakeList :
  517.     GlossEnsure                    ; force load of glossary
  518.     if !(length QB) (error "No entries are defined")
  519.     0->append
  520.     set QC ""                        ; clear QC to receive list
  521.     mark {
  522.         to QB
  523.         while (255 csearch) {        ; find entries
  524.             c                    ; jump 255
  525.             copy (to (current = 255)) QD    ; copy entry in scratch Qreg
  526.             mark (to QC toend            ; go to end of QC in imenu format:
  527.             insert "^I\"" 
  528.             insert QD insert "\",^J")    ; tab, entry between quotes,
  529.             toeol c                ; to return value, comma new line
  530.             to current = 255        ; skip expansion
  531.             }
  532.         to QC
  533.         insert "imenu \"Glossary Items\" {"    ; build menu
  534.         toend r (del del) insert "$}"        ; delete last new line and comma
  535.         }
  536.     if ((length QC) < 1024) {
  537.         status "\n"
  538.         macro QC                        ; display menu to choose from
  539.         set QC Q0                        ; glossary to expand in QC
  540.         }
  541.     else error "Too many entries for menu"
  542.  
  543. ; Merge two glossary files together.
  544. ; QA contains name of glossary to add items to.
  545. ; system will prompt for name of glossary to add to it.
  546.  
  547. GlossMerge : ; RDT, changed
  548.     GlossEnsure
  549.     set QD home  ;"" ; put home in to suggest correct location
  550.     mark { to QD toend insert "*.SPG" } ; append extension
  551.     message "\nGlossary to merge with '" QA "': " ; current gloss
  552.     set QD
  553.     if (!length QD) (set QD "*.spg")        ; to force a list if no entry
  554.     set QD fchange "%.SPG" QD        ; name is in QD
  555.     if !(2 exist QD) {
  556.         stopped error "Glossary file not found"
  557.         return
  558.         }
  559.     if stopped {
  560.         2 open QD    draw            ; open glossary to be merged
  561.         while (255 csearch) {
  562.             c    ; skip the 255
  563.             copy (to current = 255) QC    ; name in QC
  564.             while GlossFound {    ; item was found so allow user to decide outcome
  565.                 set Q0 QC
  566.                 mark(to Q0 del insert "DUPLICATE ITEM: " toend r del)
  567.                 menu  Q0  {
  568.                     "Replace existing definition"    0,
  569.                     "Add under new name"    1,
  570.                     "Don't merge (skip)"    2
  571.                 }
  572.                 case {
  573.                     0 GlossDeleteRest,    ; erase existing definition
  574.                     1 message "\nNew name for " QC ": " GlossGetName,    ; get a new name
  575.                     2 set QC "" break
  576.                     }
  577.                 } ; end while
  578.             toeol c
  579.             if length QC {        ; if we are adding a definition
  580.                 copy (to current = 255 r c )    ; leave off end of record
  581.                 GlossDefineRest    ; name in QC, expansion in kills buffer
  582.                 }
  583.             }
  584.         close        ; put away glossary
  585.         }
  586.     close
  587.  
  588. GlossPickList :    ; display a menu, let user pick from it
  589.     status "\nBuilding glossary menu..."
  590.     GlossMakeList
  591.     GlossLookupRest
  592.  
  593. ; Prepare the name by inserting 255s.  The argument is the Q register
  594. ; number.
  595.  
  596. GlossPrep :
  597.     mark {
  598.         qswitch
  599.         if current != 255 {        ; if not prepared already....
  600.             255 insert
  601.             f toend
  602.             255 insert
  603.             }
  604.         }
  605.  
  606. ; Make path name for Glossary file name in QD
  607. GlossQDName :
  608.     set QD QA ; get stored gloss file name in scratch QD
  609.     set Q0 home ; put home into Q0 for test and massage
  610.     0 QCap ; cap home
  611.     if (length Q0) { ; if there's a home env. var. massage QD
  612.         mark { to Q0 ; go into Q0
  613.             if !(3 search "[/\\\\:]") { ; if there're no slashes or it's not a drive
  614.                 toend insert '\\' }  ; put in a slash at the right end
  615.              }; end Q0 mark
  616.         mark { to QD ; Now go into the QD register
  617.             if !(3 search "[/\\\\:]") { ; if there're no slashes in QA/QD, it's not a pathed name
  618.                 r toend  ; get in front of QA
  619.                 insert Q0 ; which should be empty or contain HOME Env var
  620.                         ; if empty, current dir. is default
  621.                 }
  622.             } ; end QD mark 
  623.     } ; result of all this should be QD containing massaged version of QA, the current gloss file name
  624.  
  625. ; Rename an existing glossary item.  Ask the user for an item name,
  626. ; make sure that it exists, ask for another name, and make sure that it
  627. ; *doesn't* exist, and then do the rename operation.
  628.  
  629. GlossRename :
  630.     message "\nGlossary item to be renamed (Enter for list): "
  631.     if !GlossCheckName return
  632.     set QD QC        ; save the first name; we'll need it again
  633.     message "\nRename '"
  634.     message QD
  635.     message "' to be: "
  636.     GlossGetName
  637.     if GlossFound {
  638.         message "\nThe new name `"
  639.         message QC
  640.         message "' already exists."
  641.         1 Bell
  642.         return
  643.         }
  644.     else    {
  645.         mark {
  646.             to QB
  647.             1 search QD
  648.             replace found QC
  649.             }
  650.         message "\nItem renamed."
  651.         }
  652.  
  653. ; Save the glossary if it is modified and has a nonzero length.
  654. GlossSave :
  655.     mark {
  656.         to QB
  657.         if (length && modf) {
  658.             message "\nSave changes to glossary file '" QA "'"
  659.             if ask "(Y,N,ESC)?" {
  660. ;                set Q0 "spedit.exe" NeedDisk
  661.                 GlossQDName 1 write QD
  662.                 }
  663.             }
  664.         }
  665.  
  666. ; Always write the glossary.
  667.  
  668. GlossWrite : 
  669. ;    set Q0 "spedit.exe" NeedDisk
  670.     GlossQDName
  671.     mark (to QB write QD)
  672.  
  673. ; -----------------------------------------------------------------
  674. ; Menus
  675.  
  676. ;GlossMenu :
  677. ;    menu "Glossary" {
  678. ;    "Expand item from file"    GlossLookup1,
  679. ;    "Insert item by name"    GlossLookup2,
  680. ;    "Pick item from menu"    GlossPickList,
  681. ;    "Define item"            GlossDefine1,
  682. ;    "Rename item"            GlossRename,
  683. ;    "List items"            GlossList,
  684. ;    "delete item"            GlossDelete,
  685. ;    "Save glossary file"    GlossSave
  686. ;        }
  687.  
  688. KeyAssignGloss : 
  689.     do    {
  690.         status "\nTo which key should the glossary item be assigned: "
  691.         KeyGet->x if (x = '^[') abort
  692.         if (x KeyCanAssign) {
  693.             status "\nBuilding glossary menu"
  694.             GlossMakeList    ; get the name in QC
  695.             set QD ""
  696.             mark {
  697.                 to QD    ; build assign command in QD
  698.                 "set QD \""
  699.                 insert QC    ; name
  700.                 insert "\" glosslookup3"
  701.                 }
  702.             x macro QD    ; and bind it.
  703.             break
  704.             }
  705.         else KeyAssignError
  706.         }
  707.  
  708. KeyRecordEnd :        ; end keyboard recording and insert keys in Glossary
  709.     if record { MacroCollEnd
  710.         GlossDefineKey 
  711.         }    ; see keyrecordgloss
  712.  
  713. KeyRecordGloss :    ; Start recording keys for glossary
  714.     mode "Keyboard recording on. Use Alt-) to end recording."
  715.     MacroCollBegin
  716.  
  717. F1A9H : KeyRecordEnd ; Alt-)
  718.