source: git/emacs/singular.el @ 2135c8a

spielwiese
Last change on this file since 2135c8a was 2135c8a, checked in by Jens Schmidt <schmidt@…>, 26 years ago
* singular.el (singular-strip-prompts-filter): new function. Added to `comint-output-filter-functions'. * singular.el (singular-debug): doc fix * singular.el (singular-process): new macro (singular-remove-prompt): doc fix (singular-fold-section): doc fix git-svn-id: file:///usr/local/Singular/svn/trunk@2411 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 54.1 KB
Line 
1;;; singular.el --- Emacs support for Computer Algebra System Singular
2
3;; $Id: singular.el,v 1.15 1998-07-31 08:18:30 schmidt Exp $
4
5;;; Commentary:
6
7
8;;; Code:
9
10;;{{{ Style and coding conventions
11
12;; Style and coding conventions:
13;;
14;; - "Singular" is written with an upper-case `S' in comments, doc
15;;   strings, and messages.  As part of symbols, it is written with
16;;   a lower-case `s'.
17;; - use a `fill-column' of 70 for doc strings and comments
18;; - use foldings to structure the source code but try not to exceed a
19;;   maximal depth of two folding (one folding in another folding which is
20;;   on top-level)
21;; - use lowercase folding titles except for first word
22;; - folding-marks are `;;{{{' and `;;}}}' resp., for sake of standard
23;;   conformity
24;; - mark incomplete doc strings or code with `NOT READY' (optionally
25;;   followed by an explanation what exactly is missing)
26;; - documentation on the customization of the modes is in the
27;;   doc-strings to `singular-mode-configuration' and
28;;   `singular-interactive-mode-configuration', resp.
29;;
30;; - use `singular' as prefix for all global symbols
31;; - use `singular-debug' as prefix for all global symbols concerning
32;;   debugging.
33;;
34;; - mark dependencies on Emacs flavor/version with a comment of the form
35;;   `;; Emacs[ <version>]'     resp.
36;;   `;; XEmacs[ <version>][ <nasty comment>]' (in that order, if
37;;   possible)
38;; - use a `cond' statement to execute Emacs flavor/version-dependent code,
39;;   not `if'.  This is to make such checks more extensible.
40;; - try to define different functions for different flavors/version
41;;   and use `singular-fset' at library-loading time to set the function
42;;   you really need.  If the function is named `singular-<basename>', the
43;;   flavor/version-dependent functions should be named
44;;   `singular-<flavor>[-<version>]-<basename>'.
45
46;; - use `singular-debug' for debugging output/actions
47;; - to switch between buffer and process names, use the functions
48;;   `singular-process-name-to-buffer-name' and
49;;   `singular-buffer-name-to-process-name'
50;; - we assume that the buffer is *not* read-only
51
52;;}}}
53
54(require 'comint)
55
56;;{{{ Code common to both modes
57;;{{{ Debugging stuff
58(defvar singular-debug nil
59  "*List of modes to debug or t to debug all modes.
60Currently, there are the modes `interactive', `interactive-filter',
61`interactive-simple-secs', and `interactive-sections'.")
62
63(defun singular-debug-format (string)
64  "Return STRING in a nicer format."
65  (save-match-data
66    (while (string-match "\n" string)
67      (setq string (replace-match "^J" nil nil string)))
68
69    (if (> (length string) 16)
70        (concat "<" (substring string 0 7) ">...<" (substring string -8) ">")
71      (concat "<" string ">"))))
72
73(defmacro singular-debug (mode form &optional else-form)
74  "Major debugging hook for singular.el.
75Evaluates FORM if `singular-debug' equals `all' or if MODE is an
76element of `singular-debug', othwerwise ELSE-FORM"
77  `(if (or (eq singular-debug 'all)
78           (memq ,mode singular-debug))
79       ,form
80     ,else-form))
81;;}}}
82
83;;{{{ Determining version
84(defvar singular-emacs-flavor nil
85  "A symbol describing the current Emacs.
86Currently, only Emacs \(`emacs') and XEmacs are supported \(`xemacs').")
87
88(defvar singular-emacs-major-version nil
89  "An integer describing the major version of the current emacs.")
90
91(defvar singular-emacs-minor-version nil
92  "An integer describing the major version of the current emacs.")
93
94(defun singular-fset (real-function emacs-function xemacs-function
95                                    &optional emacs-19-function)
96  "Set REAL-FUNCTION to one of the functions, in dependency on Emacs flavor and version.
97Sets REAL-FUNCTION to XEMACS-FUNCTION if `singular-emacs-flavor' is
98`xemacs'.  Sets REAL-FUNCTION to EMACS-FUNCTION if `singular-emacs-flavor'
99is `emacs' and `singular-emacs-major-version' is 20.  Otherwise, sets
100REAL-FUNCTION to EMACS-19-FUNCTION which defaults to EMACS-FUNCTION.
101
102This is not as common as would be desirable.  But it is sufficient so far."
103  (cond
104   ;; XEmacs
105   ((eq singular-emacs-flavor 'xemacs)
106    (fset real-function xemacs-function))
107   ;; Emacs 20
108   ((eq singular-emacs-major-version 20)
109    (fset real-function emacs-function))
110   ;; Emacs 19
111   (t
112    (fset real-function (or emacs-19-function emacs-function)))))
113
114(defun singular-set-version ()
115  "Determine flavor, major version, and minor version of current emacs.
116singular.el is guaranteed to run on Emacs 19.34, Emacs 20.2, and XEmacs
11720.2.  It should run on newer version and on slightly older ones, too."
118
119  ;; get major and minor versions first
120  (if (and (boundp 'emacs-major-version)
121           (boundp 'emacs-minor-version))
122      (setq singular-emacs-major-version emacs-major-version
123            singular-emacs-minor-version emacs-minor-version)
124    (with-output-to-temp-buffer "*singular warnings*"
125      (princ
126"You seem to have quite an old Emacs or XEmacs version.  Some of the
127features from singular.el will not work properly.  Consider upgrading to a
128more recent version of Emacs or XEmacs.  singular.el is guaranteed to run
129on Emacs 19.34, Emacs 20.2, and XEmacs 20.2."))
130    ;; assume the oldest version we support
131    (setq singular-emacs-major-version 19
132          singular-emacs-minor-version 34))
133
134  ;; get flavor
135  (if (string-match "XEmacs\\|Lucid" emacs-version)
136      (setq singular-emacs-flavor 'xemacs)
137    (setq singular-emacs-flavor 'emacs)))
138
139(singular-set-version)
140;;}}}
141
142;;{{{ Faces
143
144;; Note:
145;;
146;; These fonts look quite good:
147;; "-adobe-courier-bold-r-*-*-18-*-*-*-*-*-*-*" for input
148;; "-adobe-courier-bold-o-*-*-18-*-*-*-*-*-*-*" for output
149;;
150;; For my (Jens) Emacs a quite good variant is:
151;; "-misc-fixed-bold-*-*-*-15-*-*-*-*-*-*-*" for input
152;; "-misc-fixed-medium-*-*-*-15-*-*-*-*-*-*-*" for output
153
154(make-face 'singular-input-face)
155(set-face-background 'singular-input-face "Orange")
156(defvar singular-input-face 'singular-input-face
157  "Face for user input.
158This face should have set background only.")
159
160(make-face 'singular-output-face)
161;(set-face-font 'singular-output-face "-adobe-courier-bold-o-*-*-18-*-*-*-*-*-*-*")
162(set-face-background 'singular-output-face "Wheat")
163(defvar singular-output-face 'singular-output-face
164  "Face for Singular output.
165This face should have set background only.")
166
167(defun singular-lookup-face (face-type)
168  "Return face belonging to FACE-TYPE.
169NOT READY [should be rewritten completely.  Interface should stay the same.]!"
170  (cond ((eq face-type 'input) singular-input-face)
171        ((eq face-type 'output) singular-output-face)))
172;;}}}
173;;}}}
174
175;;{{{ Singular interactive mode
176;;{{{ Key map
177(defvar singular-interactive-mode-map ()
178  "Key map to use in Singular interactive mode.")
179
180(if singular-interactive-mode-map
181    ()
182  (cond
183   ;; Emacs
184   ((eq singular-emacs-flavor 'emacs)
185    (setq singular-interactive-mode-map
186          (nconc (make-sparse-keymap) comint-mode-map)))
187   ;; XEmacs
188   (t
189    (setq singular-interactive-mode-map (make-keymap))
190    (set-keymap-parents singular-interactive-mode-map (list comint-mode-map))
191    (set-keymap-name singular-interactive-mode-map
192                     'singular-interactive-mode-map)))
193  (define-key singular-interactive-mode-map "\C-m" 'singular-send-or-copy-input))
194;;}}}
195
196;;{{{ Miscellaneous
197
198;; Note:
199;;
200;; We assume a one-to-one correspondance between Singular buffers
201;; and Singular processes.  We always have
202;; (equal buffer-name (concat "*" process-name "*")).
203
204(defun singular-buffer-name-to-process-name (buffer-name)
205  "Create the process name for BUFFER-NAME.
206The process name is the buffer name with surrounding `*' stripped
207off."
208  (substring buffer-name 1 -1))
209
210(defun singular-process-name-to-buffer-name (process-name)
211  "Create the buffer name for PROCESS-NAME.
212The buffer name is the process name with surrounding `*'."
213  (concat "*" process-name "*"))
214
215(defmacro singular-process ()
216  "Return process of current buffer."
217  (get-buffer-process (current-buffer)))
218
219(defmacro singular-process-mark ()
220  "Return process mark of current buffer."
221  (process-mark (get-buffer-process (current-buffer))))
222;;}}}
223
224;;{{{ Customizing variables of comint
225
226;; Note:
227;;
228;; In contrast to the variables from comint.el, all the variables
229;; below are global variables.  It would not make any sense to make
230;; them buffer-local since
231;; o they are read only when Singular interactive mode comes up;
232;; o since they are Singular-dependent and not user-dependent, i.e.,
233;;   the user would not mind to change them.
234;;
235;; For the same reasons these variables are not marked as
236;; "customizable" by a leading `*'.
237
238(defvar singular-prompt-regexp "^> "
239  "Regexp to match prompt patterns in Singular.
240Should not match the continuation prompt \(`.'), only the regular
241prompt \(`>').
242
243This variable is used to initialize `comint-prompt-regexp' when
244Singular interactive mode starts up.")
245
246(defvar singular-delimiter-argument-list '(?= ?\( ?\) ?, ?;)
247  "List of characters to recognize as separate arguments.
248
249This variable is used to initialize `comint-delimiter-argument-list'
250when Singular interactive mode starts up.")
251
252(defvar singular-input-ignoredups t
253  "If non-nil, don't add input matching the last on the input ring.
254
255This variable is used to initialize `comint-input-ignoredups' when
256Singular interactive mode starts up.")
257
258(defvar singular-buffer-maximum-size 2048
259  "The maximum size in lines for Singular buffers.
260
261This variable is used to initialize `comint-buffer-maximum-size' when
262Singular interactive mode starts up.")
263
264(defvar singular-input-ring-size 64
265  "Size of input history ring.
266
267This variable is used to initialize `comint-input-ring-size' when
268Singular interactive mode starts up.")
269
270(defvar singular-history-filter-regexp "\\`\\(..?\\|\\s *\\)\\'"
271  "Regular expression to filter strings *not* to insert in the history.
272By default, input consisting of less than three characters and input
273consisting of white-space only is not added to the history.")
274
275(defvar singular-history-filter
276  (function (lambda (string)
277              (not (string-match singular-history-filter-regexp string))))
278  "Predicate for filtering additions to input history.
279
280This variable is used to initialize `comint-input-filter' when
281Singular interactive mode starts up.")
282;;}}}
283
284;;{{{ Skipping and stripping prompts and newlines and other things
285
286;; Note:
287;;
288;; All of these functions modify the match data!
289
290(defun singular-strip-white-space (string &optional trailing leading)
291  "Strip off trailing or leading white-space from STRING.
292Strips off trailing white-space if optional argument TRAILING is
293non-nil.
294Strips off leading white-space if optional argument LEADING is
295non-nil."
296  (let ((beg 0)
297        (end (length string)))
298    (and leading
299         (string-match "\\`\\s-*" string)
300         (setq beg (match-end 0)))
301    (and trailing
302         (string-match "\\s-*\\'" string beg)
303         (setq end (match-beginning 0)))
304    (substring string beg end)))
305
306(defconst singular-extended-prompt-regexp "\\([>.] \\)"
307  "Matches one Singular prompt.
308Should not be anchored neither to start nor to end!")
309
310(defconst singular-strip-leading-prompt-regexp
311  (concat "\\`" singular-extended-prompt-regexp "+")
312  "Matches Singular prompt anchored to string start.")
313
314(defun singular-strip-leading-prompt (string)
315  "Strip leading prompts from STRING.
316May or may not return STRING or a modified copy of it."
317  (if (string-match singular-strip-leading-prompt-regexp string)
318      (substring string (match-end 0))
319    string))
320
321(defconst singular-remove-prompt-regexp
322  (concat "^" singular-extended-prompt-regexp
323          "*" singular-extended-prompt-regexp)
324  "Matches a non-empty sequence of prompts at start of a line.")
325
326(defun singular-remove-prompt (beg end)
327  "Remove all superfluous prompts from region between BEG and END.
328More precisely, removes prompts from first beginning of line before
329BEG to END.
330Removes all but the last prompt of a sequence if that sequence ends at
331END.
332The region between BEG and END should be accessible."
333  (save-excursion
334    (let ((end (copy-marker end))
335          prompt-end)
336      (goto-char beg)
337      (beginning-of-line)
338      (while (and (setq prompt-end
339                        (re-search-forward singular-remove-prompt-regexp end t))
340                  (not (= end prompt-end)))
341        (delete-region (match-beginning 0) prompt-end))
342
343      ;; check for trailing prompt
344      (if prompt-end
345          (delete-region (match-beginning 0)  (match-beginning 2)))
346      (set-marker end nil))))
347
348(defconst singular-skip-prompt-forward-regexp
349  (concat singular-extended-prompt-regexp "*")
350  "Matches an arbitary sequence of Singular prompts.")
351
352(defun singular-skip-prompt-forward ()
353  "Skip forward over prompts."
354  (looking-at singular-skip-prompt-forward-regexp)
355  (goto-char (match-end 0)))
356;;}}}
357
358;;{{{ Simple section stuff for both Emacs and XEmacs
359
360;; Note:
361;;
362;; Sections and simple sections are used to mark Singular's input and
363;; output for further access.  Here are some general notes on simple
364;; sections.  Sections are explained in the respective folding.
365;;
366;; In general, simple sections are more or less Emacs' overlays or XEmacs
367;; extents, resp.  But they are more than simply an interface to overlays
368;; or sections.
369;;
370;; - Simple sections are non-empty portions of text.  They are interpreted
371;;   as left-closed, right-opened intervals, i.e., the start point of a
372;;   simple sections belongs to it whereas the end point does not.
373;; - Simple sections start and end at line borders only.
374;; - Simple sections do not overlap.  Thus, any point in the buffer may be
375;;   covered by at most one simple section.
376;; - Besides from their start and their end, simple sections have some type
377;;   associated.
378;; - Simple sections are realized using overlays (extents for XEmacs)
379;;   which define the start and, end, and type (via properties) of the
380;;   simple section.  Actually, as a lisp object a simple section is
381;;   nothing else but the underlying overlay.
382;; - There may be so-called clear simple sections.  Clear simple sections
383;;   have not an underlying overlay.  Instead, they start at the end of the
384;;   preceding non-clear simple section, end at the beginning of the next
385;;   non-clear simple section, and have the type defined by
386;;   `singular-simple-sec-clear-type'.  Clear simple sections are
387;;   represented by nil.
388;; - Buffer narrowing does not restrict the extent of completely or
389;;   partially inaccessible simple sections.  But one should note that
390;;   some of the functions assume that there is no narrowing in
391;;   effect.
392;; - After creation, simple sections are not modified any further.
393;;
394;; - In `singular-interactive-mode', the whole buffer is covered with
395;;   simple sections from the very beginning of the file up to the
396;;   beginning of the line containing the last input or output.  The
397;;   remaining text up to `(point-max)' may be interpreted as covered by
398;;   one clear simple section.  Thus, it is most reasonable to define
399;;   `input' to be the type of clear simple sections.
400
401(defvar singular-simple-sec-clear-type 'input
402  "Type of clear simple sections.
403If nil no clear simple sections are used.")
404
405(defvar singular-simple-sec-last-end nil
406  "Marker at the end of the last simple section.
407Should be initialized by `singular-simple-sec-init' before any calls to
408`singular-simple-sec-create' are done.
409
410This variable is buffer-local.")
411
412(defun singular-simple-sec-init (pos)
413  "Initialize global variables belonging to simple section management.
414Creates the buffer-local marker `singular-simple-sec-last-end' and
415initializes it to POS."
416  (make-local-variable 'singular-simple-sec-last-end)
417  (if (not (and (boundp 'singular-simple-sec-last-end)
418                singular-simple-sec-last-end))
419      (setq singular-simple-sec-last-end (make-marker)))
420  (set-marker singular-simple-sec-last-end pos))
421
422;; Note:
423;;
424;; The rest of the folding is either marked as
425;; Emacs
426;; or
427;; XEmacs
428
429(singular-fset 'singular-simple-sec-create
430               'singular-emacs-simple-sec-create
431               'singular-xemacs-simple-sec-create)
432
433(singular-fset 'singular-simple-sec-reset-last
434               'singular-emacs-simple-sec-reset-last
435               'singular-xemacs-simple-sec-reset-last)
436
437(singular-fset 'singular-simple-sec-start
438               'singular-emacs-simple-sec-start
439               'singular-xemacs-simple-sec-start)
440
441(singular-fset 'singular-simple-sec-end
442               'singular-emacs-simple-sec-end
443               'singular-xemacs-simple-sec-end)
444
445(singular-fset 'singular-simple-sec-start-at
446               'singular-emacs-simple-sec-start-at
447               'singular-xemacs-simple-sec-start-at)
448
449(singular-fset 'singular-simple-sec-end-at
450               'singular-emacs-simple-sec-end-at
451               'singular-xemacs-simple-sec-end-at)
452
453(singular-fset 'singular-simple-sec-type
454               'singular-emacs-simple-sec-type
455               'singular-xemacs-simple-sec-type)
456
457(singular-fset 'singular-simple-sec-at
458               'singular-emacs-simple-sec-at
459               'singular-xemacs-simple-sec-at)
460
461(singular-fset 'singular-simple-sec-before
462               'singular-emacs-simple-sec-before
463               'singular-xemacs-simple-sec-before)
464
465(singular-fset 'singular-simple-sec-in
466               'singular-emacs-simple-sec-in
467               'singular-xemacs-simple-sec-in)
468;;}}}
469
470;;{{{ Simple section stuff for Emacs
471(defun singular-emacs-simple-sec-create (type end)
472  "Create a new simple section of type TYPE.
473Creates the section from end of previous simple section up to END.
474END should be larger than `singular-simple-sec-last-end'.
475Returns the new simple section or `empty' if no simple section has
476been created.
477Assumes that no narrowing is in effect.
478Updates `singular-simple-sec-last-end'."
479  (let ((last-end (marker-position singular-simple-sec-last-end))
480        ;; `simple-sec' is the new simple section or `empty'
481        simple-sec)
482
483    ;; get beginning of line before END.  At this point we need that there
484    ;; are no restrictions.
485    (setq end (let ((old-point (point)))
486                (goto-char end) (beginning-of-line)
487                (prog1 (point) (goto-char old-point))))
488
489    (cond
490     ;; do not create empty sections
491     ((eq end last-end) (setq simple-sec 'empty))
492     ;; create only non-clear simple sections
493     ((not (eq type singular-simple-sec-clear-type))
494      ;; if type has not changed we only have to extend the previous
495      ;; simple section
496      (setq simple-sec (singular-emacs-simple-sec-before last-end))
497      (if (eq type (singular-emacs-simple-sec-type simple-sec))
498          ;; move existing overlay
499          (setq simple-sec (move-overlay simple-sec (overlay-start simple-sec) end))
500        ;; create new overlay
501        (setq simple-sec (make-overlay last-end end))
502        ;; set type property
503        (overlay-put simple-sec 'singular-type type)
504        ;; set face
505        (overlay-put simple-sec 'face (singular-lookup-face type))
506        ;; evaporate empty sections
507        (overlay-put simple-sec 'evaporate t))))
508           
509    ;; update end of last simple section
510    (set-marker singular-simple-sec-last-end end)
511    simple-sec))
512
513(defun singular-emacs-simple-sec-reset-last (pos)
514  "Reset end of last simple section to POS after accidental extension.
515Updates `singular-simple-sec-last-end', too."
516  (let ((simple-sec (singular-emacs-simple-sec-at pos)))
517    (if simple-sec (move-overlay simple-sec (overlay-start simple-sec) pos))
518    (set-marker singular-simple-sec-last-end pos)))
519
520(defun singular-emacs-simple-sec-start (simple-sec)
521  "Return start of non-clear simple section SIMPLE-SEC."
522  (overlay-start simple-sec))
523
524(defun singular-emacs-simple-sec-end (simple-sec)
525  "Return end of non-clear simple section SIMPLE-SEC."
526  (overlay-end simple-sec))
527
528(defun singular-emacs-simple-sec-start-at (pos)
529  "Return start of clear section at position POS.
530Assumes that no narrowing is in effect."
531  (let ((previous-overlay-change (1+ (point))))
532    ;; this `while' loop at last will run into the end of the next
533    ;; non-clear overlay or stop at bob.  Since POS may be right at the end
534    ;; of a previous non-clear location, we have to search at least one
535    ;; time from POS+1 backwards.
536    (while (not (or (singular-emacs-simple-sec-before previous-overlay-change)
537                    (eq previous-overlay-change (point-min))))
538      (setq previous-overlay-change
539            (previous-overlay-change previous-overlay-change)))
540    previous-overlay-change))
541
542(defun singular-emacs-simple-sec-end-at (pos)
543  "Return end of clear section at position POS.
544Assumes that no narrowing is in effect."
545  (let ((next-overlay-change (next-overlay-change (point))))
546    ;; this `while' loop at last will run into the beginning of the next
547    ;; non-clear overlay or stop at eob.  Since POS may not be at the
548    ;; beginning of a non-clear simple section we may start searching
549    ;; immediately.
550    (while (not (or (singular-emacs-simple-sec-at next-overlay-change)
551                    (eq next-overlay-change (point-max))))
552      (setq next-overlay-change
553            (next-overlay-change next-overlay-change)))
554    next-overlay-change))
555
556(defun singular-emacs-simple-sec-type (simple-sec)
557  "Return type of SIMPLE-SEC."
558  (if simple-sec
559      (overlay-get simple-sec 'singular-type)
560    singular-simple-sec-clear-type))
561
562(defun singular-emacs-simple-sec-at (pos)
563  "Return simple section at position POS."
564  (let ((overlays (overlays-at pos)) simple-sec)
565    ;; be careful, there may be other overlays!
566    (while (and overlays (not simple-sec))
567      (if (singular-emacs-simple-sec-type (car overlays))
568          (setq simple-sec (car overlays)))
569      (setq overlays (cdr overlays)))
570    simple-sec))
571
572(defun singular-emacs-simple-sec-before (pos)
573  "Return simple section before position POS.
574This is the same as `singular-simple-section-at' except if POS falls
575on a section border.  In this case `singular-simple-section-before'
576returns the previous simple section instead of the current one."
577  (singular-emacs-simple-sec-at (max 1 (1- pos))))
578
579(defun singular-emacs-simple-sec-in (beg end)
580  "Return a list of all simple sections intersecting with the region from BEG to END.
581A simple section intersects the region if the section and the region
582have at least one character in common.
583The result contains both clear and non-clear simple sections in the
584order in that the appear in the region."
585  ;; NOT READY
586  nil)
587;;}}}
588
589;;{{{ Simple section stuff for XEmacs
590(defun singular-xemacs-simple-sec-create (type end)
591  "Create a new simple section of type TYPE.
592Creates the section from end of previous simple section up to END.
593END should be larger than `singular-simple-sec-last-end'.
594Returns the new simple section or `empty' if no simple section has
595been created.
596Assumes that no narrowing is in effect.
597Updates `singular-simple-sec-last-end'."
598  (let ((last-end (marker-position singular-simple-sec-last-end))
599        ;; `simple-sec' is the new simple section or `empty'
600        simple-sec)
601
602    ;; get beginning of line before END.  At this point we need that there
603    ;; are no restrictions.
604    (setq end (let ((old-point (point)))
605                (goto-char end) (beginning-of-line)
606                (prog1 (point) (goto-char old-point))))
607
608    (cond
609     ;; do not create empty sections
610     ((eq end last-end) (setq simple-sec 'empty))
611     ;; create only non-clear simple sections
612     ((not (eq type singular-simple-sec-clear-type))
613      ;; if type has not changed we only have to extend the previous
614      ;; simple section
615      (setq simple-sec (singular-xemacs-simple-sec-before last-end))
616      (if (eq type (singular-xemacs-simple-sec-type simple-sec))
617          ;; move existing extent
618          (setq simple-sec (set-extent-endpoints simple-sec 
619                                                 (extent-start-position simple-sec) end))
620        ;; create new extent
621        (setq simple-sec (make-extent last-end end))
622        ;; set type property
623        (set-extent-property simple-sec 'singular-type type)
624        ;; set face
625        (set-extent-property simple-sec 'face (singular-lookup-face type)))))
626           
627    ;; update end of last simple section
628    (set-marker singular-simple-sec-last-end end)
629    simple-sec))
630
631(defun singular-xemacs-simple-sec-reset-last (pos)
632  "Reset end of last simple section to POS after accidental extension.
633Updates `singular-simple-sec-last-end', too."
634  (let ((simple-sec (singular-xemacs-simple-sec-at pos)))
635    (if simple-sec 
636        (set-extent-endpoints simple-sec (extent-start-position simple-sec) pos))
637    (set-marker singular-simple-sec-last-end pos)))
638
639(defun singular-xemacs-simple-sec-start (simple-sec)
640  "Return start of non-clear simple section SIMPLE-SEC."
641  (extent-start-position simple-sec))
642
643(defun singular-xemacs-simple-sec-end (simple-sec)
644  "Return end of non-clear simple section SIMPLE-SEC."
645  (extent-end-position simple-sec))
646
647(defun singular-xemacs-simple-sec-start-at (pos)
648  "Return start of clear section at position POS.
649Assumes that no narrowing is in effect."
650  (let ((previous-extent-change (1+ (point))))
651    ;; this `while' loop at last will run into the end of the next
652    ;; non-clear extent or stop at bob.  Since POS may be right at the end
653    ;; of a previous non-clear location, we have to search at least one
654    ;; time from POS+1 backwards.
655    (while (not (or (singular-xemacs-simple-sec-before previous-extent-change)
656                    (eq previous-extent-change (point-min))))
657      (setq previous-extent-change
658            (previous-extent-change previous-extent-change)))
659    previous-extent-change))
660
661(defun singular-xemacs-simple-sec-end-at (pos)
662  "Return end of clear section at position POS.
663Assumes that no narrowing is in effect."
664  (let ((next-extent-change (next-extent-change (point))))
665    ;; this `while' loop at last will run into the beginning of the next
666    ;; non-clear extent or stop at eob.  Since POS may not be at the
667    ;; beginning of a non-clear simple section we may start searching
668    ;; immediately.
669    (while (not (or (singular-xemacs-simple-sec-at next-extent-change)
670                    (eq next-extent-change (point-max))))
671      (setq next-extent-change
672            (next-extent-change next-extent-change)))
673    next-extent-change))
674
675(defun singular-xemacs-simple-sec-type (simple-sec)
676  "Return type of SIMPLE-SEC."
677  (if simple-sec
678      (extent-property simple-sec 'singular-type)
679    singular-simple-sec-clear-type))
680
681(defun singular-xemacs-simple-sec-at (pos)
682  "Return simple section at position POS."
683  (map-extents (function (lambda (ext args) ext))
684               ;; is this pos-pos-region OK? I think so.
685               (current-buffer) pos pos nil nil 'singular-type))
686
687(defun singular-xemacs-simple-sec-before (pos)
688  "Return simple section before position POS.
689This is the same as `singular-simple-section-at' except if POS falls
690on a section border.  In this case `singular-simple-section-before'
691returns the previous simple section instead of the current one."
692  (singular-xemacs-simple-sec-at (max 1 (1- pos))))
693
694(defun singular-xemacs-simple-sec-in (beg end)
695  "Return a list of all simple sections intersecting with the region from BEG to END.
696A simple section intersects the region if the section and the region
697have at least one character in common.
698The result contains both clear and non-clear simple sections in the
699order they appear in the region."
700  ;; NOT READY
701  nil)
702;;}}}
703
704;;{{{ Section stuff
705
706;; Note:
707;;
708;; Sections are built on simple sections.  Their purpose is to cover the
709;; difference between clear and non-clear simple sections.
710;;
711;; - Sections consist of a simple section, its type, and its start and end
712;;   points.  This is redundant information only in the case of non-clear
713;;   simple section.
714;; - Sections are read-only objects, neither are they modified nor are they
715;;   created.
716;; - Buffer narrowing does not restrict the extent of completely or
717;;   partially inaccessible sections.  In contrast to simple sections
718;;   the functions concerning sections do not assume that there is no
719;;   narrowing in effect.
720;; - Sections are independent from implementation dependencies.  There are
721;;   no different versions of the functions for Emacs and XEmacs.
722
723(defun singular-section-at (pos &optional restricted)
724  "Return section at position POS.
725Returns section intersected with current restriction if RESTRICTED is
726non-nil."
727  (let* ((simple-sec (singular-simple-sec-at pos))
728         (type (singular-simple-sec-type simple-sec))
729         start end)
730    (if simple-sec
731        (setq start (singular-simple-sec-start simple-sec)
732              end  (singular-simple-sec-end simple-sec))
733      (save-restriction
734        (widen)
735        (setq start (singular-simple-sec-start-at pos)
736              end (singular-simple-sec-end-at pos))))
737    (if restricted
738        (vector simple-sec type
739                (max start (point-min)) (min end (point-max)))
740      (vector simple-sec type start end))))
741
742(defun singular-section-before (pos &optional restricted)
743  "Return section before position POS.
744This is the same as `singular-section-at' except if POS falls on a
745section border.  In this case `singular-section-before' returns the
746previous section instead of the current one.
747Returns section intersected with current restriction if RESTRICTED is
748non-nil."
749  (singular-section-at (max 1 (1- pos)) restricted))
750
751(defmacro singular-section-simple-sec (section)
752  "Return underlying simple section of SECTION."
753  `(aref ,section 0))
754
755(defmacro singular-section-type (section)
756  "Return type of SECTION."
757  `(aref ,section 1))
758
759(defmacro singular-section-start (section)
760  "Return start of SECTION."
761  `(aref ,section 2))
762
763(defmacro singular-section-end (section)
764  "Return end of SECTION."
765  `(aref ,section 3))
766;;}}}
767
768;;{{{ Getting section contents
769(defun singular-input-section-to-string (section &optional end raw)
770  "Get content of SECTION as string.
771Returns text between start of SECTION and END if optional argument END
772is non-nil.  END should be a position inside SECTION.
773Strips leading prompts and trailing white space unless optional argument
774RAW is non-nil."
775  (save-restriction
776    (widen)
777    (let ((string (if end
778                      (buffer-substring (singular-section-start section) end)
779                    (buffer-substring (singular-section-start section)
780                                      (singular-section-end section)))))
781      (if raw string
782        (singular-strip-leading-prompt
783         (singular-strip-white-space string t))))))
784;;}}}
785
786;;{{{ Folding sections
787(defvar singular-folding-ellipsis "Singular I/O ..."
788  "Ellipsis to show for folded input or output.")
789
790(defun singular-fold-internal (start end fold)
791  "(Un)fold region from START to END.
792Folds if FOLD is non-nil, otherwise unfolds.
793Folding affects undo information and buffer modified flag.
794Assumes that there is no narrowing in effect."
795  (save-excursion
796    (if fold
797        (progn
798          (goto-char start) (insert ?\r)
799          (subst-char-in-region start end ?\n ?\r t))
800      (subst-char-in-region start end ?\r ?\n t)
801      (goto-char start) (delete-char 1))))
802
803(defun singular-section-foldedp (section)
804  "Return t iff SECTION is folded.
805Assumes that there is no narrowing in effect."
806  (eq (char-after (singular-section-start section)) ?\r))
807
808(defun singular-fold-section (section)
809  "(Un)fold SECTION.
810(Un)folds section at point and goes to beginning of section if called
811interactively.
812Unfolds folded sections and folds unfolded sections."
813  (interactive (list (singular-section-at (point))))
814  (let ((start (singular-section-start section))
815        ;; we have to save restrictions this way since we change text
816        ;; outside the restriction.  Note that we do not use a marker for
817        ;; `old-point-min'.  This way, even partial narrowed sections are
818        ;; folded properly if they have been narrowed at bol.  Nice but
819        ;; dirty trick: The insertion of a `?\r' at beginning of section
820        ;; advances the beginning of the restriction such that it displays
821        ;; the `?\r' immediately before bol.  Seems worth it.
822        (old-point-min (point-min))
823        (old-point-max (point-max-marker)))
824    (unwind-protect
825        (progn
826          (widen)
827          (singular-fold-internal start (singular-section-end section)
828                                  (not (singular-section-foldedp section))))
829      (narrow-to-region old-point-min old-point-max)
830      (set-marker old-point-max nil))
831    (if (interactive-p) (goto-char (max start (point-min))))))
832;;}}}
833
834;;{{{ Input and output filters
835
836;; debugging filters
837(defun singular-debug-input-filter (string)
838  "Echo STRING in mini-buffer."
839  (singular-debug 'interactive-filter
840                  (message "Input filter: %s"
841                           (singular-debug-format string))))
842
843(defun singular-debug-output-filter (string)
844  "Echo STRING in mini-buffer."
845  (singular-debug 'interactive-filter
846                  (message "Output filter: %s"
847                           (singular-debug-format string))))
848
849;; stripping prompts
850(defun singular-remove-prompt-filter (&optional string)
851  "Strip prompts from last simple section."
852  (singular-remove-prompt comint-last-output-start
853                          (singular-process-mark)))
854;;}}}
855
856;;{{{ Demo mode
857(defvar singular-demo-chunk-regexp "\\(\n\n\\)"
858  "Regular expressions to recognize chunks of a demo file.
859If there is a subexpression specified its content is removed when the
860chunk is displayed.")
861
862(defvar singular-demo-mode nil
863  "Non-nil if Singular demo mode is on.
864
865This variable is buffer-local.")
866
867(defvar singular-demo-old-mode-name nil
868  "Used to store previous `mode-name' before switching to demo mode.
869
870This variable is buffer-local.")
871
872(defvar singular-demo-end nil
873  "Marker pointing to end of demo file.
874
875This variable is buffer-local.")
876
877(defvar singular-demo-command-on-enter nil
878  "Singular command to send when entering demo mode or nil if no string to send.")
879
880(defvar singular-demo-command-on-leave nil
881  "Singular command to send when leaving demo mode or nil if no string to send.")
882 
883(defun singular-demo-mode (mode)
884  "Switch between demo mode states.
885MODE may be either:
886- `init' to initialize global variables;
887- `exit' to clean up demo and leave Singular demo mode;
888- `enter' to enter Singular demo mode;
889- `leave' to leave Singular demo mode.
890
891Modifies the global variables `singular-demo-mode',
892`singular-demo-end', and `singular-demo-old-mode-name' to reflect the
893new state of Singular demo mode."
894  (cond
895   ;; initialization.  Should be called only once.
896   ((eq mode 'init)
897    (make-local-variable 'singular-demo-mode)
898    (make-local-variable 'singular-demo-mode-old-name)
899    (make-local-variable 'singular-demo-mode-end)
900    (if (not (and (boundp 'singular-demo-end)
901                  singular-demo-end))
902        (setq singular-demo-end (make-marker))))
903
904   ;; final exit.  Clean up demo.
905   ((and (eq mode 'exit)
906         singular-demo-mode)
907    (setq mode-name singular-demo-old-mode-name
908          singular-demo-mode nil)
909    ;; clean up hidden rest of demo file if existent
910    (let ((old-point-min (point-min))
911          (old-point-max (point-max)))
912      (unwind-protect
913          (progn
914            (widen)
915            (delete-region old-point-max singular-demo-end))
916        ;; this is unwide-protected
917        (narrow-to-region old-point-min old-point-max)))
918    (if (and singular-demo-command-on-leave
919             (singular-process))
920        (send-string (singular-process) singular-demo-command-on-leave))
921    (force-mode-line-update))
922
923   ;; enter demo mode
924   ((and (eq mode 'enter)
925         (not singular-demo-mode))
926    (setq singular-demo-old-mode-name mode-name
927          mode-name "Singular Demo"
928          singular-demo-mode t)
929    (if singular-demo-command-on-enter
930        (send-string (singular-process) singular-demo-command-on-enter))
931    (force-mode-line-update))
932
933   ;; leave demo mode
934   ((and (eq mode 'leave)
935         singular-demo-mode)
936    (setq mode-name singular-demo-old-mode-name
937          singular-demo-mode nil)
938    (if singular-demo-command-on-leave
939        (send-string (singular-process) singular-demo-command-on-leave))
940    (force-mode-line-update))))
941
942(defun singular-demo-exit ()
943  "Prematurely exit singular demo mode."
944  (interactive)
945  (singular-demo-mode 'exit))
946
947(defun singular-demo-show-next-chunk ()
948  "Show next chunk of demo file at input prompt.
949Moves point to end of buffer and widenes the buffer such that the next
950chunk of the demo file becomes visible.
951Finds and removes chunk separators as specified by
952`singular-demo-chunk-regexp'.
953Removing chunk separators affects undo information and buffer-modified
954flag.
955Leaves demo mode after showing last chunk."
956  (let ((old-point-min (point-min)))
957    (unwind-protect
958        (progn
959          (goto-char (point-max))
960          (widen)
961          (if (re-search-forward singular-demo-chunk-regexp singular-demo-end 'limit)
962              (and (match-beginning 1)
963                   (delete-region (match-beginning 1) (match-end 1)))
964            ;; remove trailing white-space
965            (skip-syntax-backward "-")
966            (delete-region (point) singular-demo-end)
967            (singular-demo-mode 'leave)))
968
969      ;; this is unwind-protected
970      (narrow-to-region old-point-min (point)))))
971
972(defun singular-demo-load (demo-file)
973  "Load demo file DEMO-FILE and enter Singular demo mode.
974For a description of the Singular demo mode one should refer to the
975doc-string of `singular-interactive-mode'.
976Moves point to end of buffer and inserts contents of DEMO-FILE there."
977  (interactive "fLoad demo file: ")
978
979  ;; check for running demo
980  (and singular-demo-mode
981       (error "Another demo is already running"))
982
983  (let ((old-point-min (point-min)))
984    (unwind-protect
985        (progn
986          (goto-char (point-max))
987          (widen)
988          ;; load file and remember its end
989          (set-marker singular-demo-end
990                      (+ (point) (nth 1 (insert-file-contents demo-file)))))
991
992      ;; completely hide demo file.
993      ;; This is unwide protected.
994      (narrow-to-region old-point-min (point)))
995
996    ;; switch demo mode on
997    (singular-demo-mode 'enter)))
998;;}}}
999     
1000;;{{{ Sending input and receiving output
1001
1002;;{{{ Some lengthy notes on filters
1003
1004;; Note:
1005;;
1006;; The filters and other functions have access to four important markers,
1007;; `comint-last-input-start', `comint-last-input-end',
1008;; `comint-last-output-start', and the buffers process mark.  They are
1009;; initialized to nil (except process mark, which is initialized to
1010;; `(point-max)') when Singular is called in `singular'.  These markers are
1011;; modified by `comint-send-input' and `comint-output-filter' but not in a
1012;; quite reliable way.  Here are some valid invariants and pre-/post-
1013;; conditions.
1014;;
1015;; Output filters:
1016;; ---------------
1017;; The output filters may be sure that they are run in the process buffer
1018;; and that the process buffer is still alive.  `comint-output-filter'
1019;; ensures this.  But `comint-output-filter' does neither catch changes in
1020;; match data done by the filters nor does it protect against non-local
1021;; exits of itself or of one of the filters.  As a result, the current
1022;; buffer may be changed in `comint-output-filter'!
1023;;
1024;; `comint-output-filter' is called also from `comint-send-input' (dunno
1025;; why).  The following holds only for executions of `comint-output-filter'
1026;; as a result of Singular output being processed.
1027;;
1028;; We have the following preconditions for any output filters (up to
1029;; changes through other filter functions):
1030;; - The argument STRING is what has been inserted in the buffer.  Not
1031;;   really reliable.
1032;; - `comint-last-input-end' <= `comint-last-output-start' <= process mark
1033;;   if all of them are defined
1034;; - The text between `comint-last-output-start' and process mark is the
1035;;   one which has been inserted immediately before.
1036;; - The text between `comint-last-input-end' (if it is defined) and
1037;;   process mark is the one which has been inserted into buffer since last
1038;;   user input.
1039;; - It seems to be a reasonable assumption that the text between process
1040;;   mark and `(point-max)' is user input.
1041;;
1042;; The standard filters which come with comint.el do not change the markers
1043;; in the preconditions described above.  But they may change the text
1044;; (e.g., `comint-strip-ctrl-m').
1045;;
1046;; Post-conditions for `comint-output-filter':
1047;; - `comint-last-output-start' <= process mark.  The region between them
1048;;   is the text which has been inserted immediately before.
1049;; - `comint-last-input-start' and `comint-last-input-end' are unchanged.
1050;;
1051;; Input filters:
1052;; --------------
1053;; `comint-send-input' ensures that the process is still alive.  Further
1054;; preconditions for any input filter (up to changes through filter
1055;; functions):
1056;; - The (CR-terminated) argument STRING is what will be sent to the
1057;;   process (up to slight differences between XEmacs and Emacs).  Not
1058;;   really reliable.
1059;; - process mark <= `(point)'
1060;; - The (CR-terminated) text between process mark and `(point)' is what
1061;;   has been inserted by the user.
1062;;
1063;; Post-conditions for `comint-send-input':
1064;; - `comint-last-input-start' <= `comint-last-input-end'
1065;;                              = `comint-last-output-start' (!)
1066;;                              = process mark = `(point)'.
1067;;   The region between the first of them is what has been inserted by the
1068;;   user.
1069;;
1070;; Invariants which always hold outside `comint-send-input' and
1071;; `comint-output-filter':
1072;; ------------------------------------------------------------
1073;; - `comint-last-input-start' <= `comint-last-input-end' <= process mark
1074;;   if all of them are defined.  The region between the first of them is
1075;;   the last input entered by the user, the region between the latter of
1076;;   them is the text from Singular printed since the last input.
1077;; - `comint-last-output-start' <= process mark if both are defined.
1078;; - It is a reasonable assumption that the text from process mark up to
1079;;   `(point-max)' is user input.
1080
1081;;}}}
1082
1083(defun singular-get-old-input (get-section)
1084  "Retrieve old input.
1085Retrivies from beginning of current section to point if GET-SECTION is
1086non-nil, otherwise on a per-line base."
1087  (if get-section
1088      ;; get input from input section
1089      (let ((section (singular-section-at (point))))
1090        (if (eq (singular-section-type section) 'input)
1091            (setq old-input (singular-input-section-to-string section (point)))
1092          (error "Not on an input section")))
1093    ;; get input from line
1094    (save-excursion
1095      (beginning-of-line)
1096      (singular-skip-prompt-forward)
1097      (let ((old-point (point)))
1098        (end-of-line)
1099        (buffer-substring old-point (point))))))
1100
1101(defun singular-send-or-copy-input (send-full-section)
1102  "NOT READY!!"
1103  (interactive "P")
1104
1105  (let ((process (get-buffer-process (current-buffer)))
1106        pmark)
1107    ;; some checks and initializations
1108    (or process (error "Current buffer has no process"))
1109    (setq pmark (marker-position (process-mark process)))
1110
1111    (cond
1112     (;; check for demo mode and show next chunk if necessary
1113      (and singular-demo-mode
1114          (eq (point) pmark)
1115          (eq pmark (point-max)))
1116      (singular-demo-show-next-chunk))
1117
1118     (;; get old input
1119      (< (point) pmark)
1120      (let ((old-input (singular-get-old-input send-full-section)))
1121        (goto-char (point-max))
1122        (insert old-input)))
1123
1124     (;; send input from pmark to point
1125      t
1126      ;; note that the input string does not include its terminal newline
1127      (let* ((raw-input (buffer-substring pmark (point)))
1128             (input raw-input)
1129             (history raw-input))
1130
1131        ;; insert newline into buffer
1132        (insert ?\n)
1133
1134        ;; insert input into history
1135        (if (and (funcall comint-input-filter history)
1136                 (or (null comint-input-ignoredups)
1137                     (not (ring-p comint-input-ring))
1138                     (ring-empty-p comint-input-ring)
1139                     (not (string-equal (ring-ref comint-input-ring 0) history))))
1140            (ring-insert comint-input-ring history))
1141
1142        ;; run hooks and reset index into history
1143        (run-hook-with-args 'comint-input-filter-functions (concat input "\n"))
1144        (setq comint-input-ring-index nil)
1145
1146        ;; update markers and create a new simple section
1147        (set-marker comint-last-input-start pmark)
1148        (set-marker comint-last-input-end (point))
1149        (set-marker (process-mark process) (point))
1150        (singular-debug 'interactive-simple-secs
1151                        (message "Simple input section: %S"
1152                                 (singular-simple-sec-create 'input (point)))
1153                        (singular-simple-sec-create 'input (point)))
1154
1155        ;; do it !!
1156        (send-string process input)
1157        (send-string process "\n"))))))
1158
1159(defun singular-output-filter (process string)
1160  "Insert STRING containing output from PROCESS into its associated buffer.
1161
1162Takes care off:
1163- current buffer, even in case of non-local exits;
1164- point and restriction in buffer associated with process;
1165- markers which should not be advanced when inserting output.
1166Updates:
1167- process mark;
1168- `comint-last-output-start';
1169- simple sections;
1170- mode line.
1171Runs the hooks on `comint-output-filter-functions'.
1172
1173For a more detailed descriptions of the output filter, the markers it
1174sets, and output filter functions refer to the section \"Some lengthy
1175notes on filters\" in singular.el."
1176  (let ((process-buffer (process-buffer process))
1177        (old-buffer (current-buffer)))
1178
1179    ;; check whether buffer is still alive
1180    (if (and process-buffer (buffer-name process-buffer))
1181        (unwind-protect
1182            (progn
1183              (set-buffer process-buffer)
1184              (let ((old-point (point))
1185                    (old-point-min (point-min))
1186                    (old-point-max (point-max))
1187                    (old-pmark (marker-position (process-mark process)))
1188                    (n (length string)))
1189                (widen)
1190                (goto-char old-pmark)
1191
1192                ;; adjust point and narrowed region borders
1193                (if (<= (point) old-point) (setq old-point (+ old-point n)))
1194                (if (< (point) old-point-min) (setq old-point-min (+ old-point-min n)))
1195                (if (<= (point) old-point-max) (setq old-point-max (+ old-point-max n)))
1196
1197                ;; do it !!
1198                (insert-before-markers string)
1199
1200                ;; reset markers and simple sections which may have
1201                ;; been advanced by above insertion.  We rely on the
1202                ;; fact that `set-marker' always returns some non-nil
1203                ;; value.  Looks nicer this way.
1204                (and (= comint-last-input-end (point))
1205                     (set-marker comint-last-input-end old-pmark)
1206                     ;; this may happen only on startup and only if
1207                     ;; `comint-last-input-end' has been modified,
1208                     ;; too.  Hence, we check for it after the first
1209                     ;; test.
1210                     (= comint-last-input-start (point))
1211                     (set-marker comint-last-input-start old-pmark))
1212                (and (= singular-simple-sec-last-end (point))
1213                     (singular-simple-sec-reset-last old-pmark))
1214
1215                ;; set new markers and create/extend new simple section
1216                (set-marker comint-last-output-start old-pmark)
1217                (singular-debug 'interactive-simple-secs
1218                                (message "Simple output section: %S"
1219                                         (singular-simple-sec-create 'output (point)))
1220                                (singular-simple-sec-create 'output (point)))
1221
1222                ;; restore old values, run hooks, and force mode line update
1223                (narrow-to-region old-point-min old-point-max)
1224                (goto-char old-point)
1225                (run-hook-with-args 'comint-output-filter-functions string)
1226                (force-mode-line-update)))
1227
1228          ;; this is unwind-protected
1229          (set-buffer old-buffer)))))
1230;;}}}
1231
1232;;{{{ Singular interactive mode
1233(defun singular-interactive-mode ()
1234  "Major mode for interacting with Singular.
1235
1236NOT READY [how to send input]!
1237
1238NOT READY [multiple Singulars]!
1239
1240Singular buffers are automatically limited in length \(by default, to
12412048 lines).  This limit may be adjusted by setting
1242`singular-buffer-maximum-size' before Singular interactive mode starts
1243up or by setting `comint-buffer-maximum-size' while Singular
1244interactive mode is running.
1245
1246\\{singular-interactive-mode-map}
1247Customization: Entry to this mode runs the hooks on `comint-mode-hook'
1248and `singular-interactive-mode-hook' \(in that order).  Before each
1249input, the hooks on `comint-input-filter-functions' are run.  After
1250each Singular output, the hooks on `comint-output-filter-functions'
1251are run.
1252
1253NOT READY [much more to come.  See shell.el.]!"
1254  (interactive)
1255
1256  ;; run comint mode and do basic mode setup
1257  (comint-mode)
1258  (setq major-mode 'singular-interactive-mode)
1259  (setq mode-name "Singular Interaction")
1260  (use-local-map singular-interactive-mode-map)
1261
1262  ;; customize comint for Singular
1263  (setq comint-prompt-regexp singular-prompt-regexp)
1264  (setq comint-delimiter-argument-list singular-delimiter-argument-list)
1265  (setq comint-input-ignoredups singular-input-ignoredups)
1266  (make-local-variable 'comint-buffer-maximum-size)
1267  (setq comint-buffer-maximum-size singular-buffer-maximum-size)
1268  (setq comint-input-ring-size singular-input-ring-size)
1269  (setq comint-input-filter singular-history-filter)
1270  ;; do not add `comint-truncate-buffer' if it already has been added
1271  ;; globally.  This is sort of a bug in `add-hook'.
1272  (and (default-boundp 'comint-output-filter-functions)
1273       (not (memq 'comint-truncate-buffer
1274                  (default-value 'comint-output-filter-functions)))
1275       (add-hook 'comint-output-filter-functions
1276                 'comint-truncate-buffer nil t))
1277
1278  ;; get name of history file (if any)
1279  (setq comint-input-ring-file-name (getenv "SINGULARHIST"))
1280  (if (or (not comint-input-ring-file-name)
1281          (equal comint-input-ring-file-name "")
1282          (equal (file-truename comint-input-ring-file-name) "/dev/null"))
1283      (setq comint-input-ring-file-name nil))
1284
1285  ;; initialize singular demo mode
1286  (singular-demo-mode 'init)
1287
1288  ;; selective display
1289  (setq selective-display t)
1290  (setq selective-display-ellipses t)
1291  (cond
1292   ;; Emacs
1293   ((eq singular-emacs-flavor 'emacs)
1294    (setq buffer-display-table (or (copy-sequence standard-display-table)
1295                                   (make-display-table)))
1296    (set-display-table-slot buffer-display-table
1297     'selective-display (vconcat singular-folding-ellipsis)))
1298    ;; XEmacs
1299   (t
1300    (set-glyph-image invisible-text-glyph singular-folding-ellipsis (current-buffer))))
1301
1302  ;; input and output filters
1303  (singular-debug 'interactive-filter
1304                  (add-hook 'comint-input-filter-functions
1305                            'singular-debug-input-filter nil t))
1306  (singular-debug 'interactive-filter
1307                  (add-hook 'comint-output-filter-functions
1308                            'singular-debug-output-filter nil t))
1309  (add-hook 'comint-output-filter-functions
1310            'singular-remove-prompt-filter nil t)
1311
1312  (run-hooks 'singular-interactive-mode-hook))
1313;;}}}
1314
1315;;{{{ Starting singular
1316(defvar singular-start-file "~/.emacs_singularrc"
1317  "Name of start-up file to pass to Singular.
1318If the file named by this variable exists it is given as initial input
1319to any Singular process being started.  Note that this may lose due to
1320a timing error if Singular discards input when it starts up.")
1321
1322(defvar singular-default-executable "Singular"
1323  "Default name of Singular executable.
1324Used by `singular' when new Singular processes are started.")
1325
1326(defvar singular-default-name "singular"
1327  "Default process name for Singular process.
1328Used by `singular' when new Singular processes are started.")
1329
1330(defvar singular-default-switches '("-t")
1331  "Default switches for Singular processes.
1332Used by `singular' when new Singular processes are started.")
1333
1334(defun singular-exit-sentinel (process message)
1335 "Clean up after termination of Singular.
1336Writes back input ring after regular termination of Singular if
1337process buffer is still alive."
1338  (save-excursion
1339    (singular-debug 'interactive
1340                    (message "Sentinel: %s" (substring message 0 -1)))
1341    ;; exit demo mode if necessary
1342    (singular-demo-mode 'exit)
1343    (if (string-match "finished\\|exited" message)
1344        (let ((process-buffer (process-buffer process)))
1345          (if (and process-buffer
1346                   (buffer-name process-buffer)
1347                   (set-buffer process-buffer))
1348              (progn
1349                (singular-debug 'interactive (message "Writing input ring back"))
1350                (comint-write-input-ring)))))))
1351
1352(defun singular-exec (buffer name executable start-file switches)
1353  "Start a new Singular process NAME in BUFFER, running EXECUTABLE.
1354EXECUTABLE should be a string denoting an executable program.
1355SWITCHES should be a list of strings that are passed as command line
1356switches.  START-FILE should be the name of a file which contents is
1357sent to the process.
1358
1359Deletes any old processes running in that buffer.
1360Moves point to the end of BUFFER.
1361Initializes all important markers and the simple sections.
1362Runs `comint-exec-hook' and `singular-exec-hook' (in that order).
1363Returns BUFFER."
1364  (let ((old-buffer (current-buffer)))
1365    (unwind-protect
1366        (progn
1367          (set-buffer buffer)
1368
1369          ;; delete any old processes
1370          (let ((process (get-buffer-process buffer)))
1371            (if process (delete-process process)))
1372
1373          ;; create new process
1374          (singular-debug 'interactive (message "Starting new Singular"))
1375          (let ((process (comint-exec-1 name buffer executable switches)))
1376
1377            ;; set process filter and sentinel
1378            (set-process-filter process 'singular-output-filter)
1379            (set-process-sentinel process 'singular-exit-sentinel)
1380            (make-local-variable 'comint-ptyp)
1381            (setq comint-ptyp process-connection-type) ; T if pty, NIL if pipe.
1382
1383            ;; go to the end of the buffer, set up markers, and
1384            ;; initialize simple sections
1385            (goto-char (point-max))
1386            (set-marker comint-last-input-start (point))
1387            (set-marker comint-last-input-end (point))
1388            (set-marker comint-last-output-start (point))
1389            (set-marker (process-mark process) (point))
1390            (singular-simple-sec-init (point))
1391
1392            ;; feed process with start file and read input ring.  Take
1393            ;; care about the undo information.
1394            (if start-file
1395                (let ((buffer-undo-list t) start-string)
1396                  (singular-debug 'interactive (message "Feeding start file"))
1397                  (sleep-for 1)                 ; try to avoid timing errors
1398                  (insert-file-contents start-file)
1399                  (setq start-string (buffer-substring (point) (point-max)))
1400                  (delete-region (point) (point-max))
1401                  (send-string process start-string)))
1402            (singular-debug 'interactive (message "Reading input ring"))
1403            (comint-read-input-ring t)
1404
1405            ;; execute hooks
1406            (run-hooks 'comint-exec-hook)
1407            (run-hooks 'singular-exec-hook))
1408         
1409          buffer)
1410      ;; this code is unwide-protected
1411      (set-buffer old-buffer))))
1412
1413;; Note:
1414;;
1415;; In contrast to shell.el, `singular' does not run
1416;; `singular-interactive-mode' every time a new Singular process is
1417;; started, but only when a new buffer is created.  This behaviour seems
1418;; more intuitive w.r.t. local variables and hooks.
1419
1420(defun singular (&optional executable name switches)
1421  "Run an inferior Singular process, with I/O through an Emacs buffer.
1422
1423NOT READY [arguments, default values, and interactive use]!
1424
1425If buffer exists but Singular is not running, starts new Singular.
1426If buffer exists and Singular is running, just switches to buffer.
1427If a file `~/.emacs_singularrc' exists, it is given as initial input.
1428Note that this may lose due to a timing error if Singular discards
1429input when it starts up.
1430
1431If a new buffer is created it is put in Singular interactive mode,
1432giving commands for sending input and handling ouput of Singular.  See
1433`singular-interactive-mode'.
1434
1435Every time `singular' starts a new Singular process it runs the hooks
1436on `comint-exec-hook' and `singular-exec-hook' \(in that order).
1437
1438Type \\[describe-mode] in the Singular buffer for a list of commands."
1439  ;; handle interactive calls
1440  (interactive (list singular-default-executable
1441                     singular-default-name
1442                     singular-default-switches))
1443
1444  (let* (;; get default values for optional arguments
1445         (executable (or executable singular-default-executable))
1446         (name (or name singular-default-name))
1447         (switches (or switches singular-default-switches))
1448
1449         (buffer-name (singular-process-name-to-buffer-name name))
1450         ;; buffer associated with Singular, nil if there is none
1451         (buffer (get-buffer buffer-name)))
1452
1453    (if (not buffer)
1454        (progn
1455          ;; create new buffer and call `singular-interactive-mode'
1456          (singular-debug 'interactive (message "Creating new buffer"))
1457          (setq buffer (get-buffer-create buffer-name))
1458          (set-buffer buffer)
1459          (singular-debug 'interactive (message "Calling `singular-interactive-mode'"))
1460          (singular-interactive-mode)))
1461
1462    (if (not (comint-check-proc buffer))
1463        ;; create new process if there is none
1464        (singular-exec buffer name executable
1465                       (if (file-exists-p singular-start-file)
1466                           singular-start-file)
1467                       switches))
1468
1469    ;; pop to buffer
1470    (singular-debug 'interactive (message "Calling `pop-to-buffer'"))
1471    (pop-to-buffer buffer)))
1472
1473;; for convenience only
1474(defalias 'Singular 'singular)
1475;;}}}
1476;;}}}
1477
1478(provide 'singular)
1479
1480;;; singular.el ends here.
Note: See TracBrowser for help on using the repository browser.