source: git/emacs/singular.el @ 81da6ba

spielwiese
Last change on this file since 81da6ba was 81da6ba, checked in by Jens Schmidt <schmidt@…>, 26 years ago
* singular.el: input/output completely rewritten. Keine Zeit mehr, Omlett wird fertig!! * singular.el (singular-pre-input-filter-functions, singular-post-input-filter-functions, singular-pre-output-filter-functions, singular-post-output-filter-functions): new local variables resp. hooks. Localizations added. * singular.el (singular-last-input-section, singular-last-output-section, singular-current-output-section, singular-latest-output-section): new functions * singular.el (singular-input-filter-init, singular-output-filter-init): new functions (singular-exec): calls new I/O initialization instead of old one * singular.el (singular-interactive-mode): all references to `comint-input-filter-functions' resp. `comint-output-filter-functions' replaced by there corresponding singular specific hooks (singular-interactive-mode): `comint-truncate-lines' removed from `comint-output-filter-functions' * singular.el (singular-debug-post-output-filter, singular-debug-pre-output-filter, singular-debug-post-output-filter, singular-debug-pre-output-filter): new functions. Added to the respective hooks. (singular-debug-input-filter, singular-debug-output-filter): functions removed. Removed from the respective hooks. * singular.el (singular-remove-prompt): does not save point. Does not jump to beginning of line. (singular-remove-prompt-filter): adapted to new calling conventions. Uses SIMPLE-SEC-START to determine whether removal is necessary. * singular.el (singular-simple-sec-init): initialization slightly changed (singular-run-hook-with-arg-and-value): new function (singular-debug): checks for `t' instead of `all' (singular-fold-section): doc fix (singular-extended-prompt-regexp): `"?"' as prompt character added (singular-skip-prompt-backward): new function git-svn-id: file:///usr/local/Singular/svn/trunk@2422 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 62.4 KB
Line 
1;;; singular.el --- Emacs support for Computer Algebra System Singular
2
3;; $Id: singular.el,v 1.16 1998-07-31 21:05:53 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 t or if MODE is an element
76of `singular-debug', othwerwise ELSE-FORM."
77  `(if (or (eq singular-debug t)
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(defun singular-run-hook-with-arg-and-value (hook value)
216  "Call functions on HOOK.
217Provides argument VALUE.  If a function returns a non-nil value it
218replaces VALUE as new argument to the functions.  Returns final
219VALUE."
220  (let (result)
221    (while hook
222      (setq result (funcall (car hook) value))
223      (and result (setq value result))
224      (setq hook (cdr hook)))
225    value))
226
227(defmacro singular-process ()
228  "Return process of current buffer."
229  (get-buffer-process (current-buffer)))
230
231(defmacro singular-process-mark ()
232  "Return process mark of current buffer."
233  (process-mark (get-buffer-process (current-buffer))))
234;;}}}
235
236;;{{{ Customizing variables of comint
237
238;; Note:
239;;
240;; In contrast to the variables from comint.el, all the variables
241;; below are global variables.  It would not make any sense to make
242;; them buffer-local since
243;; o they are read only when Singular interactive mode comes up;
244;; o since they are Singular-dependent and not user-dependent, i.e.,
245;;   the user would not mind to change them.
246;;
247;; For the same reasons these variables are not marked as
248;; "customizable" by a leading `*'.
249
250(defvar singular-prompt-regexp "^> "
251  "Regexp to match prompt patterns in Singular.
252Should not match the continuation prompt \(`.'), only the regular
253prompt \(`>').
254
255This variable is used to initialize `comint-prompt-regexp' when
256Singular interactive mode starts up.")
257
258(defvar singular-delimiter-argument-list '(?= ?\( ?\) ?, ?;)
259  "List of characters to recognize as separate arguments.
260
261This variable is used to initialize `comint-delimiter-argument-list'
262when Singular interactive mode starts up.")
263
264(defvar singular-input-ignoredups t
265  "If non-nil, don't add input matching the last on the input ring.
266
267This variable is used to initialize `comint-input-ignoredups' when
268Singular interactive mode starts up.")
269
270(defvar singular-buffer-maximum-size 2048
271  "The maximum size in lines for Singular buffers.
272
273This variable is used to initialize `comint-buffer-maximum-size' when
274Singular interactive mode starts up.")
275
276(defvar singular-input-ring-size 64
277  "Size of input history ring.
278
279This variable is used to initialize `comint-input-ring-size' when
280Singular interactive mode starts up.")
281
282(defvar singular-history-filter-regexp "\\`\\(..?\\|\\s *\\)\\'"
283  "Regular expression to filter strings *not* to insert in the history.
284By default, input consisting of less than three characters and input
285consisting of white-space only is not added to the history.")
286
287(defvar singular-history-filter
288  (function (lambda (string)
289              (not (string-match singular-history-filter-regexp string))))
290  "Predicate for filtering additions to input history.
291
292This variable is used to initialize `comint-input-filter' when
293Singular interactive mode starts up.")
294;;}}}
295
296;;{{{ Skipping and stripping prompts and newlines and other things
297
298;; Note:
299;;
300;; All of these functions modify the match data!
301
302(defun singular-strip-white-space (string &optional trailing leading)
303  "Strip off trailing or leading white-space from STRING.
304Strips off trailing white-space if optional argument TRAILING is
305non-nil.
306Strips off leading white-space if optional argument LEADING is
307non-nil."
308  (let ((beg 0)
309        (end (length string)))
310    (and leading
311         (string-match "\\`\\s-*" string)
312         (setq beg (match-end 0)))
313    (and trailing
314         (string-match "\\s-*\\'" string beg)
315         (setq end (match-beginning 0)))
316    (substring string beg end)))
317
318(defconst singular-extended-prompt-regexp "\\([?>.] \\)"
319  "Matches one Singular prompt.
320Should not be anchored neither to start nor to end!")
321
322(defconst singular-strip-leading-prompt-regexp
323  (concat "\\`" singular-extended-prompt-regexp "+")
324  "Matches Singular prompt anchored to string start.")
325
326(defun singular-strip-leading-prompt (string)
327  "Strip leading prompts from STRING.
328May or may not return STRING or a modified copy of it."
329  (if (string-match singular-strip-leading-prompt-regexp string)
330      (substring string (match-end 0))
331    string))
332
333(defconst singular-remove-prompt-regexp
334  (concat "^" singular-extended-prompt-regexp
335          "*" singular-extended-prompt-regexp)
336  "Matches a non-empty sequence of prompts at start of a line.")
337
338(defun singular-remove-prompt (beg end)
339  "Remove all superfluous prompts from region between BEG and END.
340Removes all but the last prompt of a sequence if that sequence ends at
341END.
342The region between BEG and END should be accessible.
343Leaves point after the last prompt found."
344  (let ((end (copy-marker end))
345        prompt-end)
346    (goto-char beg)
347    (while (and (setq prompt-end
348                      (re-search-forward singular-remove-prompt-regexp end t))
349                (not (= end prompt-end)))
350      (delete-region (match-beginning 0) prompt-end))
351
352    ;; check for trailing prompt
353    (if prompt-end
354        (delete-region (match-beginning 0)  (match-beginning 2)))
355    (set-marker end nil)))
356
357(defconst singular-skip-prompt-forward-regexp
358  (concat singular-extended-prompt-regexp "*")
359  "Matches an arbitary sequence of Singular prompts.")
360
361(defun singular-skip-prompt-forward ()
362  "Skip forward over prompts."
363  (looking-at singular-skip-prompt-forward-regexp)
364  (goto-char (match-end 0)))
365
366(defun singular-skip-prompt-backward ()
367  "Skip backward over prompts."
368  (while (re-search-backward singular-extended-prompt-regexp (- (point) 2) t)))
369;;}}}
370
371;;{{{ Simple section stuff for both Emacs and XEmacs
372
373;; Note:
374;;
375;; Sections and simple sections are used to mark Singular's input and
376;; output for further access.  Here are some general notes on simple
377;; sections.  Sections are explained in the respective folding.
378;;
379;; In general, simple sections are more or less Emacs' overlays or XEmacs
380;; extents, resp.  But they are more than simply an interface to overlays
381;; or sections.
382;;
383;; - Simple sections are non-empty portions of text.  They are interpreted
384;;   as left-closed, right-opened intervals, i.e., the start point of a
385;;   simple sections belongs to it whereas the end point does not.
386;; - Simple sections start and end at line borders only.
387;; - Simple sections do not overlap.  Thus, any point in the buffer may be
388;;   covered by at most one simple section.
389;; - Besides from their start and their end, simple sections have some type
390;;   associated.
391;; - Simple sections are realized using overlays (extents for XEmacs)
392;;   which define the start and, end, and type (via properties) of the
393;;   simple section.  Actually, as a lisp object a simple section is
394;;   nothing else but the underlying overlay.
395;; - There may be so-called clear simple sections.  Clear simple sections
396;;   have not an underlying overlay.  Instead, they start at the end of the
397;;   preceding non-clear simple section, end at the beginning of the next
398;;   non-clear simple section, and have the type defined by
399;;   `singular-simple-sec-clear-type'.  Clear simple sections are
400;;   represented by nil.
401;; - Buffer narrowing does not restrict the extent of completely or
402;;   partially inaccessible simple sections.  But one should note that
403;;   some of the functions assume that there is no narrowing in
404;;   effect.
405;; - After creation, simple sections are not modified any further.
406;;
407;; - In `singular-interactive-mode', the whole buffer is covered with
408;;   simple sections from the very beginning of the file up to the
409;;   beginning of the line containing the last input or output.  The
410;;   remaining text up to `(point-max)' may be interpreted as covered by
411;;   one clear simple section.  Thus, it is most reasonable to define
412;;   `input' to be the type of clear simple sections.
413
414(defvar singular-simple-sec-clear-type 'input
415  "Type of clear simple sections.
416If nil no clear simple sections are used.")
417
418(defvar singular-simple-sec-last-end nil
419  "Marker at the end of the last simple section.
420Should be initialized by `singular-simple-sec-init' before any calls to
421`singular-simple-sec-create' are done.
422
423This variable is buffer-local.")
424
425(defun singular-simple-sec-init (pos)
426  "Initialize global variables belonging to simple section management.
427Creates the buffer-local marker `singular-simple-sec-last-end' and
428initializes it to POS."
429  (make-local-variable 'singular-simple-sec-last-end)
430  (if (not (markerp singular-simple-sec-last-end))
431      (setq singular-simple-sec-last-end (make-marker)))
432  (set-marker singular-simple-sec-last-end pos))
433
434;; Note:
435;;
436;; The rest of the folding is either marked as
437;; Emacs
438;; or
439;; XEmacs
440
441(singular-fset 'singular-simple-sec-create
442               'singular-emacs-simple-sec-create
443               'singular-xemacs-simple-sec-create)
444
445(singular-fset 'singular-simple-sec-reset-last
446               'singular-emacs-simple-sec-reset-last
447               'singular-xemacs-simple-sec-reset-last)
448
449(singular-fset 'singular-simple-sec-start
450               'singular-emacs-simple-sec-start
451               'singular-xemacs-simple-sec-start)
452
453(singular-fset 'singular-simple-sec-end
454               'singular-emacs-simple-sec-end
455               'singular-xemacs-simple-sec-end)
456
457(singular-fset 'singular-simple-sec-start-at
458               'singular-emacs-simple-sec-start-at
459               'singular-xemacs-simple-sec-start-at)
460
461(singular-fset 'singular-simple-sec-end-at
462               'singular-emacs-simple-sec-end-at
463               'singular-xemacs-simple-sec-end-at)
464
465(singular-fset 'singular-simple-sec-type
466               'singular-emacs-simple-sec-type
467               'singular-xemacs-simple-sec-type)
468
469(singular-fset 'singular-simple-sec-at
470               'singular-emacs-simple-sec-at
471               'singular-xemacs-simple-sec-at)
472
473(singular-fset 'singular-simple-sec-before
474               'singular-emacs-simple-sec-before
475               'singular-xemacs-simple-sec-before)
476
477(singular-fset 'singular-simple-sec-in
478               'singular-emacs-simple-sec-in
479               'singular-xemacs-simple-sec-in)
480;;}}}
481
482;;{{{ Simple section stuff for Emacs
483(defun singular-emacs-simple-sec-create (type end)
484  "Create a new simple section of type TYPE.
485Creates the section from end of previous simple section up to END.
486END should be larger than `singular-simple-sec-last-end'.
487Returns the new simple section or `empty' if no simple section has
488been created.
489Assumes that no narrowing is in effect.
490Updates `singular-simple-sec-last-end'."
491  (let ((last-end (marker-position singular-simple-sec-last-end))
492        ;; `simple-sec' is the new simple section or `empty'
493        simple-sec)
494
495    ;; get beginning of line before END.  At this point we need that there
496    ;; are no restrictions.
497    (setq end (let ((old-point (point)))
498                (goto-char end) (beginning-of-line)
499                (prog1 (point) (goto-char old-point))))
500
501    (cond
502     ;; do not create empty sections
503     ((eq end last-end) (setq simple-sec 'empty))
504     ;; create only non-clear simple sections
505     ((not (eq type singular-simple-sec-clear-type))
506      ;; if type has not changed we only have to extend the previous
507      ;; simple section
508      (setq simple-sec (singular-emacs-simple-sec-before last-end))
509      (if (eq type (singular-emacs-simple-sec-type simple-sec))
510          ;; move existing overlay
511          (setq simple-sec (move-overlay simple-sec (overlay-start simple-sec) end))
512        ;; create new overlay
513        (setq simple-sec (make-overlay last-end end))
514        ;; set type property
515        (overlay-put simple-sec 'singular-type type)
516        ;; set face
517        (overlay-put simple-sec 'face (singular-lookup-face type))
518        ;; evaporate empty sections
519        (overlay-put simple-sec 'evaporate t))))
520           
521    ;; update end of last simple section
522    (set-marker singular-simple-sec-last-end end)
523    simple-sec))
524
525(defun singular-emacs-simple-sec-reset-last (pos)
526  "Reset end of last simple section to POS after accidental extension.
527Updates `singular-simple-sec-last-end', too."
528  (let ((simple-sec (singular-emacs-simple-sec-at pos)))
529    (if simple-sec (move-overlay simple-sec (overlay-start simple-sec) pos))
530    (set-marker singular-simple-sec-last-end pos)))
531
532(defun singular-emacs-simple-sec-start (simple-sec)
533  "Return start of non-clear simple section SIMPLE-SEC."
534  (overlay-start simple-sec))
535
536(defun singular-emacs-simple-sec-end (simple-sec)
537  "Return end of non-clear simple section SIMPLE-SEC."
538  (overlay-end simple-sec))
539
540(defun singular-emacs-simple-sec-start-at (pos)
541  "Return start of clear section at position POS.
542Assumes that no narrowing is in effect."
543  (let ((previous-overlay-change (1+ (point))))
544    ;; this `while' loop at last will run into the end of the next
545    ;; non-clear overlay or stop at bob.  Since POS may be right at the end
546    ;; of a previous non-clear location, we have to search at least one
547    ;; time from POS+1 backwards.
548    (while (not (or (singular-emacs-simple-sec-before previous-overlay-change)
549                    (eq previous-overlay-change (point-min))))
550      (setq previous-overlay-change
551            (previous-overlay-change previous-overlay-change)))
552    previous-overlay-change))
553
554(defun singular-emacs-simple-sec-end-at (pos)
555  "Return end of clear section at position POS.
556Assumes that no narrowing is in effect."
557  (let ((next-overlay-change (next-overlay-change (point))))
558    ;; this `while' loop at last will run into the beginning of the next
559    ;; non-clear overlay or stop at eob.  Since POS may not be at the
560    ;; beginning of a non-clear simple section we may start searching
561    ;; immediately.
562    (while (not (or (singular-emacs-simple-sec-at next-overlay-change)
563                    (eq next-overlay-change (point-max))))
564      (setq next-overlay-change
565            (next-overlay-change next-overlay-change)))
566    next-overlay-change))
567
568(defun singular-emacs-simple-sec-type (simple-sec)
569  "Return type of SIMPLE-SEC."
570  (if simple-sec
571      (overlay-get simple-sec 'singular-type)
572    singular-simple-sec-clear-type))
573
574(defun singular-emacs-simple-sec-at (pos)
575  "Return simple section at position POS."
576  (let ((overlays (overlays-at pos)) simple-sec)
577    ;; be careful, there may be other overlays!
578    (while (and overlays (not simple-sec))
579      (if (singular-emacs-simple-sec-type (car overlays))
580          (setq simple-sec (car overlays)))
581      (setq overlays (cdr overlays)))
582    simple-sec))
583
584(defun singular-emacs-simple-sec-before (pos)
585  "Return simple section before position POS.
586This is the same as `singular-simple-section-at' except if POS falls
587on a section border.  In this case `singular-simple-section-before'
588returns the previous simple section instead of the current one."
589  (singular-emacs-simple-sec-at (max 1 (1- pos))))
590
591(defun singular-emacs-simple-sec-in (beg end)
592  "Return a list of all simple sections intersecting with the region from BEG to END.
593A simple section intersects the region if the section and the region
594have at least one character in common.
595The result contains both clear and non-clear simple sections in the
596order in that the appear in the region."
597  ;; NOT READY
598  nil)
599;;}}}
600
601;;{{{ Simple section stuff for XEmacs
602(defun singular-xemacs-simple-sec-create (type end)
603  "Create a new simple section of type TYPE.
604Creates the section from end of previous simple section up to END.
605END should be larger than `singular-simple-sec-last-end'.
606Returns the new simple section or `empty' if no simple section has
607been created.
608Assumes that no narrowing is in effect.
609Updates `singular-simple-sec-last-end'."
610  (let ((last-end (marker-position singular-simple-sec-last-end))
611        ;; `simple-sec' is the new simple section or `empty'
612        simple-sec)
613
614    ;; get beginning of line before END.  At this point we need that there
615    ;; are no restrictions.
616    (setq end (let ((old-point (point)))
617                (goto-char end) (beginning-of-line)
618                (prog1 (point) (goto-char old-point))))
619
620    (cond
621     ;; do not create empty sections
622     ((eq end last-end) (setq simple-sec 'empty))
623     ;; create only non-clear simple sections
624     ((not (eq type singular-simple-sec-clear-type))
625      ;; if type has not changed we only have to extend the previous
626      ;; simple section
627      (setq simple-sec (singular-xemacs-simple-sec-before last-end))
628      (if (eq type (singular-xemacs-simple-sec-type simple-sec))
629          ;; move existing extent
630          (setq simple-sec (set-extent-endpoints simple-sec 
631                                                 (extent-start-position simple-sec) end))
632        ;; create new extent
633        (setq simple-sec (make-extent last-end end))
634        ;; set type property
635        (set-extent-property simple-sec 'singular-type type)
636        ;; set face
637        (set-extent-property simple-sec 'face (singular-lookup-face type)))))
638           
639    ;; update end of last simple section
640    (set-marker singular-simple-sec-last-end end)
641    simple-sec))
642
643(defun singular-xemacs-simple-sec-reset-last (pos)
644  "Reset end of last simple section to POS after accidental extension.
645Updates `singular-simple-sec-last-end', too."
646  (let ((simple-sec (singular-xemacs-simple-sec-at pos)))
647    (if simple-sec 
648        (set-extent-endpoints simple-sec (extent-start-position simple-sec) pos))
649    (set-marker singular-simple-sec-last-end pos)))
650
651(defun singular-xemacs-simple-sec-start (simple-sec)
652  "Return start of non-clear simple section SIMPLE-SEC."
653  (extent-start-position simple-sec))
654
655(defun singular-xemacs-simple-sec-end (simple-sec)
656  "Return end of non-clear simple section SIMPLE-SEC."
657  (extent-end-position simple-sec))
658
659(defun singular-xemacs-simple-sec-start-at (pos)
660  "Return start of clear section at position POS.
661Assumes that no narrowing is in effect."
662  (let ((previous-extent-change (1+ (point))))
663    ;; this `while' loop at last will run into the end of the next
664    ;; non-clear extent or stop at bob.  Since POS may be right at the end
665    ;; of a previous non-clear location, we have to search at least one
666    ;; time from POS+1 backwards.
667    (while (not (or (singular-xemacs-simple-sec-before previous-extent-change)
668                    (eq previous-extent-change (point-min))))
669      (setq previous-extent-change
670            (previous-extent-change previous-extent-change)))
671    previous-extent-change))
672
673(defun singular-xemacs-simple-sec-end-at (pos)
674  "Return end of clear section at position POS.
675Assumes that no narrowing is in effect."
676  (let ((next-extent-change (next-extent-change (point))))
677    ;; this `while' loop at last will run into the beginning of the next
678    ;; non-clear extent or stop at eob.  Since POS may not be at the
679    ;; beginning of a non-clear simple section we may start searching
680    ;; immediately.
681    (while (not (or (singular-xemacs-simple-sec-at next-extent-change)
682                    (eq next-extent-change (point-max))))
683      (setq next-extent-change
684            (next-extent-change next-extent-change)))
685    next-extent-change))
686
687(defun singular-xemacs-simple-sec-type (simple-sec)
688  "Return type of SIMPLE-SEC."
689  (if simple-sec
690      (extent-property simple-sec 'singular-type)
691    singular-simple-sec-clear-type))
692
693(defun singular-xemacs-simple-sec-at (pos)
694  "Return simple section at position POS."
695  (map-extents (function (lambda (ext args) ext))
696               ;; is this pos-pos-region OK? I think so.
697               (current-buffer) pos pos nil nil 'singular-type))
698
699(defun singular-xemacs-simple-sec-before (pos)
700  "Return simple section before position POS.
701This is the same as `singular-simple-section-at' except if POS falls
702on a section border.  In this case `singular-simple-section-before'
703returns the previous simple section instead of the current one."
704  (singular-xemacs-simple-sec-at (max 1 (1- pos))))
705
706(defun singular-xemacs-simple-sec-in (beg end)
707  "Return a list of all simple sections intersecting with the region from BEG to END.
708A simple section intersects the region if the section and the region
709have at least one character in common.
710The result contains both clear and non-clear simple sections in the
711order they appear in the region."
712  ;; NOT READY
713  nil)
714;;}}}
715
716;;{{{ Section stuff
717
718;; Note:
719;;
720;; Sections are built on simple sections.  Their purpose is to cover the
721;; difference between clear and non-clear simple sections.
722;;
723;; - Sections consist of a simple section, its type, and its start and end
724;;   points.  This is redundant information only in the case of non-clear
725;;   simple section.
726;; - Sections are read-only objects, neither are they modified nor are they
727;;   created.
728;; - Buffer narrowing does not restrict the extent of completely or
729;;   partially inaccessible sections.  In contrast to simple sections
730;;   the functions concerning sections do not assume that there is no
731;;   narrowing in effect.
732;; - Sections are independent from implementation dependencies.  There are
733;;   no different versions of the functions for Emacs and XEmacs.
734
735(defun singular-section-at (pos &optional restricted)
736  "Return section at position POS.
737Returns section intersected with current restriction if RESTRICTED is
738non-nil."
739  (let* ((simple-sec (singular-simple-sec-at pos))
740         (type (singular-simple-sec-type simple-sec))
741         start end)
742    (if simple-sec
743        (setq start (singular-simple-sec-start simple-sec)
744              end  (singular-simple-sec-end simple-sec))
745      (save-restriction
746        (widen)
747        (setq start (singular-simple-sec-start-at pos)
748              end (singular-simple-sec-end-at pos))))
749    (if restricted
750        (vector simple-sec type
751                (max start (point-min)) (min end (point-max)))
752      (vector simple-sec type start end))))
753
754(defun singular-section-before (pos &optional restricted)
755  "Return section before position POS.
756This is the same as `singular-section-at' except if POS falls on a
757section border.  In this case `singular-section-before' returns the
758previous section instead of the current one.
759Returns section intersected with current restriction if RESTRICTED is
760non-nil."
761  (singular-section-at (max 1 (1- pos)) restricted))
762
763(defmacro singular-section-simple-sec (section)
764  "Return underlying simple section of SECTION."
765  `(aref ,section 0))
766
767(defmacro singular-section-type (section)
768  "Return type of SECTION."
769  `(aref ,section 1))
770
771(defmacro singular-section-start (section)
772  "Return start of SECTION."
773  `(aref ,section 2))
774
775(defmacro singular-section-end (section)
776  "Return end of SECTION."
777  `(aref ,section 3))
778;;}}}
779
780;;{{{ Getting section contents
781(defun singular-input-section-to-string (section &optional end raw)
782  "Get content of SECTION as string.
783Returns text between start of SECTION and END if optional argument END
784is non-nil.  END should be a position inside SECTION.
785Strips leading prompts and trailing white space unless optional argument
786RAW is non-nil."
787  (save-restriction
788    (widen)
789    (let ((string (if end
790                      (buffer-substring (singular-section-start section) end)
791                    (buffer-substring (singular-section-start section)
792                                      (singular-section-end section)))))
793      (if raw string
794        (singular-strip-leading-prompt
795         (singular-strip-white-space string t))))))
796;;}}}
797
798;;{{{ Last input and output section
799(defun singular-last-input-section (&optional no-error)
800  "Return last input section.
801Returns nil if optional argument NO-ERROR is non-nil and there is no
802last input section defined, throws an error otherwise."
803  (let ((last-input-start (marker-position singular-last-input-section-start))
804        (last-input-end (marker-position singular-current-output-section-start)))
805    (cond ((and last-input-start last-input-end)
806           (vector (singular-simple-sec-at last-input-start) 'input
807                   last-input-start last-input-end))
808          (no-error nil)
809          (t (error "No last input section defined")))))
810
811(defun singular-current-output-section (&optional no-error)
812  "Return current output section.
813Returns nil if optional argument NO-ERROR is non-nil and there is no
814current output section defined, throws an error otherwise."
815  (let ((current-output-start (marker-position singular-current-output-section-start))
816        (current-output-end (save-excursion
817                              (goto-char (singular-process-mark))
818                              (singular-skip-prompt-backward)
819                              (and (bolp) (point)))))
820    (cond ((and current-output-start current-output-end)
821           (vector (singular-simple-sec-at current-output-start) 'output
822                   current-output-start current-output-end))
823          (no-error nil)
824          (t (error "No current output section defined")))))
825
826(defun singular-last-output-section (&optional no-error)
827  "Return last output section.
828Returns nil if optional argument NO-ERROR is non-nil and there is no
829last output section defined, throws an error otherwise."
830  (let ((last-output-start (marker-position singular-last-output-section-start))
831        (last-output-end (marker-position singular-last-input-section-start)))
832    (cond ((and last-output-start last-output-end)
833           (vector (singular-simple-sec-at last-output-start) 'output
834                   last-output-start last-output-end))
835          (no-error nil)
836          (t (error "No last output section defined")))))
837
838(defun singular-latest-output-section (&optional no-error)
839  "Return latest output section.
840This is the current output section if it is defined, otherwise the
841last output section.
842Returns nil if optional argument NO-ERROR is non-nil and there is no
843latest output section defined, throws an error otherwise."
844  (or (singular-current-output-section t)
845      (singular-last-output-section t)
846      (if no-error
847          nil
848        (error "No latest output section defined"))))
849;;}}}
850
851;;{{{ Folding sections
852(defvar singular-folding-ellipsis "Singular I/O ..."
853  "Ellipsis to show for folded input or output.")
854
855(defun singular-fold-internal (start end fold)
856  "(Un)fold region from START to END.
857Folds if FOLD is non-nil, otherwise unfolds.
858Folding affects undo information and buffer modified flag.
859Assumes that there is no narrowing in effect."
860  (save-excursion
861    (if fold
862        (progn
863          (goto-char start) (insert ?\r)
864          (subst-char-in-region start end ?\n ?\r t))
865      (subst-char-in-region start end ?\r ?\n t)
866      (goto-char start) (delete-char 1))))
867
868(defun singular-section-foldedp (section)
869  "Return t iff SECTION is folded.
870Assumes that there is no narrowing in effect."
871  (eq (char-after (singular-section-start section)) ?\r))
872
873(defun singular-fold-section (section)
874  "\(Un)fold SECTION.
875\(Un)folds section at point and goes to beginning of section if called
876interactively.
877Unfolds folded sections and folds unfolded sections."
878  (interactive (list (singular-section-at (point))))
879  (let ((start (singular-section-start section))
880        ;; we have to save restrictions this way since we change text
881        ;; outside the restriction.  Note that we do not use a marker for
882        ;; `old-point-min'.  This way, even partial narrowed sections are
883        ;; folded properly if they have been narrowed at bol.  Nice but
884        ;; dirty trick: The insertion of a `?\r' at beginning of section
885        ;; advances the beginning of the restriction such that it displays
886        ;; the `?\r' immediately before bol.  Seems worth it.
887        (old-point-min (point-min))
888        (old-point-max (point-max-marker)))
889    (unwind-protect
890        (progn
891          (widen)
892          (singular-fold-internal start (singular-section-end section)
893                                  (not (singular-section-foldedp section))))
894      ;; this is unwide-protected
895      (narrow-to-region old-point-min old-point-max)
896      (set-marker old-point-max nil))
897    (if (interactive-p) (goto-char (max start (point-min))))))
898;;}}}
899
900;;{{{ Input and output filters
901
902;; debugging filters
903(defun singular-debug-pre-input-filter (string)
904  "Display STRING and some markers in mini-buffer."
905  (singular-debug 'interactive-filter
906                  (message "Pre-input filter: %s"
907                           (singular-debug-format string)))
908  (singular-debug 'interactive-filter
909                  (message "Pre-input filter: (li %S ci %S lo %S co %S)"
910                           (marker-position singular-last-input-section-start)
911                           (marker-position singular-current-input-section-start)
912                           (marker-position singular-last-output-section-start)
913                           (marker-position singular-current-output-section-start)))
914  nil)
915
916(defun singular-debug-post-input-filter (beg end)
917  "Display BEG, END, and some markers in mini-buffer."
918  (singular-debug 'interactive-filter
919                  (message "Post-input filter: (beg %S end %S)" beg end))
920  (singular-debug 'interactive-filter
921                  (message "Post-input filter: (li %S ci %S lo %S co %S)"
922                           (marker-position singular-last-input-section-start)
923                           (marker-position singular-current-input-section-start)
924                           (marker-position singular-last-output-section-start)
925                           (marker-position singular-current-output-section-start))))
926
927(defun singular-debug-pre-output-filter (string)
928  "Display STRING and some markers in mini-buffer."
929  (singular-debug 'interactive-filter
930                  (message "Pre-output filter: %s"
931                           (singular-debug-format string)))
932  (singular-debug 'interactive-filter
933                  (message "Pre-output filter: (li %S ci %S lo %S co %S)"
934                           (marker-position singular-last-input-section-start)
935                           (marker-position singular-current-input-section-start)
936                           (marker-position singular-last-output-section-start)
937                           (marker-position singular-current-output-section-start)))
938  nil)
939
940(defun singular-debug-post-output-filter (beg end simple-sec-start)
941  "Display BEG, END, SIMPLE-SEC-START, and some markers in mini-buffer."
942  (singular-debug 'interactive-filter
943                  (message "Post-output filter: (beg %S end %S sss %S)"
944                           beg end simple-sec-start))
945  (singular-debug 'interactive-filter
946                  (message "Post-output filter: (li %S ci %S lo %S co %S)"
947                           (marker-position singular-last-input-section-start)
948                           (marker-position singular-current-input-section-start)
949                           (marker-position singular-last-output-section-start)
950                           (marker-position singular-current-output-section-start))))
951
952;; stripping prompts
953(defun singular-remove-prompt-filter (beg end simple-sec-start)
954  "Strip prompts from last simple section."
955  (if simple-sec-start (singular-remove-prompt simple-sec-start end)))
956;;}}}
957
958;;{{{ Demo mode
959(defvar singular-demo-chunk-regexp "\\(\n\n\\)"
960  "Regular expressions to recognize chunks of a demo file.
961If there is a subexpression specified its content is removed when the
962chunk is displayed.")
963
964(defvar singular-demo-mode nil
965  "Non-nil if Singular demo mode is on.
966
967This variable is buffer-local.")
968
969(defvar singular-demo-old-mode-name nil
970  "Used to store previous `mode-name' before switching to demo mode.
971
972This variable is buffer-local.")
973
974(defvar singular-demo-end nil
975  "Marker pointing to end of demo file.
976
977This variable is buffer-local.")
978
979(defvar singular-demo-command-on-enter nil
980  "Singular command to send when entering demo mode or nil if no string to send.")
981
982(defvar singular-demo-command-on-leave nil
983  "Singular command to send when leaving demo mode or nil if no string to send.")
984 
985(defun singular-demo-mode (mode)
986  "Switch between demo mode states.
987MODE may be either:
988- `init' to initialize global variables;
989- `exit' to clean up demo and leave Singular demo mode;
990- `enter' to enter Singular demo mode;
991- `leave' to leave Singular demo mode.
992
993Modifies the global variables `singular-demo-mode',
994`singular-demo-end', and `singular-demo-old-mode-name' to reflect the
995new state of Singular demo mode."
996  (cond
997   ;; initialization.  Should be called only once.
998   ((eq mode 'init)
999    (make-local-variable 'singular-demo-mode)
1000    (make-local-variable 'singular-demo-mode-old-name)
1001    (make-local-variable 'singular-demo-mode-end)
1002    (if (not (and (boundp 'singular-demo-end)
1003                  singular-demo-end))
1004        (setq singular-demo-end (make-marker))))
1005
1006   ;; final exit.  Clean up demo.
1007   ((and (eq mode 'exit)
1008         singular-demo-mode)
1009    (setq mode-name singular-demo-old-mode-name
1010          singular-demo-mode nil)
1011    ;; clean up hidden rest of demo file if existent
1012    (let ((old-point-min (point-min))
1013          (old-point-max (point-max)))
1014      (unwind-protect
1015          (progn
1016            (widen)
1017            (delete-region old-point-max singular-demo-end))
1018        ;; this is unwide-protected
1019        (narrow-to-region old-point-min old-point-max)))
1020    (if (and singular-demo-command-on-leave
1021             (singular-process))
1022        (send-string (singular-process) singular-demo-command-on-leave))
1023    (force-mode-line-update))
1024
1025   ;; enter demo mode
1026   ((and (eq mode 'enter)
1027         (not singular-demo-mode))
1028    (setq singular-demo-old-mode-name mode-name
1029          mode-name "Singular Demo"
1030          singular-demo-mode t)
1031    (if singular-demo-command-on-enter
1032        (send-string (singular-process) singular-demo-command-on-enter))
1033    (force-mode-line-update))
1034
1035   ;; leave demo mode
1036   ((and (eq mode 'leave)
1037         singular-demo-mode)
1038    (setq mode-name singular-demo-old-mode-name
1039          singular-demo-mode nil)
1040    (if singular-demo-command-on-leave
1041        (send-string (singular-process) singular-demo-command-on-leave))
1042    (force-mode-line-update))))
1043
1044(defun singular-demo-exit ()
1045  "Prematurely exit singular demo mode."
1046  (interactive)
1047  (singular-demo-mode 'exit))
1048
1049(defun singular-demo-show-next-chunk ()
1050  "Show next chunk of demo file at input prompt.
1051Moves point to end of buffer and widenes the buffer such that the next
1052chunk of the demo file becomes visible.
1053Finds and removes chunk separators as specified by
1054`singular-demo-chunk-regexp'.
1055Removing chunk separators affects undo information and buffer-modified
1056flag.
1057Leaves demo mode after showing last chunk."
1058  (let ((old-point-min (point-min)))
1059    (unwind-protect
1060        (progn
1061          (goto-char (point-max))
1062          (widen)
1063          (if (re-search-forward singular-demo-chunk-regexp singular-demo-end 'limit)
1064              (and (match-beginning 1)
1065                   (delete-region (match-beginning 1) (match-end 1)))
1066            ;; remove trailing white-space
1067            (skip-syntax-backward "-")
1068            (delete-region (point) singular-demo-end)
1069            (singular-demo-mode 'leave)))
1070
1071      ;; this is unwind-protected
1072      (narrow-to-region old-point-min (point)))))
1073
1074(defun singular-demo-load (demo-file)
1075  "Load demo file DEMO-FILE and enter Singular demo mode.
1076For a description of the Singular demo mode one should refer to the
1077doc-string of `singular-interactive-mode'.
1078Moves point to end of buffer and inserts contents of DEMO-FILE there."
1079  (interactive "fLoad demo file: ")
1080
1081  ;; check for running demo
1082  (and singular-demo-mode
1083       (error "Another demo is already running"))
1084
1085  (let ((old-point-min (point-min)))
1086    (unwind-protect
1087        (progn
1088          (goto-char (point-max))
1089          (widen)
1090          ;; load file and remember its end
1091          (set-marker singular-demo-end
1092                      (+ (point) (nth 1 (insert-file-contents demo-file)))))
1093
1094      ;; completely hide demo file.
1095      ;; This is unwide protected.
1096      (narrow-to-region old-point-min (point)))
1097
1098    ;; switch demo mode on
1099    (singular-demo-mode 'enter)))
1100;;}}}
1101     
1102;;{{{ Some lengthy notes on input and output
1103
1104;; NOT READY[so sorry]!
1105
1106;;}}}
1107
1108;;{{{ Sending input
1109(defvar singular-pre-input-filter-functions nil
1110  "Functions to call before input is sent to process.
1111These functions get one argument, a string containing the text which
1112is to be sent to process.  The functions should return either nil
1113or a string.  In the latter case the returned string replaces the
1114string to be sent to process.
1115
1116This is a buffer-local variable, not a buffer-local hook!
1117
1118`singular-run-hook-with-arg-and-value' is used to run the functions in
1119the list.")
1120
1121(defvar singular-post-input-filter-functions nil
1122  "Functions to call after input is sent to process.
1123These functions get two arguments BEG and END.
1124If `singular-input-filter' has been called with a string as argument
1125BEG and END gives the position of this string after insertion into the
1126buffer.
1127If `singular-input-filter' has been called with a position as argument
1128BEG and END equal process mark and that position, resp.
1129The functions may assume that no narrowing is in effect and may change
1130point at will.
1131
1132This hook is buffer-local.")
1133
1134(defvar singular-current-input-section-start nil
1135  "Marker to the start of the current input section.
1136This marker points nowhere on startup or if there is no current input
1137section.
1138
1139This variable is buffer-local.")
1140
1141(defvar singular-last-input-section-start nil
1142  "Marker to the start of the last input section.
1143This marker points nowhere on startup.
1144
1145This variable is buffer-local.")
1146
1147(defun singular-input-filter-init (pos)
1148  "Initialize all variables concerning input.
1149POS is the position of the process mark."
1150  ;; localize variables not yet localized in `singular-interactive-mode'
1151  (make-local-variable 'singular-current-input-section-start)
1152  (make-local-variable 'singular-last-input-section-start)
1153
1154  ;; initialize markers
1155  (if (not (markerp singular-current-input-section-start))
1156      (setq singular-current-input-section-start (make-marker)))
1157  (if (not (markerp singular-last-input-section-start))
1158      (setq singular-last-input-section-start (make-marker))))
1159
1160(defun singular-send-string (process string)
1161  "Send newline terminated STRING to to process PROCESS.
1162Runs the hooks on `singular-pre-input-filter-functions' in the buffer
1163associated to PROCESS.  The functions get the non-terminated string."
1164  (let ((process-buffer (process-buffer process)))
1165
1166    ;; check whether buffer is still alive
1167    (if (and process-buffer (buffer-name process-buffer))
1168        (save-excursion
1169          (set-buffer process-buffer)
1170          (send-string
1171           process
1172           (concat (singular-run-hook-with-arg-and-value
1173                    singular-pre-input-filter-functions string)
1174                   "\n"))))))
1175
1176(defun singular-input-filter (process string-or-pos)
1177  "Insert/update input from user in buffer associated to PROCESS.
1178Inserts STRING-OR-POS followed by a newline at process mark if it is a
1179string.
1180Assumes that the input is already inserted and that it is placed
1181between process mark and STRING-OR-POS if the latter is a position.
1182Inserts a newline after STRING-OR-POS.
1183
1184Takes care off:
1185- current buffer as well as point and restriction in buffer associated
1186  with process, even against non-local exits.
1187Updates:
1188- process mark;
1189- current and last sections;
1190- simple sections;
1191- mode line.
1192
1193Runs the hooks on `singular-pre-input-filter-functions' and
1194`singular-post-input-filter-functions'.
1195
1196For a more detailed descriptions of the input filter, the markers it
1197sets, and input filter functions refer to the section \"Some lengthy
1198notes on input and output\" in singular.el."
1199  (let ((process-buffer (process-buffer process)))
1200
1201    ;; check whether buffer is still alive
1202    (if (and process-buffer (buffer-name process-buffer))
1203        (let ((old-buffer (current-buffer))
1204              (old-pmark (marker-position (process-mark process)))
1205              old-point old-point-min old-point-max)
1206          (unwind-protect
1207              (let (simple-sec-start)
1208                (set-buffer process-buffer)
1209                ;; the following lines are not protected since the
1210                ;; unwind-forms refer the variables being set here
1211                (setq old-point (point-marker)
1212                      old-point-min (point-min-marker)
1213                      old-point-max (point-max-marker)
1214
1215                ;; get end of last simple section (equals start of
1216                ;; current)
1217                      simple-sec-start (marker-position singular-simple-sec-last-end))
1218
1219                ;; prepare for insertion
1220                (widen)
1221                (set-marker-insertion-type old-point t)
1222                (set-marker-insertion-type old-point-max t)
1223
1224                ;; insert string at process mark and advance process
1225                ;; mark after insertion.  If it not a string simply
1226                ;; jump to desired position and insrt a newline.
1227                (if (stringp string-or-pos)
1228                    (progn
1229                      (goto-char old-pmark)
1230                      (insert string-or-pos))
1231                  (goto-char string-or-pos))
1232                (insert ?\n)
1233                (set-marker (process-mark process) (point))
1234
1235                ;; create new simple section and update section markers
1236                (cond
1237                 ((eq (singular-simple-sec-create 'input (point)) 'empty)
1238                  nil)
1239                 ;; a new simple section has been created ...
1240                 ((null (marker-position singular-current-input-section-start))
1241                  ;; ... and even a new input section has been created!
1242                  (set-marker singular-current-input-section-start
1243                              simple-sec-start)
1244                  (set-marker singular-last-output-section-start
1245                              singular-current-output-section-start)
1246                  (set-marker singular-current-output-section-start nil)))
1247
1248                ;; run post-output hooks and force mode-line update
1249                (run-hook-with-args 'singular-post-input-filter-functions
1250                                    old-pmark (point)))
1251
1252            ;; restore buffer, restrictions and point
1253            (narrow-to-region old-point-min old-point-max)
1254            (set-marker old-point-min nil)
1255            (set-marker old-point-max nil)
1256            (goto-char old-point)
1257            (set-marker old-point nil)
1258            (set-buffer old-buffer))))))
1259           
1260(defun singular-get-old-input (get-section)
1261  "Retrieve old input.
1262Retrivies from beginning of current section to point if GET-SECTION is
1263non-nil, otherwise on a per-line base."
1264  (if get-section
1265      ;; get input from input section
1266      (let ((section (singular-section-at (point))))
1267        (if (eq (singular-section-type section) 'input)
1268            (setq old-input (singular-input-section-to-string section (point)))
1269          (error "Not on an input section")))
1270    ;; get input from line
1271    (save-excursion
1272      (beginning-of-line)
1273      (singular-skip-prompt-forward)
1274      (let ((old-point (point)))
1275        (end-of-line)
1276        (buffer-substring old-point (point))))))
1277
1278(defun singular-send-or-copy-input (send-full-section)
1279  "Send input from current buffer to associated process.
1280NOT READY[old input copying, demo mode,
1281          eol-on-send, history, SEND-FULL-SECTION]!"
1282  (interactive "P")
1283
1284  (let ((process (get-buffer-process (current-buffer)))
1285        pmark)
1286    ;; some checks and initializations
1287    (or process (error "Current buffer has no process"))
1288    (setq pmark (marker-position (process-mark process)))
1289
1290    (cond
1291     (;; check for demo mode and show next chunk if necessary
1292      (and singular-demo-mode
1293          (eq (point) pmark)
1294          (eq pmark (point-max)))
1295      (singular-demo-show-next-chunk))
1296
1297     (;; get old input
1298      (< (point) pmark)
1299      (let ((old-input (singular-get-old-input send-full-section)))
1300        (goto-char pmark)
1301        (insert old-input)))
1302
1303     (;; send input from pmark to point after doing history expansion
1304      t
1305      ;; go to desired position
1306      (if comint-eol-on-send (end-of-line))
1307      (if send-full-section (goto-char (point-max)))
1308
1309      ;; do history expansion
1310      (if (eq comint-input-autoexpand 'input)
1311          (comint-replace-by-expanded-history t))
1312      (let* ((input (buffer-substring pmark (point))))
1313
1314        ;; insert input into history
1315        (if (and (funcall comint-input-filter input)
1316                 (or (null comint-input-ignoredups)
1317                     (not (ring-p comint-input-ring))
1318                     (ring-empty-p comint-input-ring)
1319                     (not (string-equal (ring-ref comint-input-ring 0) input))))
1320            (ring-insert comint-input-ring input))
1321        (setq comint-input-ring-index nil)
1322
1323        ;; send string to process ...
1324        (singular-send-string process input)
1325        ;; ... and insert it into buffer ...
1326        (singular-input-filter process (point)))))))
1327;;}}}
1328
1329;;{{{ Receiving output
1330(defvar singular-pre-output-filter-functions nil
1331  "Functions to call before output is inserted into the buffer.
1332These functions get one argument, a string containing the text sent
1333from process.  The functions should return either nil or a string.
1334In the latter case the returned string replaces the string sent from
1335process.
1336
1337This is a buffer-local variable, not a buffer-local hook!
1338
1339`singular-run-hook-with-arg-and-value' is used to run the functions in
1340this list.")
1341
1342(defvar singular-post-output-filter-functions nil
1343  "Functions to call after output is inserted into the buffer.
1344These functions get three arguments BEG, END, and SIMPLE-SEC-START.
1345The region between BEG and END is what has been inserted into the
1346buffer.
1347SIMPLE-SEC-START is the start of the simple section which has been
1348created on insertion or nil if no simple section has been created.
1349The functions may assume that no narrowing is in effect and may change
1350point at will.
1351
1352This hook is buffer-local.")
1353
1354(defvar singular-current-output-section-start nil
1355  "Marker to the start of the current output section.
1356This marker points nowhere on startup or if there is no current output
1357section.
1358
1359This variable is buffer-local.")
1360
1361(defvar singular-last-output-section-start nil
1362  "Marker to the start of the last output section.
1363This marker points nowhere on startup.
1364
1365This variable is buffer-local.")
1366
1367(defun singular-output-filter-init (pos)
1368  "Initialize all variables concerning output including process mark.
1369Set process mark to POS."
1370
1371  ;; localize variables not yet localized in `singular-interactive-mode'
1372  (make-local-variable 'singular-current-output-section-start)
1373  (make-local-variable 'singular-last-output-section-start)
1374
1375  ;; initialize markers
1376  (if (not (markerp singular-current-output-section-start))
1377      (setq singular-current-output-section-start (make-marker)))
1378  (if (not (markerp singular-last-output-section-start))
1379      (setq singular-last-output-section-start (make-marker)))
1380  (set-marker (singular-process-mark) pos))
1381
1382(defun singular-output-filter (process string)
1383  "Insert STRING containing output from PROCESS into its associated buffer.
1384Takes care off:
1385- current buffer as well as point and restriction in buffer associated
1386  with process, even against non-local exits.
1387Updates:
1388- process mark;
1389- current and last sections;
1390- simple sections;
1391- mode line.
1392Runs the hooks on `singular-pre-output-filter-functions' and
1393`singular-post-output-filter-functions'.
1394
1395For a more detailed descriptions of the output filter, the markers it
1396sets, and output filter functions refer to the section \"Some lengthy
1397notes on input and output\" in singular.el."
1398  (let ((process-buffer (process-buffer process)))
1399
1400    ;; check whether buffer is still alive
1401    (if (and process-buffer (buffer-name process-buffer))
1402        (let ((old-buffer (current-buffer))
1403              (old-pmark (marker-position (process-mark process)))
1404              old-point old-point-min old-point-max)
1405          (unwind-protect
1406              (let (simple-sec-start)
1407                (set-buffer process-buffer)
1408                ;; the following lines are not protected since the
1409                ;; unwind-forms refer the variables being set here
1410                (setq old-point (point-marker)
1411                      old-point-min (point-min-marker)
1412                      old-point-max (point-max-marker)
1413
1414                ;; get end of last simple section (equals start of
1415                ;; current)
1416                      simple-sec-start (marker-position singular-simple-sec-last-end)
1417
1418                ;; get string to insert
1419                      string (singular-run-hook-with-arg-and-value
1420                              singular-pre-output-filter-functions
1421                              string))
1422
1423                ;; prepare for insertion
1424                (widen)
1425                (set-marker-insertion-type old-point t)
1426                (set-marker-insertion-type old-point-max t)
1427
1428                ;; insert string at process mark and advance process
1429                ;; mark after insertion
1430                (goto-char old-pmark)
1431                (insert string)
1432                (set-marker (process-mark process) (point))
1433
1434                ;; create new simple section and update section markers
1435                (cond
1436                 ((eq (singular-simple-sec-create 'output (point)) 'empty)
1437                  (setq simple-sec-start nil))
1438                 ;; a new simple section has been created ...
1439                 ((null (marker-position singular-current-output-section-start))
1440                  ;; ... and even a new output section has been created!
1441                  (set-marker singular-current-output-section-start
1442                              simple-sec-start)
1443                  (set-marker singular-last-input-section-start
1444                              singular-current-input-section-start)
1445                  (set-marker singular-current-input-section-start nil)))
1446
1447                ;; run post-output hooks and force mode-line update
1448                (run-hook-with-args 'singular-post-output-filter-functions
1449                                    old-pmark (point) simple-sec-start)
1450                (force-mode-line-update))
1451
1452            ;; restore buffer, restrictions and point
1453            (narrow-to-region old-point-min old-point-max)
1454            (set-marker old-point-min nil)
1455            (set-marker old-point-max nil)
1456            (goto-char old-point)
1457            (set-marker old-point nil)
1458            (set-buffer old-buffer))))))
1459;;}}}
1460
1461;;{{{ Singular interactive mode
1462(defun singular-interactive-mode ()
1463  "Major mode for interacting with Singular.
1464
1465NOT READY [how to send input]!
1466
1467NOT READY [multiple Singulars]!
1468
1469\\{singular-interactive-mode-map}
1470Customization: Entry to this mode runs the hooks on `comint-mode-hook'
1471and `singular-interactive-mode-hook' \(in that order).  Before each
1472input, the hooks on `comint-input-filter-functions' are run.  After
1473each Singular output, the hooks on `comint-output-filter-functions'
1474are run.
1475
1476NOT READY [much more to come.  See shell.el.]!"
1477  (interactive)
1478
1479  ;; run comint mode and do basic mode setup
1480  (comint-mode)
1481  (setq major-mode 'singular-interactive-mode)
1482  (setq mode-name "Singular Interaction")
1483  (use-local-map singular-interactive-mode-map)
1484
1485  ;; customize comint for Singular
1486  (setq comint-prompt-regexp singular-prompt-regexp)
1487  (setq comint-delimiter-argument-list singular-delimiter-argument-list)
1488  (setq comint-input-ignoredups singular-input-ignoredups)
1489  (make-local-variable 'comint-buffer-maximum-size)
1490  (setq comint-buffer-maximum-size singular-buffer-maximum-size)
1491  (setq comint-input-ring-size singular-input-ring-size)
1492  (setq comint-input-filter singular-history-filter)
1493
1494  ;; get name of history file (if any)
1495  (setq comint-input-ring-file-name (getenv "SINGULARHIST"))
1496  (if (or (not comint-input-ring-file-name)
1497          (equal comint-input-ring-file-name "")
1498          (equal (file-truename comint-input-ring-file-name) "/dev/null"))
1499      (setq comint-input-ring-file-name nil))
1500
1501  ;; initialize singular demo mode, input and output filters
1502  (singular-demo-mode 'init)
1503  (make-local-variable 'singular-pre-input-filter-functions)
1504  (make-local-hook 'singular-post-input-filter-functions)
1505  (make-local-variable 'singular-pre-output-filter-functions)
1506  (make-local-hook 'singular-post-output-filter-functions)
1507
1508  ;; selective display
1509  (setq selective-display t)
1510  (setq selective-display-ellipses t)
1511  (cond
1512   ;; Emacs
1513   ((eq singular-emacs-flavor 'emacs)
1514    (setq buffer-display-table (or (copy-sequence standard-display-table)
1515                                   (make-display-table)))
1516    (set-display-table-slot buffer-display-table
1517     'selective-display (vconcat singular-folding-ellipsis)))
1518    ;; XEmacs
1519   (t
1520    (set-glyph-image invisible-text-glyph singular-folding-ellipsis (current-buffer))))
1521
1522  ;; debugging filters
1523  (singular-debug 'interactive-filter
1524                  (add-hook 'singular-pre-input-filter-functions
1525                            'singular-debug-pre-input-filter nil t))
1526  (singular-debug 'interactive-filter
1527                  (add-hook 'singular-post-input-filter-functions
1528                            'singular-debug-post-input-filter nil t))
1529  (singular-debug 'interactive-filter
1530                  (add-hook 'singular-pre-output-filter-functions
1531                            'singular-debug-pre-output-filter nil t))
1532  (singular-debug 'interactive-filter
1533                  (add-hook 'singular-post-output-filter-functions
1534                            'singular-debug-post-output-filter nil t))
1535
1536  ;; other input or output filters
1537  (add-hook 'singular-post-output-filter-functions
1538            'singular-remove-prompt-filter nil t)
1539
1540  (run-hooks 'singular-interactive-mode-hook))
1541;;}}}
1542
1543;;{{{ Starting singular
1544(defvar singular-start-file "~/.emacs_singularrc"
1545  "Name of start-up file to pass to Singular.
1546If the file named by this variable exists it is given as initial input
1547to any Singular process being started.  Note that this may lose due to
1548a timing error if Singular discards input when it starts up.")
1549
1550(defvar singular-default-executable "Singular"
1551  "Default name of Singular executable.
1552Used by `singular' when new Singular processes are started.")
1553
1554(defvar singular-default-name "singular"
1555  "Default process name for Singular process.
1556Used by `singular' when new Singular processes are started.")
1557
1558(defvar singular-default-switches '("-t")
1559  "Default switches for Singular processes.
1560Used by `singular' when new Singular processes are started.")
1561
1562(defun singular-exit-sentinel (process message)
1563 "Clean up after termination of Singular.
1564Writes back input ring after regular termination of Singular if
1565process buffer is still alive."
1566  (save-excursion
1567    (singular-debug 'interactive
1568                    (message "Sentinel: %s" (substring message 0 -1)))
1569    ;; exit demo mode if necessary
1570    (singular-demo-mode 'exit)
1571    (if (string-match "finished\\|exited" message)
1572        (let ((process-buffer (process-buffer process)))
1573          (if (and process-buffer
1574                   (buffer-name process-buffer)
1575                   (set-buffer process-buffer))
1576              (progn
1577                (singular-debug 'interactive (message "Writing input ring back"))
1578                (comint-write-input-ring)))))))
1579
1580(defun singular-exec (buffer name executable start-file switches)
1581  "Start a new Singular process NAME in BUFFER, running EXECUTABLE.
1582EXECUTABLE should be a string denoting an executable program.
1583SWITCHES should be a list of strings that are passed as command line
1584switches.  START-FILE should be the name of a file which contents is
1585sent to the process.
1586
1587Deletes any old processes running in that buffer.
1588Moves point to the end of BUFFER.
1589Initializes all important markers and the simple sections.
1590Runs `comint-exec-hook' and `singular-exec-hook' (in that order).
1591Returns BUFFER."
1592  (let ((old-buffer (current-buffer)))
1593    (unwind-protect
1594        (progn
1595          (set-buffer buffer)
1596
1597          ;; delete any old processes
1598          (let ((process (get-buffer-process buffer)))
1599            (if process (delete-process process)))
1600
1601          ;; create new process
1602          (singular-debug 'interactive (message "Starting new Singular"))
1603          (let ((process (comint-exec-1 name buffer executable switches)))
1604
1605            ;; set process filter and sentinel
1606            (set-process-filter process 'singular-output-filter)
1607            (set-process-sentinel process 'singular-exit-sentinel)
1608            (make-local-variable 'comint-ptyp)
1609            (setq comint-ptyp process-connection-type) ; T if pty, NIL if pipe.
1610
1611            ;; go to the end of the buffer, initialize I/O and simple
1612            ;; sections
1613            (goto-char (point-max))
1614            (singular-input-filter-init (point))
1615            (singular-output-filter-init (point))
1616            (singular-simple-sec-init (point))
1617
1618            ;; feed process with start file and read input ring.  Take
1619            ;; care about the undo information.
1620            (if start-file
1621                (let ((buffer-undo-list t) start-string)
1622                  (singular-debug 'interactive (message "Feeding start file"))
1623                  (sleep-for 1)                 ; try to avoid timing errors
1624                  (insert-file-contents start-file)
1625                  (setq start-string (buffer-substring (point) (point-max)))
1626                  (delete-region (point) (point-max))
1627                  (send-string process start-string)))
1628            (singular-debug 'interactive (message "Reading input ring"))
1629            (comint-read-input-ring t)
1630
1631            ;; execute hooks
1632            (run-hooks 'comint-exec-hook)
1633            (run-hooks 'singular-exec-hook))
1634         
1635          buffer)
1636      ;; this code is unwide-protected
1637      (set-buffer old-buffer))))
1638
1639;; Note:
1640;;
1641;; In contrast to shell.el, `singular' does not run
1642;; `singular-interactive-mode' every time a new Singular process is
1643;; started, but only when a new buffer is created.  This behaviour seems
1644;; more intuitive w.r.t. local variables and hooks.
1645
1646(defun singular (&optional executable name switches)
1647  "Run an inferior Singular process, with I/O through an Emacs buffer.
1648
1649NOT READY [arguments, default values, and interactive use]!
1650
1651If buffer exists but Singular is not running, starts new Singular.
1652If buffer exists and Singular is running, just switches to buffer.
1653If a file `~/.emacs_singularrc' exists, it is given as initial input.
1654Note that this may lose due to a timing error if Singular discards
1655input when it starts up.
1656
1657If a new buffer is created it is put in Singular interactive mode,
1658giving commands for sending input and handling ouput of Singular.  See
1659`singular-interactive-mode'.
1660
1661Every time `singular' starts a new Singular process it runs the hooks
1662on `comint-exec-hook' and `singular-exec-hook' \(in that order).
1663
1664Type \\[describe-mode] in the Singular buffer for a list of commands."
1665  ;; handle interactive calls
1666  (interactive (list singular-default-executable
1667                     singular-default-name
1668                     singular-default-switches))
1669
1670  (let* (;; get default values for optional arguments
1671         (executable (or executable singular-default-executable))
1672         (name (or name singular-default-name))
1673         (switches (or switches singular-default-switches))
1674
1675         (buffer-name (singular-process-name-to-buffer-name name))
1676         ;; buffer associated with Singular, nil if there is none
1677         (buffer (get-buffer buffer-name)))
1678
1679    (if (not buffer)
1680        (progn
1681          ;; create new buffer and call `singular-interactive-mode'
1682          (singular-debug 'interactive (message "Creating new buffer"))
1683          (setq buffer (get-buffer-create buffer-name))
1684          (set-buffer buffer)
1685          (singular-debug 'interactive (message "Calling `singular-interactive-mode'"))
1686          (singular-interactive-mode)))
1687
1688    (if (not (comint-check-proc buffer))
1689        ;; create new process if there is none
1690        (singular-exec buffer name executable
1691                       (if (file-exists-p singular-start-file)
1692                           singular-start-file)
1693                       switches))
1694
1695    ;; pop to buffer
1696    (singular-debug 'interactive (message "Calling `pop-to-buffer'"))
1697    (pop-to-buffer buffer)))
1698
1699;; for convenience only
1700(defalias 'Singular 'singular)
1701;;}}}
1702;;}}}
1703
1704(provide 'singular)
1705
1706;;; singular.el ends here.
Note: See TracBrowser for help on using the repository browser.