home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / modes / math / mathtalk.el < prev    next >
Encoding:
Text File  |  1990-01-20  |  24.9 KB  |  968 lines

  1. ;;; Communication with mathematica
  2. ;;; Copyright 1989 Daniel LaLiberte
  3.  
  4. ;;; $Header: /home/srg/1/liberte/math/RCS/mathtalk.el,v 1.2 89/05/25 01:08:50 liberte Exp Locker: liberte $
  5. ;;; $Log:    mathtalk.el,v $
  6. ; Revision 1.2  89/05/25  01:08:50  liberte
  7. ; Fix math 1.2 OUTPROMPTs.
  8. ; Fixup interrupt handling.
  9.  
  10. (provide 'mathtalk)
  11. (require 'math-mode)  ; usually loaded first anyway
  12.  
  13. (defconst math-path "mathremote.emacs"
  14.   "Path to the mathematica program.")
  15.  
  16. (defconst math-version ""
  17.   "String from Mathematica $Version.")
  18.  
  19.  
  20. (defconst math-ESCAPE "!")
  21.  
  22. (defconst math-action-code-base ?\#
  23.   "First character in action code list.")
  24.  
  25. (defconst math-action-codes '
  26.   [aBEEP
  27.    aCOMPLETE
  28.    aDEBUGd
  29.    aDEBUGo
  30.    aDEBUGu
  31.    aDISCARD
  32.    aESCAPE
  33.    aEVAL
  34.    aEVALONLY
  35.    aFORMAT
  36.    aFRONTENDERROR
  37.    aIAMHERE
  38.    aINCOMPLETE
  39.    aINFO
  40.    aINPROMPT
  41.    aINPUTu
  42.    aINPUTFORM
  43.    aINSPECTORd
  44.    aINSPECTORi
  45.    aINSPECTORu
  46.    aINTERRUPTABLE
  47.    aINTERRUPTd
  48.    aINTERRUPTi
  49.    aINTERRUPToi
  50.    aINTERRUPTui
  51.    aMESSAGE
  52.    aOUTPROMPT
  53.    aOUTPUTFORM
  54.    aPRINT
  55.    aRESPOND
  56.    aRESPONSE
  57.    aSENDINT
  58.    aAREYOUTHERE
  59.    aSTART
  60.    aSTATUS
  61.    aSYNTAX
  62.    aTOPLEVELd
  63.    aTOPLEVELi
  64.    aTOPLEVELu
  65.    aPOSTSCRIPT
  66.    aVALUE
  67.    aQUIT
  68.    aINPUTi
  69.    aINPUTd
  70.    aEVALNOIF
  71.    aEVALONOIF
  72.    aNEWLINE
  73.    aSTDERR
  74.    aRESET
  75.    aINTERRUPTu
  76.    ]
  77.   "The list of symbols representing MathTalk Action Codes.
  78. These have values of consecutive ASCII codes starting with
  79. math-action-code-base.")
  80.  
  81.  
  82. (defun math-enum (seq &optional start)
  83.   "Set the values of each symbol in SEQ to respective natural numbers,
  84. 0 to (length SEQ).  Optional START means start at that value instead of 0."
  85.   (let ((i (or start 0))
  86.         (elist (append seq nil))) ; make it a list
  87.     (while elist
  88.       (set (car elist) i)
  89.       (setq elist (cdr elist))
  90.       (setq i (1+ i))
  91.       )))
  92.  
  93.  
  94. ;; Initialize the symbols in math-action-codes to corresponding constant values.
  95. (math-enum math-action-codes math-action-code-base)
  96.  
  97. (defun math-declare-action-takes-data (action-list)
  98.   "Declare that all the actions in ACTION-LIST come with preceeding data."
  99.   (while action-list
  100.     (put (car action-list) 'math-data t)
  101.     (setq action-list (cdr action-list))))
  102.  
  103. (math-declare-action-takes-data
  104.  '(aCOMPLETE aDEBUGo aDISCARD aEVAL aEVALONLY aFORMAT aINCOMPLETE
  105.          aINFO aINPROMPTd aINPUTu aINPUTFORM aINTERRUPToi aMESSAGE
  106.          aOUTPUTPROMPT aOUTPUTFORM aPRINT aRESPONSE aSTATUS aSYNTAX
  107.          aPOSTSCRIPT))
  108.  
  109. (defun math-with-data (action)
  110.   "Return non-nil if ACTION comes with data."
  111.   (get action 'math-data))
  112.  
  113.   
  114.  
  115. (defun math-interpret-action (c)
  116.   "Interpret the character C.  Return the symbol for the action."
  117.   (aref math-action-codes (- c math-action-code-base)))
  118.  
  119. (defvar math-msg-block nil
  120.   "The last message block received.")
  121.  
  122. (defun math-get-block ()
  123.   "Return the block and set it to nil."
  124.   (prog1
  125.       math-msg-block
  126.     (setq math-msg-block nil)))
  127.  
  128.  
  129. (defun math-send-interrupt ()
  130.   "Send an interrupt to the back end."
  131.   (math-send-action 'aSENDINT)
  132.   )
  133.  
  134. (defun math-get-completion (symbol)
  135.   "Get a completion from mathematica for SYMBOL."
  136.   (math-send-string-action symbol 'aINCOMPLETE)
  137.   (math-kernel-loop)
  138.   math-completions
  139.   )
  140.  
  141. (defun math-send-start ()
  142.   "Indicate that we are about to send a block of data to the back end."
  143.   (to-math nil 'aSTART)
  144.   )
  145.  
  146. (defun math-send-data (str)
  147.   "Send the string STR to the back end."
  148.   (to-math str nil)
  149.   )
  150.  
  151. (defun math-send-action (action)
  152.   "Send the ACTION."
  153.   (to-math nil action)
  154.   )
  155.  
  156. (defun math-send-string-action (str action)
  157.   "Send the string STR (preceded by aSTART action)
  158. and then send ACTION."
  159.   (math-send-start)
  160.   (to-math str action)
  161.   )
  162.  
  163.  
  164. (defvar math-permission-to-interrupt nil
  165.   "non-nil if front-end now has permission to interrupt the kernel.
  166. This should be used to inhibit interrupts while handling an interrupt.")
  167.  
  168. (defvar math-current-menu 'top-level
  169.   "indicates which menu we are in at the moment.  Not used.")
  170.  
  171.  
  172. (defun math-initialize ()
  173.   "Initialize the mathematica kernel process."
  174. ; doesnt seem to be used yet
  175. ;  (send-action aRESPOND)
  176.   
  177.     )
  178.  
  179.  
  180. (defun math-kernel-loop ()
  181.   "Loop to handle messages from kernel until done."
  182.  
  183.   ;; clear out previous state
  184.   (setq math-output-form nil
  185.     math-input-form nil
  186.     math-output-prompt nil
  187.     math-Input-response ""
  188.     math-message-blocks nil
  189.     math-info-blocks nil
  190.     math-print-blocks nil
  191.     math-eval-result nil
  192.     math-completions nil
  193.     math-debug-depth 0
  194.     math-quit-count 0)
  195.  
  196.   (math-kernel-inner-loop)
  197.   (message "")
  198.   )
  199.  
  200.  
  201. (defun math-kernel-inner-loop ()
  202.   "Loop until kernel is done."    
  203.   (let ((math-kernel-done nil)
  204.     action)
  205.     (unwind-protect
  206.     (while (not math-kernel-done)
  207.       (setq action (get-math-msg))
  208.       (if (fboundp action)
  209.           (funcall action))
  210.       )
  211.  
  212.       (if (not math-kernel-done)
  213.       (progn
  214.         ;; escaped through top-level; gotta reset Mathematica
  215.         ;; what to do??
  216.         ))
  217.       )))
  218.  
  219.  
  220. (defvar math-error-offset nil
  221.   "For syntax errors, this is the character position of the error.")
  222.  
  223. (defvar math-input-form nil)
  224. (defvar math-output-form nil)
  225.  
  226. (defvar math-Input-response "" "Response to last Input function.")
  227. (defvar math-Input-prompt "" "Prompt for Input function.")
  228. (defvar math-input-prompt nil "The next input cell name.")
  229. (defvar math-output-prompt nil)
  230.  
  231. (defvar math-message-blocks nil
  232.   "List of messages from the last evaluation.")
  233.  
  234. (defvar math-info-blocks nil
  235.   "List of info strings from the last evaluation.")
  236.  
  237. (defvar math-print-blocks nil
  238.   "List of print strings from the last evaluation.")
  239.  
  240. (defvar math-completions nil)
  241. (defvar math-eval-result nil)
  242.  
  243. (defvar math-debug-depth 0
  244.   "Depth of debug inspect recursions.")
  245.  
  246. (defvar math-quit-count 0)
  247.  
  248.  
  249. ;; Functions to handle each type of action
  250.  
  251.   
  252. (defun aBEEP ()
  253.   (message "Error in data.  This should never happen.")
  254.   (ding)
  255.   (sit-for 1))
  256.  
  257. (defun aCOMPLETE ()
  258.   "Here are the completions you asked for. Respond."
  259.   (let ((block (math-get-block)))
  260.     (if (not block)
  261.         (error "missing block")
  262.       (while (string-match "," block)
  263.     (aset block (match-beginning 0) ?\ ))
  264.       (setq math-completions
  265.         (car (read-from-string (concat "[" block "]"))))
  266.       (setq math-kernel-done t)
  267.       )))
  268.  
  269. (defun aDEBUGu ()
  270.   "Please put up the debug menu."
  271.   (if (get-buffer math-message-buffer)
  272.       (save-excursion
  273.     (set-buffer math-message-buffer)
  274.     (if (zerop math-debug-depth)
  275.         (erase-buffer))
  276.     (setq math-debug-depth (1+ math-debug-depth))
  277.     )))
  278.  
  279. (defun aDEBUGd ()
  280.   "Take down the debug menu."
  281.   (setq math-debug-depth (1- math-debug-depth)))
  282.  
  283. (defun math-debug-inspect ()
  284.   "Get input for evaluation.  Return nil if no input entered."
  285.   
  286.   (let ((inspect-input ""))
  287.     (progn
  288.       (setq inspect-input
  289.         (read-string (concat "Inspect>"
  290.                  (make-string math-debug-depth ?>) " ")
  291.              inspect-input))
  292.       (if (zerop (length inspect-input))
  293.       (signal 'quit 'inspect))
  294.       (math-send-string-action inspect-input 'aEVALONOIF)
  295.       )
  296.     ))
  297.  
  298.  
  299. (defun math-debug-menu ()
  300.   "Request action from the user in response to an debug output."
  301.  
  302.   (let (char  ; initially nil
  303.     (inhibit-quit nil)
  304.     (cursor-in-echo-area t)
  305.     )
  306.  
  307.     (condition-case err
  308.     (while (not (memq char '(?i ?s ?n ?c ?f ?a)))
  309.       (if char
  310.           (progn
  311.         (beep)
  312.         (message "Please enter the first letter of a command.")
  313.         (sit-for 1)))
  314.       (message "Debug:  Inspect  Step  Next  Continue  Finish  Abort? ")
  315.       (setq char (read-char))
  316.  
  317.       ;; handle Inspect here
  318.       (if (= ?i char)
  319.           (condition-case err
  320.           (math-debug-inspect)
  321.         (quit ; quit from inspect - get another command
  322.          (setq char nil)
  323.          )))
  324.       )
  325.       (quit (setq char ?a)))  ; quit from debug - same as abort
  326.  
  327.     (message "")
  328.     (cond
  329.      ((= ?s char)
  330.       (message "Step")
  331.       (math-send-string-action "s" 'aRESPONSE))
  332.      ((= ?n char)
  333.       (message "Next")
  334.       (math-send-string-action "n" 'aRESPONSE))
  335.      ((= ?c char)
  336.       (message "Continue")
  337.       (math-send-string-action "c" 'aRESPONSE))
  338.      ((= ?f char)
  339.       (message "Finish")
  340.       (math-send-string-action "f" 'aRESPONSE))
  341.      ((= ?a char)
  342.       (message "Abort")
  343.       (math-send-string-action "a" 'aRESPONSE))
  344.      (t)
  345.      )
  346.     ))
  347.  
  348. (defun aDEBUGo ()
  349.   "Here is an expression for the Debug menu. Respond."
  350.   (let ((block (math-get-block)))
  351.     (if math-output-form
  352.     ;; previous inspect output
  353.     (math-display-msg (concat math-output-form "\n"))
  354.       ;; else not from inspect, so display block
  355.       (math-display-msg (concat block "\n"))))
  356.   (setq math-output-form nil)
  357.   (math-debug-menu)
  358.   )
  359.  
  360. (defun aFRONTENDERROR ()
  361.   "The front-end has sent something inappropriate."
  362.   (error (message "Front end sent something inappropriate.")))
  363.  
  364. (defun aINFO ()
  365.   "Here is the output from an Information command."
  366.   (let ((block (math-get-block)))
  367.     (setq math-info-blocks (cons block math-info-blocks))
  368.     ))
  369.  
  370. (defun aINPROMPT ()
  371.   "Here is the input prompt."
  372.   (let ((block (math-get-block)))
  373.     (setq math-input-prompt block)
  374.     ))
  375.  
  376. (defun aINPUTu ()
  377.   "Here is the prompt for an Input command."
  378.   (let ((block (math-get-block)))
  379.     (setq math-Input-prompt block)
  380.     (setq math-Input-response "")
  381.     ;; keep looping til aINPUTd
  382.     ))
  383.  
  384. (defun aINPUTi ()
  385.   "Please send some input for the Input command.  Respond."
  386.   (if (eq math-eval-result 'syntax-error)
  387.       (let ((cursor-in-echo-area t))
  388.     (beep)
  389.     (message "Syntax error: %s" math-Input-response)
  390.     (save-excursion
  391.       (set-buffer (window-buffer (minibuffer-window)))
  392. ;;      (message "current buffer: %s" (current-buffer))
  393.       (goto-char math-error-offset) ; this doesnt seem to do it!!
  394.       (sit-for 1))))
  395.   (setq math-eval-result nil)
  396.       
  397.   (let ((done nil)
  398.     (inhibit-quit t))
  399.     (unwind-protect
  400.     (while (not done)
  401.       (condition-case err
  402.           (progn
  403.         (setq math-Input-response
  404.               (read-string math-Input-prompt math-Input-response))
  405.         (setq done t))
  406.         (quit
  407.          (beep)
  408.          (message "No interrupts while Inputting.") (sit-for 1)
  409.          )))
  410.       (if (not done)
  411.       (progn  ; escaped through top-level; gotta reset Mathematica
  412.         (math-send-interrupt)
  413.         (math-send-string-action "0" 'aRESPONSE)
  414.         (math-kernel-loop) ; aRESET, aINPUTd
  415.         (get-math-msg) ; aINTERRUPTui
  416.         (math-send-string-action "a" 'aRESPONSE)
  417.         (math-kernel-loop)
  418.         ))
  419.       ))
  420.     
  421.   (math-send-string-action math-Input-response 'aRESPONSE)
  422.   )
  423.  
  424. (defun aINPUTd ()
  425.   "Please take down the Input menu."
  426.   ;; nothing to do since the menu goes away itself
  427.   )
  428.  
  429. (defun aINPUTFORM ()
  430.   "Here is the input form of an expression."
  431.   (let ((block (math-get-block)))
  432.     (setq math-input-form block)
  433.     ))
  434.  
  435. ;; aUSERQUIT not sent to or from mathematica.
  436. ;; Its purpose is to communicate the user quit while waiting for mathematica
  437. ;; to finish its computation.
  438. (defun aUSERQUIT ()
  439.   "User has typed quit-char as interrupt."
  440.   (if math-show-debug
  441.       (to-math-debug "User Quit--------------------\n"))
  442.   (if (get-buffer math-message-buffer)
  443.       (save-excursion
  444.     (set-buffer math-message-buffer)
  445.     (erase-buffer)))
  446.   (math-send-interrupt)
  447.   )
  448.  
  449. (defun aINTERRUPTd ()
  450.   "Take down the interrupt dialog."
  451.   )
  452.  
  453. (defun aINTERRUPTi ()
  454.   "Send an interrupt command."
  455.   )
  456.  
  457.  
  458. (defun math-interrupt-menu ()
  459.   "Request action from the user in response to an interrupt."
  460.  
  461.   ;; reset the number of quit attempts
  462.   (setq math-quit-count 0)
  463.  
  464.   (let (char ; initially nil
  465.     (inhibit-quit nil)
  466.     (cursor-in-echo-area t)
  467.     )
  468.     
  469.     (condition-case err
  470.     (while (not (memq char '(?a ?c ?q ?o)))
  471.       (if char
  472.           (progn
  473.         (beep)
  474.         (message "Please enter a, c, o, or q")
  475.         (sit-for 1)))
  476.       (message "Interrupted:  Abort  Continue  One-step  or  Quit? ")
  477.       (setq char (read-char))
  478.  
  479.       ;; handle Quit here
  480.       (if (and (= ?q char)
  481.            (not (yes-or-no-p
  482.              "Do you really want to quit from Mathematica? ")))
  483.           (setq char nil))
  484.       )
  485.       (quit (setq char ?a)))
  486.  
  487.     (message "")
  488.     (cond
  489.      ((= ?a char)
  490.       (message "Abort")
  491.       (math-send-string-action "a" 'aRESPONSE))
  492.      ((= ?c char)
  493.       (message "Continue")
  494.       (math-send-string-action "c" 'aRESPONSE))
  495.      ((= ?q char)
  496.       (message "Quit")
  497.       (math-send-string-action "quit" 'aRESPONSE)
  498.       (setq math-kernel-done t))
  499.      ((= ?o char)
  500.       (message "One-step")
  501.       (math-send-string-action "o" 'aRESPONSE))
  502.      (t ; should never happen
  503.       (math-send-string-action "a" 'aRESPONSE))
  504.      )
  505.     ))
  506.  
  507. (defun aINTERRUPToi ()
  508.   "Here is something to display in the interrupt dialog.  Respond."
  509.   (let ((block (math-get-block)))
  510.     (math-display-msg block))
  511.   (math-interrupt-menu)
  512.   )
  513.  
  514. (defun aINTERRUPTui ()
  515.   "Put up the interrupt dialog."
  516.   (math-interrupt-menu)
  517.   )
  518.  
  519. (defun aMESSAGE ()
  520.   "Here is a message."
  521.   (let ((block (math-get-block)))
  522.     (setq math-message-blocks (cons block math-message-blocks))
  523.     ))
  524.  
  525. (defun aOUTPROMPT ()
  526.   "Here is the output prompt."
  527.   (let ((block (math-get-block)))
  528.     (setq math-output-prompt 
  529.       (if (string-match "[^=]$" block)
  530.           (concat block "=")
  531.         block))
  532.     ))
  533.  
  534. (defun aOUTPUTFORM ()
  535.   "Here is the output form of an expression."
  536.   (let ((block (math-get-block)))
  537.     (setq math-output-form block)
  538.     ))
  539.  
  540. (defun aPRINT ()
  541.   "Here is some print output from the evaluation."
  542.   (let ((block (math-get-block)))
  543.     (setq math-print-blocks (cons block math-print-blocks))
  544.     ))
  545.  
  546. (defun aPOSTSCRIPT ()
  547.   "Here is some postscript output."
  548.   (let ((block (math-get-block)))
  549.     ;; ignore it for now
  550.     ))
  551.  
  552. (defun aSYNTAX ()
  553.   "Here is the column number in which a syntax error occurred."
  554.   (let ((block (math-get-block)))
  555.     (setq math-eval-result 'syntax-error)
  556.     (setq math-error-offset (string-to-int block))
  557.     ))
  558.  
  559. (defun aTOPLEVELi ()
  560.   "Please send me some top level input.  Respond."
  561.   (setq math-kernel-done t)
  562.   )
  563.  
  564. (defun aVALUE ()
  565.   "Please display the previous input/output forms as a value."
  566.   (let ((block (math-get-block)))
  567.     (setq math-eval-result 'value)
  568.     ))
  569.  
  570.  
  571.  
  572. (defun wait-for-math (math-buffer-size)
  573.   "Wait for math to send more stuff - when the buffer size grows."
  574.   (while (= math-buffer-size (buffer-size))
  575.     (if (not (eq (process-status math-process) 'run))
  576.     (progn
  577.       (math-error "Math process is jammed with status %s"
  578.               (process-status math-process))
  579.       (error "Mathematica is not running.")))
  580.     
  581.     ;;    (sit-for 1)  ; this works but takes at least one second
  582.     (let ((inhibit-quit nil))        ; allow quit
  583.       (message "Waiting for Mathematica output...")
  584.       ;; needs a time limit to prevent indefinite wait.
  585.       (accept-process-output math-process)
  586.       (message "")            ; clear message
  587.       (sit-for 0)
  588.       )))
  589.  
  590.  
  591. (defun math-read-atom-safely ()
  592.   "Read one atom from current buffer, delete the atom
  593. and return it or return nil if not readable.
  594. Thus, we cannot distinguish a nil atom with this."
  595.   (let (size atom endpt)
  596.     (while (not 
  597.         (condition-case err
  598.         (progn
  599.           (goto-char (point-min))
  600.           (setq size (buffer-size))  ; remember the size before reading
  601.           (setq atom
  602.             (read (buffer-substring
  603.                    (point)
  604.                    (setq endpt
  605.                      (scan-sexps (point) 1)))))
  606.           ;; delete what we read
  607.           (delete-region (point) endpt)
  608.           t  ; quit the loop
  609.           )
  610.           
  611.           (error
  612. ;;           (message "not all in yet, wait for more.")
  613.            (condition-case err
  614.            (progn 
  615.              (wait-for-math size)
  616.              nil)            ; if unreadable, return nil
  617.  
  618.          (quit  ; catch quit so we can recover
  619.           (message "Interrupt") (sit-for 0)
  620.  
  621.           ;; increment the number of quit attempts made
  622.           ;; since the last time mathematica responded.
  623.           (setq math-quit-count (1+ math-quit-count))
  624.           (if (> math-quit-count 1)
  625.               (if (yes-or-no-p "Kill Mathematica process? ")
  626.               (progn
  627.                 (setq quit-flag t) ; let's get out of this loop
  628.                 ;; setting the quit-flag may do nothing
  629.                 (kill-math t)
  630.                 (error "Evaluation not completed.")))
  631.             
  632.             (setq quit-flag nil)
  633.             (setq atom 'aUSERQUIT)  ; quit the loop and do aUSERQUIT
  634.             ))
  635.          )))))
  636.  
  637.     (if math-show-debug
  638.     (to-math-debug (format "From math: %s\n" atom)))
  639.  
  640.     atom  ; return the atom
  641.     ))
  642.   
  643.  
  644. (defun get-math-msg ()
  645.   "Get a message from the top of the math-filter-queue
  646. for the current buffer's math-process.
  647. Return a command, when it is completed.
  648. Set math-msg-block to any data received before that."
  649.  
  650.   (let ((save-buffer (current-buffer))
  651.     atom)
  652.     
  653.     (save-excursion
  654.       (set-buffer math-buffer)
  655.       (setq atom (math-read-atom-safely))
  656.       (if (stringp atom)
  657.       (progn
  658.         (setq math-msg-block atom)
  659.         ;; read again, it must be an action this time
  660.         (setq atom (math-read-atom-safely))
  661.         ))
  662.       (set-buffer save-buffer)
  663.       atom ; result
  664.       )))
  665.  
  666.  
  667. ;;;-------------------
  668. ;;; Display stuff
  669.  
  670. (defconst math-message-buffer "*math-message*"
  671.   "Buffer to display messages from mathematica that dont go in the notebook.")
  672.  
  673.  
  674. (defun math-display-msg (msg)
  675.   "Display msg in a temporary buffer."
  676.   (let* ((save-buf (current-buffer))
  677.     (buf (get-buffer-create math-message-buffer)))
  678.     (pop-to-buffer buf)
  679.     (goto-char (point-max))
  680.     (insert msg)
  681.     (if (not (pos-visible-in-window-p))
  682.     (scroll-down (/ (window-height) 2)))
  683.     (pop-to-buffer save-buf)
  684.     ))
  685.  
  686. (defun display-math-buffer (msg &optional fill delete)
  687.   "Display msg in a temporary buffer and optionally paragraph fill
  688.      and delete window after next input.  The window size is shrunk
  689. to just hold the text."
  690.   (let
  691.       ((obuf (current-buffer))
  692.        (owin (selected-window))
  693.        (oheight (window-height))
  694.        start-pnt
  695.        (buf "junk")
  696.        )
  697.     (if (< 0 (length msg))
  698.         (progn
  699.       (set-buffer (get-buffer-create buf))
  700.  
  701.           (goto-char (point-max))
  702.           (insert-string "\n")
  703.           (setq start-pnt (point))
  704.           (insert msg)
  705.           (narrow-to-region start-pnt (point))
  706.  
  707.           (if fill
  708.               (progn
  709.                 (fill-region-as-paragraph start-pnt (point))
  710.                 (if (< 1 (length msg))
  711.                     (progn
  712.                       (skip-chars-backward " \t\n\f")
  713.                       (delete-region (point) (point-max))
  714.                       ))))
  715.  
  716.           (let* ((win-config (current-window-configuration))
  717.                  (win (get-buffer-window (current-buffer)))
  718.                  (lines-needed (max (min (count-lines start-pnt (point-max))
  719.                                          (/ (window-height) 2) ) ; at most half
  720.                                     2) ; at least two lines - one has problems
  721.                                ))
  722.             ;;  (display-buffer (current-buffer))
  723.             (if win
  724.                 (progn
  725.                   (select-window win)
  726.                   (enlarge-window (1+ (- lines-needed (window-height))))
  727.                   )
  728.               (split-window owin (1- (- (window-height owin) lines-needed)))
  729.               (other-window 1)          ; the new window
  730.               (setq win (selected-window))
  731.               (set-window-buffer (selected-window) math-buffer)
  732.               )
  733.  
  734.             (set-window-start win start-pnt t)
  735.             (goto-char start-pnt)       ; one of these ought to do it
  736.  
  737.             (set-buffer obuf)
  738.             (if (not (eq owin (selected-window)))
  739.                 (if owin (select-window owin))
  740.               )
  741.             (update-display)
  742.             ;; wait for user input - then delete the window
  743.             (if delete
  744.                 (progn
  745.                   (while (not (input-pending-p))
  746.                     (sit-for 2))
  747.                   ;; (select-window win)
  748.                   ;; (delete-window)
  749.                   (bury-buffer buf)
  750.                   (set-window-configuration win-config)
  751.                   )))
  752.           )
  753.  
  754.       ))
  755.   )
  756.  
  757.  
  758. ;--------------------------------------------------------------
  759. ; Send a message to Math.
  760.  
  761. (defun to-math (msg action)
  762.   "Send message MSG to math process followed by ACTION."
  763.  
  764.   (if (and (not math-mode) (not (eq action 'aQUIT)))  ; aQUIT??
  765.       (error "Buffer %s is not in Math mode." (current-buffer)))
  766.  
  767.   (if math-show-debug
  768.       (to-math-debug (format "To-math: \"%s\" %s\n" msg action)))
  769.   (if (not math-process)
  770.       (run-math))
  771.  
  772.   (let ((msg-packet
  773.      (concat ; message and action
  774.       (if msg
  775.           (let ((match-start 0)  ; change any math-ESCAPE chars in msg
  776.             (match-data (match-data)))
  777.         (while (string-match math-ESCAPE msg match-start)
  778.           (let ((where (match-beginning 0)))
  779.             ;; replace math-ESCAPE char
  780.             (setq msg (concat (substring msg 0 where)
  781.                       math-ESCAPE (char-to-string aESCAPE)
  782.                       (substring msg (1+ where))))
  783.             (setq match-start (1+ (match-end 0)))
  784.             ))
  785.         (store-match-data match-data) ; restore
  786.         msg)
  787.         )
  788.  
  789.       (if action
  790.           (concat 
  791.            math-ESCAPE
  792.            (char-to-string (symbol-value action)))
  793.         "")
  794.             "\n")
  795.      ))
  796.     
  797. ;;    (if math-show-debug
  798. ;;    (to-math-debug (format "  #send: \"%s\"\n" msg-packet)))
  799.     (send-string math-process msg-packet)
  800.     msg-packet
  801.     )
  802.   ) ; to-math
  803.  
  804. ;-------------------------------------------
  805.  
  806.  
  807.  
  808. ;================================================================
  809. ;; Run math as inferior of Emacs.
  810. ;; This code is derived from compile.el.
  811.  
  812. (defconst math-buffer " *mathematica*"
  813.   "The name of the buffer in which mathematica output is first put.")
  814.  
  815. (defvar math-process nil
  816.   "Process created by math command, or nil if none exists now.
  817. Note that the process may have been \"deleted\" and still
  818. be the value of this variable.")
  819.  
  820.  
  821.  
  822. (defun run-math ()
  823.   "Run and initialize Mathematica, if it is not already active."
  824.   (if (setup-math-process)
  825.       ;; first time, so initialize things
  826.       (progn
  827. ;;    (math-send-string-action "<< init.m" 'aEVALONLY)
  828. ;;    (math-kernel-loop)
  829.  
  830.     (let ((math-input-prompt nil))  ; save first prompt
  831.       (math-send-string-action "$Version" 'aEVALNOIF)
  832.       (math-kernel-loop)
  833.       (setq math-version math-output-form)
  834.       (math-send-string-action "$Line--" 'aEVALONLY);; decrement prompt
  835.       (math-kernel-loop)
  836.       ))
  837.     )
  838.  
  839.   (message "Mathematica is running")
  840.   (setq math-last-window-width 0)
  841.   (math-reset-pagewidth)
  842.   )
  843.  
  844.  
  845. (defvar math-last-window-width (window-width))
  846.  
  847. (defun math-reset-pagewidth ()
  848.   "If window-width has changed, send resize to mathematica."
  849.   (if (/= (window-width) math-last-window-width)
  850.       (progn
  851.     (math-send-string-action
  852.      (concat "ResetMedium[PageWidth -> "
  853.          (- (window-width) (length math-input-prompt) 8)
  854.          "]")
  855.      'aEVALONLY)
  856.     (math-kernel-loop)
  857.     ))
  858.   (setq math-last-window-width (window-width))
  859.   )
  860.  
  861.  
  862. (defun setup-math-process ()
  863. "Set up math in a separate process asynchronously
  864. with output going to the math-buffer asynchronously.
  865. Return nil if the process is already active."
  866.  
  867. ;;  (save-some-buffers)
  868.  
  869.   (if (and math-process
  870.        (not (eq (process-status math-process) 'run)))
  871.       ;; delete any bad math process
  872.       (condition-case err
  873.       (progn
  874.         (delete-process math-process)
  875.         (setq math-process nil))
  876.     (error nil)))
  877.  
  878.   (if (not math-process)
  879.       (progn
  880.     (setq math-process
  881.           (let ((process-connection-type nil))
  882.         (start-process "math"
  883.                    math-buffer
  884.                    math-path)))
  885. ;;    (message "Math status: %s" (process-status math-process))
  886.     (if (not (eq 'run (process-status math-process)))
  887.         (progn
  888.           (setq math-process nil)
  889.           (error (message "Can't execute Mathematica in %s" math-path))))
  890.  
  891.     (process-kill-without-query math-process)
  892.     (message "Mathematica process started")
  893.     (set-process-sentinel math-process 'math-sentinel)
  894.   
  895.     (let* ((thisdir default-directory)
  896.            (buf math-buffer)
  897.            (outwin (get-buffer-window buf)))
  898.     
  899.       (if (eq math-buffer (current-buffer))
  900.           (goto-char (point-max)))
  901.       (save-excursion
  902.         (set-buffer buf)
  903.         (erase-buffer)
  904.         (buffer-flush-undo (get-buffer buf))
  905. ;;        (let ((start (save-excursion (set-buffer buf) (point-min))))
  906. ;;          (set-window-start outwin start)
  907. ;;          (or (eq outwin (selected-window))
  908. ;;          (set-window-point outwin start)))
  909.         (setq default-directory thisdir)
  910.  
  911.         (fundamental-mode)
  912.         (setq mode-name "Math")
  913.         ;; Make log buffer's mode line show process state
  914.         (setq mode-line-format
  915.           "--%1*%1*-Emacs: %17b   %   %[(%m: %s)%]----%3p--%-")))
  916.     (math-kernel-loop)        ; read the first message
  917.     math-process
  918.     )
  919.     nil  ; return nil
  920.     ))
  921.  
  922.  
  923. ;; Called when math process changes state.
  924. (defun math-sentinel (proc msg)
  925.   (if (memq (process-status proc) '(signal exit))
  926.       (let* ((obuf (current-buffer))
  927. ;            (omax (point-max))
  928. ;            (opoint (point))
  929.              )
  930.         (unwind-protect
  931.             (progn
  932.               (set-buffer (get-buffer-create "*math-debug*"))
  933.               (goto-char (point-max))
  934.               (insert ?\n  "Mathematica: " msg)
  935.               (setq mode-line-format
  936.                     (concat
  937.                      "--%1*%1*-Emacs: %17b   %M   %[(%m: "
  938.                      (symbol-name (process-status proc))
  939.                      ")%]----%3p--%-"))
  940.               (delete-process proc)
  941.               (setq math-process nil)
  942.               ;; Force mode line redisplay soon
  943.               (set-buffer-modified-p (buffer-modified-p)))
  944. ;        (if (< opoint omax)
  945. ;            (goto-char opoint))
  946.          (set-buffer obuf)))
  947.   )
  948.   )
  949.  
  950.  
  951. (defun kill-math (&optional arg)
  952.   "Kill the mathematica process.  Only used in exceptional circumstances."
  953.   (interactive)
  954.   (if math-process
  955.       (if (or arg
  956.           (yes-or-no-p "Kill the current Mathematica process? "))
  957.       (progn
  958.         (message "Killing Mathematica...")
  959.         (kill-process math-process)
  960.         (setq math-process nil)
  961.         (setq math-input-prompt nil)
  962.         (message "")
  963.         ))
  964.     (message "Mathematica is not active.")
  965.     ))
  966.  
  967.