home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / progs / pari / pari_137 / pari.el < prev    next >
Lisp/Scheme  |  1992-05-20  |  20KB  |  626 lines

  1. ;; This is the interface for pari under emacs
  2. ;; The main commands in this file are
  3. ;; M-x gp      Opens a buffer for interaction with gp and then starts gp.
  4. ;; C-u M-x gp  Like M-x gp, but prompts for command line arguments.
  5. ;; M-x gpman   Displays the gp-pari manual using any dvi preview program.
  6.  
  7. ;; All functions of gp are preserved.
  8.  
  9. ;; This version by David Carlisle (JANET: carlisle@uk.ac.man.cs).
  10. ;; The original pari.el was written by Annette Hoffman.
  11.  
  12.  
  13. ;; Version 2.9 (16/12/91)
  14.  
  15. ;; See  pari.txt  for more details.
  16.  
  17.  
  18. (provide 'gp)
  19.  
  20. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  21.  
  22. ;; The following five  constants (aka variables !) should be
  23. ;; set for each site.
  24.  
  25. (defconst gp-chap3 "~pari/PARISOURCES/tex/usersch3.tex"
  26.   "The TeX source for chapter 3 of the PARI-GP manual")
  27.  
  28. (defconst gp-file-name "/usr/local/bin/gp"
  29.   "The file name of the gp executable file")
  30.  
  31. (defconst gp-man-dvi "~pari/SPARC/tex/users.dvi" 
  32.  "dvi version of the manual")
  33.  
  34. (defconst  gp-menu "~pari/PARISOURCES/pari.menu"
  35.    "menu file")
  36.  
  37. (defconst gp-dvi-preview "xdvi -s 3"
  38. ;; (defconst gp-dvi-preview "texsun"
  39.   "dvi previewer (and options)")
  40.  
  41. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  42.  
  43. ;; Individual users may want to re-set some of the variables in this section
  44. ;; in a gp-mode-hook in their .emacs file.
  45.  
  46. ;; See pari.txt for an example of a gp-mode-hook.
  47.  
  48. (defvar gp-stack-size "4000000"
  49.   "Default stack size: passed to the progam gp.")
  50.  
  51. (defvar gp-buffer-size "30000"
  52.   "Default buffer size: passed to the progam gp.")
  53.  
  54. (defvar gp-prime-limit "500000"
  55.   "Default prime limit: passed to the progam gp.")
  56.  
  57. (defvar gp-prompt-for-args nil
  58.   "A non-nil value makes M-x gp act like C-u M-x gp, 
  59.    ie prompt for the command line arguments.")
  60.  
  61. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  62.  
  63. (setq gp-temp-file (make-temp-name "/usr/tmp/gp_"))
  64.  
  65. (defvar gp-prompt-pattern
  66.   "---- (type return to continue) ----\\|\\?[\C-j\t ]*"
  67.   "Regexp used to match gp prompts.
  68.    can be set with gp-set-prompt (bound to M-\\ p)")
  69.  
  70.  
  71. (defvar gp-map (make-sparse-keymap)
  72.   "Local keymap used in buffer *PARI*.")
  73.  
  74. (define-key gp-map "\C-m"    'gp-send-input)
  75. (define-key gp-map "\M-\C-m" 'gp-copy-input)
  76. (define-key gp-map "\M-\\p"  'gp-set-prompt)
  77. (define-key gp-map "\M-\\t"  'gp-meta-t)
  78. (define-key gp-map "\M-\\d"  'gp-meta-d)
  79.  
  80. (define-key gp-map "\M-\\r"  'gp-meta-r)
  81. (define-key gp-map "\M-\\w"  'gp-meta-w)
  82. (define-key gp-map "\M-\\v"  'gp-meta-v)
  83. (define-key gp-map "\M-\\x"  'gp-meta-x)
  84. (define-key gp-map "\M-\\s"  'gp-meta-s)
  85. (define-key gp-map "\M-\\a"  'gp-meta-a)
  86. (define-key gp-map "\M-\\b"  'gp-meta-b)
  87. (define-key gp-map "\M-\\m"  'gp-meta-m)
  88. (define-key gp-map "\M-\\k"  'gp-meta-k)
  89. (define-key gp-map "\M-\\q"  'gp-meta-q)
  90. (define-key gp-map "\M-?"    'gp-get-man-entry)
  91. (define-key gp-map "\M-\\c"  'gp-menu)    
  92. (define-key gp-map "\M-\\\\"  'gp-break-long-line)
  93. (define-key gp-map "\C-c"    'gp-interrupt)
  94.  
  95. (defvar gp-process nil "")
  96. (defvar gp-man-process nil "")
  97.  
  98. (defun gp (flag)
  99.   "
  100.    Open a buffer and a window for the execution of gp.
  101.  
  102.    The following bindings are available:
  103.    \\{gp-map}
  104.  
  105.   The variables
  106.   gp-file-name gp-stack-size gp-buffer-size gp-prime-limit
  107.   determine the command line that starts gp.
  108.   To override the default settings, give gp a prefix argument.
  109.   C-u M-x gp ."
  110.   (interactive "P")
  111. ;; Create buffer *PARI* and make it become the current buffer.
  112.   (switch-to-buffer "*PARI*") 
  113.   (goto-char (point-max))
  114.   (if gp-process
  115.     nil
  116.     (kill-all-local-variables)
  117.     (setq major-mode 'gp)
  118.     (setq mode-name "GP")
  119. ;; Set up user preferences.
  120.     (run-hooks 'gp-mode-hook)
  121.  
  122. ;; Make gp-map the local map of buffer *PARI*.
  123.     (use-local-map gp-map)      
  124.     (setq mode-line-process '(": %s"))
  125.  
  126. ;; Form the command line string.
  127.  
  128.     (let* (
  129.       (flag (or flag gp-prompt-for-args))
  130.       (gp-command
  131.       (concat
  132.         (gp-read-input "Gp executable ?" gp-file-name "" flag)
  133.         (gp-read-input "Stack size ?" gp-stack-size " -s " flag)
  134.         (gp-read-input "Buffer size ?" gp-buffer-size " -b " flag)
  135.         (gp-read-input "Prime limit ?" gp-prime-limit " -p " flag))))
  136. ;; Insert the command line string into the *PARI* buffer.
  137. ;; (This is just for reference.)
  138.       (insert (concat "\n" gp-command "\n"))
  139. ;; Start gp.
  140.  
  141.       (setq gp-process
  142.         (start-process 
  143.           "pari" "*PARI*" shell-file-name "-c" 
  144.             (concat "stty nl; exec " gp-command))))
  145. ;; Clean up when the gp process has finished.
  146.       (set-process-sentinel gp-process  'gp-sentinel)))
  147.  
  148. (defun gp-read-input (prompt default sep flag)
  149. " If flag is non-nil, reads string then if string is \"\" uses default.
  150.   If flag is nil then string is the default.
  151.   If resulting string is not \"\" prepends sep.
  152.   As a special case, if string is a space, return \"\"."
  153.   (let ((string 
  154.     (if flag
  155. ;; If flag is non-nil prompt for input from mini-buffer.
  156.       (read-input 
  157.         (concat prompt " (Default "default") "))
  158. ;; Else use the default string.
  159.         default)))
  160.     (if (equal string "")
  161.       (if (equal default "") 
  162. ;; If sting and default both "": 
  163.          ""
  164. ;; If string "" and default is non empty:
  165.          (concat sep default))
  166.       (if (equal string " ")
  167. ;; If string is a space:
  168.         ""
  169. ;; If string is non empty:
  170.         (concat sep string)))))
  171.  
  172. (defun gp-sentinel (proc msg)
  173.   "Sentinel for the gp-process in buffer *PARI*."
  174.     (if (get-buffer "*gp-help*") (kill-buffer "*gp-help*"))
  175.     (let ((b (get-file-buffer gp-chap3))) (if b (kill-buffer b)))
  176.     (let ((b (get-file-buffer gp-menu)))  (if b (kill-buffer b)))
  177.     (if (get-buffer "*PARI*")
  178.       (progn
  179.         (set-buffer "*PARI*")
  180.         (goto-char (point-max))
  181.         (insert msg)
  182.         (delete-windows-on "*PARI*")))
  183.     (if (file-exists-p gp-temp-file) 
  184. ;; Let /bin/sh to the removing, as people may have aliased rm to rm -i,
  185. ;;  and apparently -f does not override this on all systems.
  186.        (let((shell-file-name "/bin/sh")
  187.              (shell-command (concat "rm " gp-temp-file)) 
  188.              (message "Removing %s" gp-temp-file ))))
  189.   (setq gp-process nil))
  190.  
  191. (defun gpman()
  192.   "Start up xdvi with the gp manual."
  193.   (interactive)
  194. ;; Run gp-mode-hook in case it specifies a different
  195. ;; version of the manual.
  196.   (run-hooks 'gp-mode-hook)
  197.   (set-buffer (get-buffer-create "*GP-MAN*"))
  198.   (if gp-man-process
  199.      nil
  200. ;; Start xdvi.
  201.     (message (concat "Starting " gp-dvi-preview " " gp-man-dvi))
  202.     (setq gp-man-process
  203.       (start-process "gp-man" "*GP-MAN*"
  204.           shell-file-name
  205.           "-c" (concat "exec " gp-dvi-preview " " gp-man-dvi)))
  206.     (set-process-sentinel gp-man-process 'gp-man-sentinel)))
  207.  
  208. (defun gp-man-sentinel (proc msg)
  209.   "Sentinel for the gp-man-process in buffer *GP-MAN*."
  210.   (let ((buf (process-buffer proc)))
  211.     (if buf (kill-buffer buf)))
  212.   (message (concat "gpman: " msg))
  213.   (setq gp-man-process nil))
  214.  
  215. (defun gp-copy-input()
  216.   "Copy expression around point to the end of the buffer.
  217.    (Unless this is already the last expression.)"
  218.   (interactive)
  219. ;; Go back to the end of prompt, and record that point.
  220. ;; If a line contains more than one prompt string, use the FIRST.
  221. ;; This is so that ? ?cos works. (ie gives the help for cos).
  222. ;; We can not insist on prompt at the beginning of a line (ie put
  223. ;; ^ in gp-prompt-pattern) because of the output from print1()
  224.   (re-search-backward gp-prompt-pattern)
  225.   (let ((p (match-end 0)))
  226.     (beginning-of-line)
  227.     (re-search-forward gp-prompt-pattern)
  228.     (setq gp-input-start (point))
  229. ;; Go past the last prompt on this line before looking for end of expression.
  230.     (goto-char p))
  231. ;; Check if we are already at the last expression.
  232.   (let ((nlast (re-search-forward (concat "[\n ]*\\("
  233.          gp-prompt-pattern
  234.          "\\|^%[0-9]+ = \\|^ *\\*\\*\\*\\|^ *unused characters\\|^ *time[ r]\\)")
  235.              (point-max) t)))
  236. ;; Find the limit of the expression.
  237. ;;   This is the end of buffer,the  prompt, or an error message.
  238.   (let ((limit (if nlast (match-beginning 0) (point-max))))
  239.   (goto-char gp-input-start)
  240. ;; End of expression is a line ending with } if it starts with {,
  241. ;;   otherwise a line not ending with \.
  242.   (let ((end-expression (if (looking-at " *{") "}$" "[^\\]$")))
  243. ;; Look for the end of expression, as far as the limit computed above.
  244.   (setq gp-complete-expression  (re-search-forward end-expression limit 1))
  245.   (setq gp-input-end (point))
  246. ;; If not already the last expression copy to the end of the buffer.
  247.   (if nlast 
  248.    (progn
  249.      (goto-char (point-max))
  250.      (insert (buffer-substring gp-input-start gp-input-end))
  251.      (if gp-complete-expression
  252.        nil
  253.        (ding)
  254.        (message "Incomplete expression."))))))))
  255.  
  256.  
  257. (defun gp-send-input ()
  258.   "Send input to gp. Does not send incomplete expressions
  259.    ie those starting with {, without a matching }, or those
  260.    ending with \\ .
  261.    Use a temporary file (and \\r )for large expressions"
  262.   (interactive)
  263. ;; gp-copy-input does all the work!
  264.   (gp-copy-input)
  265.   (insert "\n")
  266.   (if gp-complete-expression
  267. ;; If it is a complete expression do this:
  268.     (progn
  269.       (if (> (- gp-input-end gp-input-start) 255)
  270. ;; If large expression, use a temporary file.
  271.         (progn 
  272.           (write-region gp-input-start gp-input-end gp-temp-file)
  273.           (process-send-string gp-process (concat "\\r "gp-temp-file"\n")))
  274. ;; Else use process-send-region.
  275.         (process-send-region gp-process gp-input-start gp-input-end)
  276.         (process-send-string gp-process "\n"))
  277.       (set-marker (process-mark gp-process) (point)))
  278. ;; Else do this:
  279.     (message "Incomplete expression: Not sent to gp.")))
  280.  
  281.  
  282. (defun gp-interrupt ()
  283.   "Interrupt gp.
  284.    This is identical to interrupt-shell-subjob in shell-mode."
  285.   (interactive)
  286.   (interrupt-process nil t))
  287.  
  288. (defun gp-set-prompt (p)
  289.   "Set new gp prompt (and tell emacs that you have done so).
  290.    Do not put spaces in the argument, or emacs and gp will
  291.    have a different idea about what the prompt is."
  292.   (interactive "sNew prompt: ")
  293. ;; gp-prompt-pattern matches:
  294. ;; (New prompt plus any following white space) OR (Old pattern).
  295.   (setq gp-prompt-pattern 
  296.     (concat (regexp-quote p) "[\C-j\t ]*\\|" gp-prompt-pattern))
  297.   (set-buffer "*PARI*")
  298.   (goto-char (point-max))
  299. ;; Tell gp about the change too!
  300.   (insert (concat "\\prompt="p))
  301.   (gp-send-input))
  302.  
  303. (defun gp-replace (a b)
  304.   "Replace the regexp a by the string b everywhere in the current buffer"
  305.   (goto-char (point-min))
  306.   (while (re-search-forward a (point-max) t)
  307.     (replace-match b t t)))
  308.  
  309. (defun gp-get-man-entry (fn)
  310.   "Obtains the description of fn from chapter 3 of the manual.
  311.   Strips off some (not all) of the TeX syntax, and displays the result
  312.   in a new window.
  313.   If there is no entry for fn in the manual, sends ?fn to gp."
  314.   (interactive "sFunction: ")
  315. ;; Stop TeX-mode being loaded for gp-chap3.
  316.   (let ((auto-mode-alist nil))
  317.     (set-buffer (find-file-noselect gp-chap3)))
  318. ;; Fix up one or two special cases, or 
  319. ;; regexp-quote the argument.
  320.   (let ((qfn (cond
  321.            ((equal fn "\\" ) "\\\\backslash")
  322.            ((equal fn "^" ) "\\\\hat{}")
  323.            ((equal fn "!" ) "fact")
  324.            ((equal fn "~" ) "trans") 
  325.            ((equal fn "_" ) "conj")
  326.            ((equal fn "-" ) "\\+")
  327.            ((equal fn "%" ) "\\\\%")
  328.            ((equal fn "min" ) "max")
  329.            ((equal fn "log" ) "ln")
  330.            ((equal fn "det2" ) "det")
  331.            ((or (equal fn "<=" )(equal fn "<" )(equal fn ">=" )
  332.             (equal fn ">" )(equal fn "==" )(equal fn "!=" )
  333.             (equal fn "||" )(equal fn "&&" )) 
  334.                       "comparison and \\\\ref{boolean operators}")
  335.            ((regexp-quote fn)))))
  336. ;; Find the entry.
  337.   (goto-char (point-min))
  338. ;; Entry starts with \subsec ... fn
  339.   (if (re-search-forward 
  340.      (concat "\\(subsec[\\\\{ref]*[\\${]\\)" qfn "[}\\$]") (point-max) t)
  341. ;; If There is an entry in the manual do this:
  342.   (progn
  343.     (goto-char (match-end 1))
  344.     (let ((copy (buffer-substring (point) 
  345. ;; Entry ends with "The library" or the next (sub-)section.
  346.           (progn (re-search-forward "[tT]he library\\|\\\\[sub]*sec" 
  347.                     (point-max) t) 
  348.                  (match-beginning 0))))
  349.           (wind (selected-window)))
  350. ;; Copy the entry to the help buffer.
  351.     (switch-to-buffer-other-window (get-buffer-create "*gp-help*"))
  352.     (erase-buffer)
  353.     (insert copy)
  354. ;; Strip off some of the TeX. Note the idea is to leave enough
  355. ;; pseudo-TeX so that the entry is understandable. Thus want to
  356. ;; leave:  a^2,  x \over y, etc.
  357.     (gp-replace "\\$-" "-")
  358.     (gp-replace "\\$" " " )
  359.     (gp-replace "\\\\backslash" "\\")
  360.     (gp-replace "\\\\hat" "^")
  361.     (gp-replace
  362. "\\\\smallskip\\|\\\\sref{[ a-z]*}\\|\\\\bf\\|\
  363. \\\\ref\\|\\\\Bbb\\|\\\\text\\|\\\\tt\\|{\\|}"
  364.       "")
  365.     (goto-char (point-min))
  366.     (select-window wind)))
  367. ;; Else there is no entry in the manual. So send ?fn to gp.
  368.   (set-buffer "*PARI*")
  369.   (gp-meta-command (concat "?" fn)))))
  370.  
  371. (defun gp-meta-command (command)
  372.   "Send command to gp, and display output in help buffer"
  373.   (goto-char (point-max))
  374.   (let ((temp (point)) (wind (selected-window)))
  375. ;; Send the meta command to gp.
  376.   (process-send-string gp-process (concat command "\n"))
  377. ;; Wait for the gp-prompt to be sent.
  378.   (gp-wait-for-output)
  379. ;; Display the output in the help buffer.
  380.   (let ((copy (buffer-substring temp (point-max))))
  381.   (delete-region temp (point-max))
  382.   (switch-to-buffer-other-window (get-buffer-create "*gp-help*"))
  383.   (erase-buffer)
  384.   (insert copy)
  385.   (beginning-of-line)
  386.   (delete-region (point) (point-max))
  387.  
  388.   (goto-char (point-min))
  389.   (select-window wind))))
  390.  
  391. (defun gp-wait-for-output ()
  392.   "Hang around until the prompt appears."
  393.   (setq ndone t)
  394.   (while ndone 
  395.   (accept-process-output "*PARI*")
  396.   (let ((p (point))) 
  397.     (beginning-of-line)
  398.     (if (looking-at gp-prompt-pattern)
  399.       (progn (message "done") (setq ndone nil))
  400.       (message "Waiting for gp output ..."))
  401.     (goto-char p))))
  402.  
  403. (defun gp-meta-d ()
  404.   "Sends \\d to gp, then displays output in the help buffer.
  405.   Prints the gp defaults."
  406.   (interactive)
  407.   (gp-meta-command "\\d"))
  408.  
  409. (defun gp-meta-t ()
  410.   "Sends \\t to gp, then displays output in the help buffer.
  411.   Prints the longword format of PARI types."
  412.   (interactive)
  413.   (gp-meta-command "\\t"))
  414.  
  415. (defun gp-meta-r (file)
  416.   "Sends a \\r <file name> comand to gp.
  417.    Reads in gp commands from a file.
  418.    See gp-meta-r"
  419.   (interactive "fRead from file: ")
  420.   (goto-char (point-max))
  421.   (insert (concat "\\r " (expand-file-name file)))
  422.   (gp-send-input))
  423.  
  424. (defun gp-meta-w (file num)
  425.   "Sends a \\w<num> <file name> comand to gp.
  426.   Writes gp object %<num> to <file name>."
  427.   (interactive "FWrite to file: \nsObject number %%")
  428.   (goto-char (point-max))
  429.   (insert (concat "\\w"num" " (expand-file-name file)))
  430.   (gp-send-input))
  431.  
  432. (defun gp-meta-x ()
  433.   "Sends \\x to gp, then displays output in the help buffer.
  434.   Prints tree of addresses and contents of last object."
  435.   (interactive)
  436.   (gp-meta-command "\\x"))
  437.  
  438. (defun gp-meta-v ()
  439.   "Sends \\v to gp, then displays output in the help buffer.
  440.   Prints the version number of this implementation of pari-gp."
  441.   (interactive)
  442.   (gp-meta-command "\\v"))
  443.  
  444. (defun gp-meta-s (num)
  445.   "Sends \\s or \\s(num) to gp, then displays output in the help buffer.
  446.   Prints the state of the pari stack."
  447.   (interactive "sNumber of longwords (default 0) ")
  448.   (if (equal num "")
  449.     (gp-meta-command "\\s")
  450.     (gp-meta-command (concat "\\s(" num ")" ))))
  451.  
  452. (defun gp-meta-a (num)
  453.   "Sends \\a or \\a<num> to gp, then displays output in the help buffer.
  454.   Prints object %<num> in raw format."
  455.   (interactive "sPrint object (default last) %%")
  456.   (if (equal num "")
  457.     (gp-meta-command "\\a")
  458.     (gp-meta-command (concat "\\a" num))))
  459.  
  460. (defun gp-meta-b (num)
  461.   "Sends \\b or \\b<num> to gp, then displays output in the help buffer.
  462.   Prints object %<num> in pretty format."
  463.   (interactive "sPrint object (default last) %%")
  464.   (if (equal num "")
  465.     (gp-meta-command "\\b")
  466.     (gp-meta-command (concat "\\b" num))))
  467.  
  468. (defun gp-meta-m (num)
  469.  
  470.   "Sends \\m or \\m<num> to gp, then displays output in the help buffer.
  471.   Prints object %<num> in prettymatrix format."
  472.   (interactive "sPrint object (default last) %%")
  473.   (if (equal num "")
  474.     (gp-meta-command "\\m")
  475.     (gp-meta-command (concat "\\m" num))))
  476.  
  477. (defun gp-meta-k ()
  478.   "Sends \\k to gp.
  479.   Prompts for confirmation before 
  480.   re-initialising gp and clearing the buffer."
  481.   (interactive) 
  482.   (if (y-or-n-p "Re-initialise gp ? ") 
  483.     (progn
  484.       (set-buffer "*PARI*")
  485.       (goto-char (point-max))
  486.       (insert "\\k\n")
  487.       (set-marker (process-mark gp-process) (point))
  488.       (if (y-or-n-p "Clear *PARI* buffer ? ")
  489.          (erase-buffer))
  490.      (process-send-string gp-process "\\k\n")))
  491.   (message ""))
  492.  
  493. (defun gp-meta-q ()
  494.  
  495.   "Sends \\q to gp.
  496.   Prompts for confirmation before quiting."
  497.   (interactive) 
  498.   (if (y-or-n-p "Quit gp ? ") 
  499.     (progn
  500.  
  501.      (set-buffer "*PARI*")
  502.      (goto-char (point-max))
  503.      (process-send-string gp-process "\\q\n")))
  504.   (message ""))
  505.  
  506. (defun gp-break-long-line ()
  507.   "gp will not accept lines longer than 256.
  508.    gp-break-long-line breaks current line 
  509.    inserting \\ every (screen-width)-5 chars."
  510.   (interactive)
  511.   (let ((length (min (- (screen-width) 5) 250)))
  512.   (move-to-column length)
  513.   (while (not (looking-at "$"))
  514.     (insert "\\\n")
  515.     (move-to-column length))))
  516.  
  517.  
  518. ;;; The gp help mode.
  519.  
  520. (defun gp-menu ()
  521.   "Major-mode for the gp menu buffer.
  522. The available commands are
  523. \\{gp-menu-map}"
  524.   (interactive)
  525.   (find-file-other-window gp-menu)
  526.   (setq buffer-read-only t)
  527.   (kill-all-local-variables)
  528.   (setq major-mode 'gp-menu)
  529.   (setq mode-name "GP MENU")
  530.   (use-local-map gp-menu-map)
  531.   (gp-menu-main))
  532.  
  533. (defun gp-menu-info ()
  534.   (message "SPC=next DEL=previous RET=select m=main-menu q=quit s=scroll-help"))
  535.  
  536. (defun gp-menu-next ()
  537.   "Move down one line of the gp help menu. (Go to top if at the end.)"
  538.   (interactive)
  539.   (gp-menu-info)
  540.   (forward-line 1)
  541.   (if (eobp) 
  542.     (progn (ding) (goto-char (point-min)))))
  543.  
  544. (defun gp-menu-previous ()
  545.   "Move up one line of the gp help menu. (Go to bottom if at the top.)"
  546.   (interactive)
  547.   (gp-menu-info)
  548.   (if (bobp) 
  549.     (progn (ding) (goto-char (point-max)) (beginning-of-line)) 
  550.     (forward-line -1)))
  551.  
  552. (defun gp-menu-quit ()
  553.   "Switch the *PARI* buffer if it exists, or (other-buffer) if it does not."
  554.   (interactive)
  555.   (let ((w (get-buffer-window "*PARI*"))
  556.         (b (get-buffer "*PARI*")) )
  557.     (cond
  558.      (w (progn (delete-window)(select-window w)))
  559.      (b (switch-to-buffer b))
  560.      (t (switch-to-buffer (other-buffer))))))
  561.  
  562. (defun gp-menu-select ()
  563.   "Select a subject from the main menu, or a manual entry from a subject menu."
  564.   (interactive)
  565.   (if main-menu 
  566. ;; RET in main menu.
  567.     (progn
  568.       (setq main-menu nil)
  569.       (widen)
  570.       (beginning-of-line)
  571.       (let ((sect (buffer-substring 
  572.            (point) (progn (end-of-line) (point)))))
  573.          (narrow-to-region
  574.            (progn 
  575.              (re-search-forward (concat "^###" sect))
  576.  
  577.              (forward-line 1) (point))
  578.            (progn (re-search-forward "\C-j###" ) (match-beginning 0))))
  579.       (goto-char (point-min)))
  580. ;; RET in subject menu.
  581.     (beginning-of-line)
  582.     (gp-get-man-entry (buffer-substring
  583.       (point)
  584.       (progn (end-of-line) (point)))))
  585.   (gp-menu-info))
  586.  
  587.  
  588.  
  589. (defun gp-menu-main ()
  590.   "Display the main menu."
  591.   (interactive)
  592.   (gp-menu-info)
  593.   (widen)
  594.   (goto-char (point-min))
  595.   (narrow-to-region (point)
  596.     (progn (re-search-forward "\C-j###") (match-beginning 0)))
  597.   (goto-char (point-min))
  598.   (setq done nil)
  599.   (setq main-menu t))
  600.  
  601. (defun gp-menu-scroll ()
  602.   "Scroll the gp help window if it is visible"
  603.   (interactive)
  604.   (gp-menu-info)
  605.   (if (get-buffer-window "*gp-help*") 
  606.     (let ((wind (selected-window)))
  607.       (switch-to-buffer-other-window  "*gp-help*")
  608.       (if (pos-visible-in-window-p (point-max))
  609.          (goto-char (point-min))
  610.          (scroll-up))
  611.       (select-window wind))))
  612.      
  613.  
  614. (defvar gp-menu-map (make-sparse-keymap)
  615.   "Local keymap used in gp menu buffer.")
  616.       
  617.  
  618. (define-key gp-menu-map " "    'gp-menu-next)
  619. (define-key gp-menu-map "\C-?" 'gp-menu-previous)
  620. (define-key gp-menu-map "\C-m" 'gp-menu-select)
  621. (define-key gp-menu-map "q"    'gp-menu-quit)
  622. (define-key gp-menu-map "m"    'gp-menu-main)
  623. (define-key gp-menu-map "s"    'gp-menu-scroll)
  624.  
  625.  
  626.