source: git/emacs/singular.el @ 92b9c5b

spielwiese
Last change on this file since 92b9c5b was 92b9c5b, checked in by Tim Wichmann <wichmann@…>, 26 years ago
* singular.el (singular-demo-mode): changed message text (singular-other): if singular options are read from minibuffer, do not display the "-t" option. Add it automatically. (singular-other): Changed minibuffer text (singular-exit-singular): Added (kill-buffer) git-svn-id: file:///usr/local/Singular/svn/trunk@2454 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 78.0 KB
Line 
1;;; singular.el --- Emacs support for Computer Algebra System Singular
2
3;; $Id: singular.el,v 1.24 1998-08-07 10:07:06 wichmann 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;; Additional faces for font locking
174(make-face 'font-lock-singular-error-face)
175(cond 
176 ;; XEmacs
177 ((eq singular-emacs-flavor 'xemacs)
178  (set-face-foreground 'font-lock-singular-error-face "Red"
179                       'global nil 'append)))
180(defvar font-lock-singular-error-face 'font-lock-singular-error-face
181  "NOT READY [docu]")
182
183(make-face 'font-lock-singular-warn-face)
184(cond
185 ;; XEmacs
186 ((eq singular-emacs-flavor 'xemacs)
187  (set-face-foreground 'font-lock-singular-warn-face "Orange" 
188                       'global nil 'append)))
189(defvar font-lock-singular-warn-face 'font-lock-singular-warn-face
190  "NOT READY [docu]")
191
192(make-face 'font-lock-singular-prompt-face)
193(cond
194 ;; XEmacs
195 ((eq singular-emacs-flavor 'xemacs)
196  (set-face-foreground 'font-lock-singular-prompt-face "Gray50"
197                       'global nil 'append)))
198(defvar font-lock-singular-warn-face 'font-lock-singular-prompt-face
199  "NOT READY [docu]")
200;;}}}
201
202;;{{{ Font-locking
203;(make-regexp '("def" "ideal" "int"  "intmat" "intvec" 
204;              "link" "list" "map" "matrix" "module"
205;              "number" "poly" "proc" "qring" "resolution"
206;              "ring" "string" "vector"))
207
208(defvar singular-font-lock-keywords-1
209  '(
210    ("\\<def\\|i\\(deal\\|nt\\(\\|mat\\|vec\\)\\)\\|li\\(nk\\|st\\)\\|m\\(a\\(p\\|trix\\)\\|odule\\)\\|number\\|p\\(oly\\|roc\\)\\|qring\\|r\\(esolution\\|ing\\)\\|string\\|vector\\>" . font-lock-type-face)
211    ("^\\(> \\|. \\)" . font-lock-singular-prompt-face)
212    ("^   [\\?].*" 0 font-lock-singular-error-face t)
213    ("^// \\(\\*\\*.*\\)" 1 font-lock-singular-warn-face t)
214    )
215  "Subdued level for highlighting in singular-(interactive)-mode")
216
217(defvar singular-font-lock-keywords-2 
218  (append
219   singular-font-lock-keywords-1
220   '(
221     ("^   [\\?].*`\\(\\sw\\sw+\\)`" 1 font-lock-reference-name-face t)
222;;     ()))
223     ))
224  "Gaudy level for highlihgting in singular-(interactive)-mode") 
225
226(defvar singular-font-lock-keywords singular-font-lock-keywords-1
227  "Default highlighting for singular-(interactive)-mode")
228
229(defvar singular-font-lock-defaults 
230  '((singular-font-lock-keywords
231     singular-font-lock-keywords-1
232     singular-font-lock-keywords-2)
233    nil                   ;; KEYWORDS-ONLY
234    nil                   ;; CASE-FOLD (ignore case when non-nil)
235    ((?_ . "w"))          ;; SYNTAX-ALIST
236    (beginning-of-line))  ;; SYNTAX_BEGIN
237  "Emacs-default for font-lock-mode in singular-(interactive)-mode")
238
239(cond 
240 ;; XEmacs
241 ((eq singular-emacs-flavor 'xemacs)
242  (singular-debug 'interactive (message "setting up font-lock for XEmacs"))
243  (put 'singular-interactive-mode 'font-lock-defaults
244       singular-font-lock-defaults)))
245;;}}}
246;;}}}
247
248;;{{{ Singular interactive mode
249;;{{{ Key map and menus
250(defvar singular-interactive-mode-map ()
251  "Key map to use in Singular interactive mode.")
252
253(if singular-interactive-mode-map
254    ()
255  (cond
256   ;; Emacs
257   ((eq singular-emacs-flavor 'emacs)
258    (setq singular-interactive-mode-map
259          (nconc (make-sparse-keymap) comint-mode-map)))
260   ;; XEmacs
261   (t
262    (setq singular-interactive-mode-map (make-keymap))
263    (set-keymap-parents singular-interactive-mode-map (list comint-mode-map))
264    (set-keymap-name singular-interactive-mode-map
265                     'singular-interactive-mode-map)))
266  (define-key singular-interactive-mode-map "\C-m" 'singular-send-or-copy-input)
267  (define-key singular-interactive-mode-map "\C-c\C-f" 'singular-load-file)
268  (define-key singular-interactive-mode-map "\C-c\C-l" 'singular-load-library)
269  (define-key singular-interactive-mode-map "\C-c\C-d" 'singular-demo-load)
270  (define-key singular-interactive-mode-map "\C-c\C-t" 'singular-toggle-truncate-lines)
271  (define-key singular-interactive-mode-map "\C-c$" 'singular-exit-singular)
272  (define-key singular-interactive-mode-map "\C-cfl" 'singular-fold-last-output)
273  (define-key singular-interactive-mode-map "\C-cfa" 'singular-fold-all-output)
274  (define-key singular-interactive-mode-map "\C-cfp" 'singular-fold-at-point)
275  (define-key singular-interactive-mode-map "\C-cul" 'singular-unfold-last-output)
276  (define-key singular-interactive-mode-map "\C-cua" 'singular-unfold-all-output)
277  (define-key singular-interactive-mode-map "\C-cup" 'singular-unfold-at-point))
278
279(defvar singular-interactive-mode-menu-1 nil
280  "NOT READY [docu]")
281
282(defvar singular-interactive-mode-menu-2 nil
283  "NOT READY [docu]")
284
285(defvar singular-start-menu-definition
286  '("Singular"
287    ["start default" singular t]
288    ["start..." singular-other t]
289    ["exit" singular-exit-singular t])
290  "NOT READY [docu]")
291
292(if singular-interactive-mode-menu-1
293    ()
294  (cond
295   ;; XEmacs
296   ((eq singular-emacs-flavor 'xemacs)
297    (easy-menu-define
298     singular-interactive-mode-menu-1
299     singular-interactive-mode-map ""
300     singular-start-menu-definition))))
301
302(if singular-interactive-mode-menu-2
303    ()
304  (cond
305   ;; XEmacs
306   ((eq singular-emacs-flavor 'xemacs)
307    (easy-menu-define 
308     singular-interactive-mode-menu-2
309     singular-interactive-mode-map ""
310     '("Commands"
311       ["load file..." singular-load-file t]
312       ("load library"
313        ["all.lib" (singular-load-library "all.lib" t) t]
314        ["classify.lib" (singular-load-library "classify.lib" t) t]
315        ["deform.lib" (singular-load-library "deform.lib" t) t]
316        ["elim.lib" (singular-load-library "elim.lib" t) t]
317        ["finvar.lib" (singular-load-library "finvar.lib" t) t]
318        ["general.lib" (singular-load-library "general.lib" t) t]
319        ["graphics.lib" (singular-load-library "graphics.lib" t) t]
320        ["hnoether.lib" (singular-load-library "hnoether.lib" t) t]
321        ["homolog.lib" (singular-load-library "homolog.lib" t) t]
322        ["inout.lib" (singular-load-library "inout.lib" t) t]
323        ["invar.lib" (singular-load-library "invar.lib" t) t]
324        ["latex.lib" (singular-load-library "latex.lib" t) t]
325        ["matrix.lib" (singular-load-library "matrix.lib" t) t]
326        ["normal.lib" (singular-load-library "normal.lib" t) t]
327        ["poly.lib" (singular-load-library "poly.lib" t) t]
328        ["presolve.lib" (singular-load-library "presolve.lib" t) t]
329        ["primdec.lib" (singular-load-library "primdec.lib" t) t]
330        ["primitiv.lib" (singular-load-library "primitiv.lib" t) t]
331        ["random.lib" (singular-load-library "random.lib" t) t]
332        ["ring.lib" (singular-load-library "ring.lib" t) t]
333        ["sing.lib" (singular-load-library "sing.lib" t) t]
334        ["standard.lib" (singular-load-library "standard.lib" t) t]
335        "---"
336        ["other..." singular-load-library t])
337       "---"
338       ["load demo" singular-demo-load (not singular-demo-mode)]
339       ["exit demo" singular-demo-exit singular-demo-mode]
340       "---"
341       ["truncate lines" singular-toggle-truncate-lines
342        :style toggle :selected truncate-lines]
343       "---"
344       ["fold last output" singular-fold-last-output t]
345       ["fold all output" singular-fold-all-output t]
346       ["fold at point" singular-fold-at-point t]
347       "---"
348       ["unfold last output" singular-unfold-last-output t]
349       ["unfold all output" singular-unfold-all-output t]
350       ["unfold at point" singular-unfold-at-point t]
351       )))))
352
353;; NOT READY
354;; This is just a temporary hack for XEmacs demo.
355(defvar singular-install-in-main-menu nil
356  "NOT READY [docu]")
357
358(if singular-install-in-main-menu
359    (cond
360     ;; XEmacs
361     ((eq singular-emacs-flavor 'xemacs)
362      (add-submenu nil 
363                   singular-start-menu-definition))))
364
365;;{{{ Syntax table
366(defvar singular-interactive-mode-syntax-table nil
367  "Syntax table for singular-interactive-mode")
368
369(if singular-interactive-mode-syntax-table
370    ()
371  (setq singular-interactive-mode-syntax-table (make-syntax-table))
372  ;; rest taken from cc-mode.el
373  (modify-syntax-entry ?_  "_"     singular-interactive-mode-syntax-table)
374  (modify-syntax-entry ?\\ "\\"    singular-interactive-mode-syntax-table)
375  (modify-syntax-entry ?+  "."     singular-interactive-mode-syntax-table)
376  (modify-syntax-entry ?-  "."     singular-interactive-mode-syntax-table)
377  (modify-syntax-entry ?=  "."     singular-interactive-mode-syntax-table)
378  (modify-syntax-entry ?%  "."     singular-interactive-mode-syntax-table)
379  (modify-syntax-entry ?<  "."     singular-interactive-mode-syntax-table)
380  (modify-syntax-entry ?>  "."     singular-interactive-mode-syntax-table)
381  (modify-syntax-entry ?&  "."     singular-interactive-mode-syntax-table)
382  (modify-syntax-entry ?|  "."     singular-interactive-mode-syntax-table)
383  (modify-syntax-entry ?\' "\""    singular-interactive-mode-syntax-table)
384  (cond
385   ;; Emacs
386   ((eq singular-emacs-flavor 'emacs)
387    (modify-syntax-entry ?/  ". 124b" singular-interactive-mode-syntax-table))
388   ;; XEmacs
389   (t
390    (modify-syntax-entry ?/  ". 1456" singular-interactive-mode-syntax-table)))
391  (modify-syntax-entry ?*  ". 23"   singular-interactive-mode-syntax-table)
392  (modify-syntax-entry ?\n "> b"    singular-interactive-mode-syntax-table)
393  (modify-syntax-entry ?\^m "> b"    singular-interactive-mode-syntax-table))
394
395;;}}}
396
397;;{{{ Miscellaneous
398
399;; Note:
400;;
401;; We assume a one-to-one correspondance between Singular buffers
402;; and Singular processes.  We always have
403;; (equal buffer-name (concat "*" process-name "*")).
404
405(defun singular-buffer-name-to-process-name (buffer-name)
406  "Create the process name for BUFFER-NAME.
407The process name is the buffer name with surrounding `*' stripped
408off."
409  (substring buffer-name 1 -1))
410
411(defun singular-process-name-to-buffer-name (process-name)
412  "Create the buffer name for PROCESS-NAME.
413The buffer name is the process name with surrounding `*'."
414  (concat "*" process-name "*"))
415
416(defun singular-run-hook-with-arg-and-value (hook value)
417  "Call functions on HOOK.
418Provides argument VALUE.  If a function returns a non-nil value it
419replaces VALUE as new argument to the functions.  Returns final
420VALUE."
421  (let (result)
422    (while hook
423      (setq result (funcall (car hook) value))
424      (and result (setq value result))
425      (setq hook (cdr hook)))
426    value))
427
428(defmacro singular-process ()
429  "Return process of current buffer."
430  (get-buffer-process (current-buffer)))
431
432(defmacro singular-process-mark ()
433  "Return process mark of current buffer."
434  (process-mark (get-buffer-process (current-buffer))))
435
436(defun singular-load-file (file &optional noexpand)
437  "docu NOT READY"
438  (interactive "fLoad file: ")
439  (let* ((filename (if noexpand file (expand-file-name file)))
440         (string (concat "< \"" filename "\";"))
441         (process (singular-process)))
442    (singular-input-filter process string)
443    (singular-send-string process string)))
444
445(defun singular-load-library (file &optional noexpand)
446  "docu NOT READY"
447  (interactive "fLoad Library: ")
448  (let* ((filename (if noexpand file (expand-file-name file)))
449         (string (concat "LIB \"" filename "\";"))
450         (process (singular-process)))
451    (singular-input-filter process string)
452    (singular-send-string process string)))
453
454(defun singular-exit-singular ()
455  "NOT READY [docu]"
456  (interactive)
457  (let ((string "quit;")
458        (process (singular-process)))
459    (singular-input-filter process string)
460    (singular-send-string process string))
461  (kill-buffer (current-buffer)))
462
463(defun singular-toggle-truncate-lines ()
464  "Toggle truncate-lines."
465  (interactive)
466  (setq truncate-lines (not truncate-lines)))
467;;}}}
468
469;;{{{ Customizing variables of comint
470
471;; Note:
472;;
473;; In contrast to the variables from comint.el, all the variables
474;; below are global variables.  It would not make any sense to make
475;; them buffer-local since
476;; o they are read only when Singular interactive mode comes up;
477;; o since they are Singular-dependent and not user-dependent, i.e.,
478;;   the user would not mind to change them.
479;;
480;; For the same reasons these variables are not marked as
481;; "customizable" by a leading `*'.
482
483(defvar singular-prompt-regexp "^> "
484  "Regexp to match prompt patterns in Singular.
485Should not match the continuation prompt \(`.'), only the regular
486prompt \(`>').
487
488This variable is used to initialize `comint-prompt-regexp' when
489Singular interactive mode starts up.")
490
491(defvar singular-delimiter-argument-list '(?= ?\( ?\) ?, ?;)
492  "List of characters to recognize as separate arguments.
493
494This variable is used to initialize `comint-delimiter-argument-list'
495when Singular interactive mode starts up.")
496
497(defvar singular-input-ignoredups t
498  "If non-nil, don't add input matching the last on the input ring.
499
500This variable is used to initialize `comint-input-ignoredups' when
501Singular interactive mode starts up.")
502
503(defvar singular-buffer-maximum-size 2048
504  "The maximum size in lines for Singular buffers.
505
506This variable is used to initialize `comint-buffer-maximum-size' when
507Singular interactive mode starts up.")
508
509(defvar singular-input-ring-size 64
510  "Size of input history ring.
511
512This variable is used to initialize `comint-input-ring-size' when
513Singular interactive mode starts up.")
514
515(defvar singular-history-filter-regexp "\\`\\(..?\\|\\s *\\)\\'"
516  "Regular expression to filter strings *not* to insert in the history.
517By default, input consisting of less than three characters and input
518consisting of white-space only is not added to the history.")
519
520(defvar singular-history-filter
521  (function (lambda (string)
522              (not (string-match singular-history-filter-regexp string))))
523  "Predicate for filtering additions to input history.
524
525This variable is used to initialize `comint-input-filter' when
526Singular interactive mode starts up.")
527;;}}}
528
529;;{{{ Skipping and stripping prompts and newlines and other things
530
531;; Note:
532;;
533;; All of these functions modify the match data!
534
535(defun singular-strip-white-space (string &optional trailing leading)
536  "Strip off trailing or leading white-space from STRING.
537Strips off trailing white-space if optional argument TRAILING is
538non-nil.
539Strips off leading white-space if optional argument LEADING is
540non-nil."
541  (let ((beg 0)
542        (end (length string)))
543    (and leading
544         (string-match "\\`\\s-*" string)
545         (setq beg (match-end 0)))
546    (and trailing
547         (string-match "\\s-*\\'" string beg)
548         (setq end (match-beginning 0)))
549    (substring string beg end)))
550
551(defconst singular-extended-prompt-regexp "\\([?>.] \\)"
552  "Matches one Singular prompt.
553Should not be anchored neither to start nor to end!")
554
555(defconst singular-strip-leading-prompt-regexp
556  (concat "\\`" singular-extended-prompt-regexp "+")
557  "Matches Singular prompt anchored to string start.")
558
559(defun singular-strip-leading-prompt (string)
560  "Strip leading prompts from STRING.
561May or may not return STRING or a modified copy of it."
562  (if (string-match singular-strip-leading-prompt-regexp string)
563      (substring string (match-end 0))
564    string))
565
566(defconst singular-remove-prompt-regexp
567  (concat "^" singular-extended-prompt-regexp
568          "*" singular-extended-prompt-regexp)
569  "Matches a non-empty sequence of prompts at start of a line.")
570
571(defun singular-remove-prompt (beg end)
572  "Remove all superfluous prompts from region between BEG and END.
573Removes all but the last prompt of a sequence if that sequence ends at
574END.
575The region between BEG and END should be accessible.
576Leaves point after the last prompt found."
577  (let ((end (copy-marker end))
578        prompt-end)
579    (goto-char beg)
580    (while (and (setq prompt-end
581                      (re-search-forward singular-remove-prompt-regexp end t))
582                (not (= end prompt-end)))
583      (delete-region (match-beginning 0) prompt-end))
584
585    ;; check for trailing prompt
586    (if prompt-end
587        (delete-region (match-beginning 0)  (match-beginning 2)))
588    (set-marker end nil)))
589
590(defconst singular-skip-prompt-forward-regexp
591  (concat singular-extended-prompt-regexp "*")
592  "Matches an arbitary sequence of Singular prompts.")
593
594(defun singular-skip-prompt-forward ()
595  "Skip forward over prompts."
596  (looking-at singular-skip-prompt-forward-regexp)
597  (goto-char (match-end 0)))
598
599(defun singular-skip-prompt-backward ()
600  "Skip backward over prompts."
601  (while (re-search-backward singular-extended-prompt-regexp (- (point) 2) t)))
602;;}}}
603
604;;{{{ Simple section stuff for both Emacs and XEmacs
605
606;; Note:
607;;
608;; Sections and simple sections are used to mark Singular's input and
609;; output for further access.  Here are some general notes on simple
610;; sections.  Sections are explained in the respective folding.
611;;
612;; In general, simple sections are more or less Emacs' overlays or XEmacs
613;; extents, resp.  But they are more than simply an interface to overlays
614;; or sections.
615;;
616;; - Simple sections are non-empty portions of text.  They are interpreted
617;;   as left-closed, right-opened intervals, i.e., the start point of a
618;;   simple sections belongs to it whereas the end point does not.
619;; - Simple sections start and end at line borders only.
620;; - Simple sections do not overlap.  Thus, any point in the buffer may be
621;;   covered by at most one simple section.
622;; - Besides from their start and their end, simple sections have some type
623;;   associated.
624;; - Simple sections are realized using overlays (extents for XEmacs)
625;;   which define the start and, end, and type (via properties) of the
626;;   simple section.  Actually, as a lisp object a simple section is
627;;   nothing else but the underlying overlay.
628;; - There may be so-called clear simple sections.  Clear simple sections
629;;   have not an underlying overlay.  Instead, they start at the end of the
630;;   preceding non-clear simple section, end at the beginning of the next
631;;   non-clear simple section, and have the type defined by
632;;   `singular-simple-sec-clear-type'.  Clear simple sections are
633;;   represented by nil.
634;; - Buffer narrowing does not restrict the extent of completely or
635;;   partially inaccessible simple sections.  But one should note that
636;;   some of the functions assume that there is no narrowing in
637;;   effect.
638;; - After creation, simple sections are not modified any further.
639;;
640;; - In `singular-interactive-mode', the whole buffer is covered with
641;;   simple sections from the very beginning of the file up to the
642;;   beginning of the line containing the last input or output.  The
643;;   remaining text up to `(point-max)' may be interpreted as covered by
644;;   one clear simple section.  Thus, it is most reasonable to define
645;;   `input' to be the type of clear simple sections.
646
647(defvar singular-simple-sec-clear-type 'input
648  "Type of clear simple sections.
649If nil no clear simple sections are used.")
650
651(defvar singular-simple-sec-last-end nil
652  "Marker at the end of the last simple section.
653Should be initialized by `singular-simple-sec-init' before any calls to
654`singular-simple-sec-create' are done.
655
656This variable is buffer-local.")
657
658(defun singular-simple-sec-init (pos)
659  "Initialize global variables belonging to simple section management.
660Creates the buffer-local marker `singular-simple-sec-last-end' and
661initializes it to POS."
662  (make-local-variable 'singular-simple-sec-last-end)
663  (if (not (markerp singular-simple-sec-last-end))
664      (setq singular-simple-sec-last-end (make-marker)))
665  (set-marker singular-simple-sec-last-end pos))
666
667;; Note:
668;;
669;; The rest of the folding is either marked as
670;; Emacs
671;; or
672;; XEmacs
673
674(singular-fset 'singular-simple-sec-create
675               'singular-emacs-simple-sec-create
676               'singular-xemacs-simple-sec-create)
677
678(singular-fset 'singular-simple-sec-reset-last
679               'singular-emacs-simple-sec-reset-last
680               'singular-xemacs-simple-sec-reset-last)
681
682(singular-fset 'singular-simple-sec-start
683               'singular-emacs-simple-sec-start
684               'singular-xemacs-simple-sec-start)
685
686(singular-fset 'singular-simple-sec-end
687               'singular-emacs-simple-sec-end
688               'singular-xemacs-simple-sec-end)
689
690(singular-fset 'singular-simple-sec-start-at
691               'singular-emacs-simple-sec-start-at
692               'singular-xemacs-simple-sec-start-at)
693
694(singular-fset 'singular-simple-sec-end-at
695               'singular-emacs-simple-sec-end-at
696               'singular-xemacs-simple-sec-end-at)
697
698(singular-fset 'singular-simple-sec-type
699               'singular-emacs-simple-sec-type
700               'singular-xemacs-simple-sec-type)
701
702(singular-fset 'singular-simple-sec-at
703               'singular-emacs-simple-sec-at
704               'singular-xemacs-simple-sec-at)
705
706(singular-fset 'singular-simple-sec-before
707               'singular-emacs-simple-sec-before
708               'singular-xemacs-simple-sec-before)
709
710(singular-fset 'singular-simple-sec-in
711               'singular-emacs-simple-sec-in
712               'singular-xemacs-simple-sec-in)
713;;}}}
714
715;;{{{ Simple section stuff for Emacs
716(defun singular-emacs-simple-sec-create (type end)
717  "Create a new simple section of type TYPE.
718Creates the section from end of previous simple section up to END.
719END should be larger than `singular-simple-sec-last-end'.
720Returns the new simple section or `empty' if no simple section has
721been created.
722Assumes that no narrowing is in effect.
723Updates `singular-simple-sec-last-end'."
724  (let ((last-end (marker-position singular-simple-sec-last-end))
725        ;; `simple-sec' is the new simple section or `empty'
726        simple-sec)
727
728    ;; get beginning of line before END.  At this point we need that there
729    ;; are no restrictions.
730    (setq end (let ((old-point (point)))
731                (goto-char end) (beginning-of-line)
732                (prog1 (point) (goto-char old-point))))
733
734    (cond
735     ;; do not create empty sections
736     ((eq end last-end) (setq simple-sec 'empty))
737     ;; create only non-clear simple sections
738     ((not (eq type singular-simple-sec-clear-type))
739      ;; if type has not changed we only have to extend the previous
740      ;; simple section
741      (setq simple-sec (singular-emacs-simple-sec-before last-end))
742      (if (eq type (singular-emacs-simple-sec-type simple-sec))
743          ;; move existing overlay
744          (setq simple-sec (move-overlay simple-sec (overlay-start simple-sec) end))
745        ;; create new overlay
746        (setq simple-sec (make-overlay last-end end))
747        ;; set type property
748        (overlay-put simple-sec 'singular-type type)
749        ;; set face
750        (overlay-put simple-sec 'face (singular-lookup-face type))
751        ;; evaporate empty sections
752        (overlay-put simple-sec 'evaporate t))))
753           
754    ;; update end of last simple section
755    (set-marker singular-simple-sec-last-end end)
756    simple-sec))
757
758(defun singular-emacs-simple-sec-reset-last (pos)
759  "Reset end of last simple section to POS after accidental extension.
760Updates `singular-simple-sec-last-end', too."
761  (let ((simple-sec (singular-emacs-simple-sec-at pos)))
762    (if simple-sec (move-overlay simple-sec (overlay-start simple-sec) pos))
763    (set-marker singular-simple-sec-last-end pos)))
764
765(defun singular-emacs-simple-sec-start (simple-sec)
766  "Return start of non-clear simple section SIMPLE-SEC."
767  (overlay-start simple-sec))
768
769(defun singular-emacs-simple-sec-end (simple-sec)
770  "Return end of non-clear simple section SIMPLE-SEC."
771  (overlay-end simple-sec))
772
773(defun singular-emacs-simple-sec-start-at (pos)
774  "Return start of clear section at position POS.
775Assumes that no narrowing is in effect."
776  (let ((previous-overlay-change (1+ pos)))
777    ;; this `while' loop at last will run into the end of the next
778    ;; non-clear overlay or stop at bob.  Since POS may be right at the end
779    ;; of a previous non-clear location, we have to search at least one
780    ;; time from POS+1 backwards.
781    (while (not (or (singular-emacs-simple-sec-before previous-overlay-change)
782                    (eq previous-overlay-change (point-min))))
783      (setq previous-overlay-change
784            (previous-overlay-change previous-overlay-change)))
785    previous-overlay-change))
786
787(defun singular-emacs-simple-sec-end-at (pos)
788  "Return end of clear section at position POS.
789Assumes that no narrowing is in effect."
790  (let ((next-overlay-change (next-overlay-change pos)))
791    ;; this `while' loop at last will run into the beginning of the next
792    ;; non-clear overlay or stop at eob.  Since POS may not be at the
793    ;; beginning of a non-clear simple section we may start searching
794    ;; immediately.
795    (while (not (or (singular-emacs-simple-sec-at next-overlay-change)
796                    (eq next-overlay-change (point-max))))
797      (setq next-overlay-change
798            (next-overlay-change next-overlay-change)))
799    next-overlay-change))
800
801(defun singular-emacs-simple-sec-type (simple-sec)
802  "Return type of SIMPLE-SEC."
803  (if simple-sec
804      (overlay-get simple-sec 'singular-type)
805    singular-simple-sec-clear-type))
806
807(defun singular-emacs-simple-sec-at (pos)
808  "Return simple section at position POS."
809  (let ((overlays (overlays-at pos)) simple-sec)
810    ;; be careful, there may be other overlays!
811    (while (and overlays (not simple-sec))
812      (if (singular-emacs-simple-sec-type (car overlays))
813          (setq simple-sec (car overlays)))
814      (setq overlays (cdr overlays)))
815    simple-sec))
816
817(defun singular-emacs-simple-sec-before (pos)
818  "Return simple section before position POS.
819This is the same as `singular-simple-section-at' except if POS falls
820on a section border.  In this case `singular-simple-section-before'
821returns the previous simple section instead of the current one."
822  (singular-emacs-simple-sec-at (max 1 (1- pos))))
823
824(defun singular-emacs-simple-sec-in (beg end)
825  "Return a list of all simple sections intersecting with the region from BEG to END.
826A simple section intersects the region if the section and the region
827have at least one character in common.
828The result contains both clear and non-clear simple sections in the
829order in that the appear in the region."
830  ;; NOT READY
831  nil)
832;;}}}
833
834;;{{{ Simple section stuff for XEmacs
835(defun singular-xemacs-simple-sec-create (type end)
836  "Create a new simple section of type TYPE.
837Creates the section from end of previous simple section up to END.
838END should be larger than `singular-simple-sec-last-end'.
839Returns the new simple section or `empty' if no simple section has
840been created.
841Assumes that no narrowing is in effect.
842Updates `singular-simple-sec-last-end'."
843  (let ((last-end (marker-position singular-simple-sec-last-end))
844        ;; `simple-sec' is the new simple section or `empty'
845        simple-sec)
846
847    ;; get beginning of line before END.  At this point we need that there
848    ;; are no restrictions.
849    (setq end (let ((old-point (point)))
850                (goto-char end) (beginning-of-line)
851                (prog1 (point) (goto-char old-point))))
852
853    (cond
854     ;; do not create empty sections
855     ((eq end last-end) (setq simple-sec 'empty))
856     ;; create only non-clear simple sections
857     ((not (eq type singular-simple-sec-clear-type))
858      ;; if type has not changed we only have to extend the previous
859      ;; simple section
860      (setq simple-sec (singular-xemacs-simple-sec-before last-end))
861      (if (eq type (singular-xemacs-simple-sec-type simple-sec))
862          ;; move existing extent
863          (setq simple-sec (set-extent-endpoints simple-sec 
864                                                 (extent-start-position simple-sec) end))
865        ;; create new extent
866        (setq simple-sec (make-extent last-end end))
867        ;; set type property
868        (set-extent-property simple-sec 'singular-type type)
869        ;; set face
870        (set-extent-property simple-sec 'face (singular-lookup-face type)))))
871           
872    ;; update end of last simple section
873    (set-marker singular-simple-sec-last-end end)
874    simple-sec))
875
876(defun singular-xemacs-simple-sec-reset-last (pos)
877  "Reset end of last simple section to POS after accidental extension.
878Updates `singular-simple-sec-last-end', too."
879  (let ((simple-sec (singular-xemacs-simple-sec-at pos)))
880    (if simple-sec 
881        (set-extent-endpoints simple-sec (extent-start-position simple-sec) pos))
882    (set-marker singular-simple-sec-last-end pos)))
883
884(defun singular-xemacs-simple-sec-start (simple-sec)
885  "Return start of non-clear simple section SIMPLE-SEC."
886  (extent-start-position simple-sec))
887
888(defun singular-xemacs-simple-sec-end (simple-sec)
889  "Return end of non-clear simple section SIMPLE-SEC."
890  (extent-end-position simple-sec))
891
892(defun singular-xemacs-simple-sec-start-at (pos)
893  "Return start of clear section at position POS.
894Assumes that no narrowing is in effect."
895  ;; if previous-extent-change is called with an argument bigger
896  ;; than (1+ (buffer-size))  (not (point-max)!), we get an error!
897  (let ((previous-extent-change (if (> pos (buffer-size))
898                                    pos
899                                  (1+ pos))))
900    ;; this `while' loop at last will run into the end of the next
901    ;; non-clear extent or stop at bob.  Since POS may be right at the end
902    ;; of a previous non-clear location, we have to search at least one
903    ;; time from POS+1 backwards.
904    (while (not (or (singular-xemacs-simple-sec-before previous-extent-change)
905                    (eq previous-extent-change (point-min))))
906      (setq previous-extent-change
907            (previous-extent-change previous-extent-change)))
908    previous-extent-change))
909
910(defun singular-xemacs-simple-sec-end-at (pos)
911  "Return end of clear section at position POS.
912Assumes that no narrowing is in effect."
913  (let ((next-extent-change (next-extent-change pos)))
914    ;; this `while' loop at last will run into the beginning of the next
915    ;; non-clear extent or stop at eob.  Since POS may not be at the
916    ;; beginning of a non-clear simple section we may start searching
917    ;; immediately.
918    (while (not (or (singular-xemacs-simple-sec-at next-extent-change)
919                    (eq next-extent-change (point-max))))
920      (setq next-extent-change
921            (next-extent-change next-extent-change)))
922    next-extent-change))
923
924(defun singular-xemacs-simple-sec-type (simple-sec)
925  "Return type of SIMPLE-SEC."
926  (if simple-sec
927      (extent-property simple-sec 'singular-type)
928    singular-simple-sec-clear-type))
929
930(defun singular-xemacs-simple-sec-at (pos)
931  "Return simple section at position POS."
932  (map-extents (function (lambda (ext args) ext))
933               ;; is this pos-pos-region OK? I think so.
934               (current-buffer) pos pos nil nil 'singular-type))
935
936(defun singular-xemacs-simple-sec-before (pos)
937  "Return simple section before position POS.
938This is the same as `singular-simple-section-at' except if POS falls
939on a section border.  In this case `singular-simple-section-before'
940returns the previous simple section instead of the current one."
941  (singular-xemacs-simple-sec-at (max 1 (1- pos))))
942
943(defun singular-xemacs-simple-sec-in (beg end)
944  "Return a list of all simple sections intersecting with the region from BEG to END.
945A simple section intersects the region if the section and the region
946have at least one character in common.
947The result contains both clear and non-clear simple sections in the
948order they appear in the region."
949  ;; NOT READY [order of sections???]
950  (let ((extent-list))
951    (map-extents 
952     (function (lambda (ext arg)
953
954                 ;; if start of first extent is not point-min, insert
955                 ;; a clear-simple-sec first:
956                 (or extent-list 
957                     (= (extent-start-position ext) (point-min))
958                     (setq extent-list (append (list nil) extent-list)))
959
960                 ;; if end of previous simple-sec is not equal start of
961                 ;; current simple-sec than we have to insert a
962                 ;; clear-simple-sec first:
963                 (and (car extent-list)
964                      (not (= (extent-end-position (car extent-list))
965                              (extent-start-position ext)))
966                      (setq extent-list (append (list nil) extent-list)))
967
968                 ;; finally insert this non-clear simple-sec:
969                 (setq extent-list (append (list ext) extent-list))
970                 nil))
971     (current-buffer) beg end nil nil 'singular-type)
972
973    ;; if extent-list is still nil at this point, then no non-clear
974    ;; simple-sec intersects with region (BEG END).
975    ;; Then insert a clear simple-sec:
976    (or extent-list
977        (setq extent-list '(nil)))
978
979    ;; if last inserted simple-sec is non-clear and its end is smaller
980    ;; than END, then insert another clear simple sec:
981    (and (car extent-list)
982         (<= (extent-end-position (car extent-list)) end)
983         (setq extent-list (append (list nil) extent-list)))
984
985    ;; we set up the list in decreasing order, so reverse the list
986    (reverse extent-list)))
987;;}}}
988
989;;{{{ Section stuff
990
991;; Note:
992;;
993;; Sections are built on simple sections.  Their purpose is to cover the
994;; difference between clear and non-clear simple sections.
995;;
996;; - Sections consist of a simple section, its type, and its start and end
997;;   points.  This is redundant information only in the case of non-clear
998;;   simple section.
999;; - Sections are read-only objects, neither are they modified nor are they
1000;;   created.
1001;; - Buffer narrowing does not restrict the extent of completely or
1002;;   partially inaccessible sections.  In contrast to simple sections
1003;;   the functions concerning sections do not assume that there is no
1004;;   narrowing in effect.
1005;; - Sections are independent from implementation dependencies.  There are
1006;;   no different versions of the functions for Emacs and XEmacs.
1007
1008(defun singular-section-at (pos &optional restricted)
1009  "Return section at position POS.
1010Returns section intersected with current restriction if RESTRICTED is
1011non-nil."
1012  (let* ((simple-sec (singular-simple-sec-at pos))
1013         (type (singular-simple-sec-type simple-sec))
1014         start end)
1015    (if simple-sec
1016        (setq start (singular-simple-sec-start simple-sec)
1017              end  (singular-simple-sec-end simple-sec))
1018      (save-restriction
1019        (widen)
1020        (setq start (singular-simple-sec-start-at pos)
1021              end (singular-simple-sec-end-at pos))))
1022    (if restricted
1023        (vector simple-sec type
1024                (max start (point-min)) (min end (point-max)))
1025      (vector simple-sec type start end))))
1026
1027(defun singular-section-before (pos &optional restricted)
1028  "Return section before position POS.
1029This is the same as `singular-section-at' except if POS falls on a
1030section border.  In this case `singular-section-before' returns the
1031previous section instead of the current one.
1032Returns section intersected with current restriction if RESTRICTED is
1033non-nil."
1034  (singular-section-at (max 1 (1- pos)) restricted))
1035
1036(defun singular-section-in (reg-beg reg-end)
1037  "NOT READY [docu]"
1038  (let ((simple-secs (singular-simple-sec-in reg-beg reg-end))
1039        sections current last-end 
1040        type beg end)
1041    (save-restriction
1042      (widen)
1043      (while simple-secs
1044        (setq current (car simple-secs))
1045        (setq type (singular-simple-sec-type current))
1046        (if current
1047            ;; current is a non-clear simple-sec
1048            (setq beg (singular-simple-sec-start current)
1049                  end (singular-simple-sec-end current)
1050                  last-end end)
1051          ;; current is a clear simple-sec
1052          (setq beg (singular-simple-sec-start-at (or last-end
1053                                                        (point-min)))
1054                end (singular-simple-sec-end-at (or last-end
1055                                                    (point-min)))))
1056        ;; NOT READY [RESTRICTED]
1057        (setq sections (append sections (list (vector current type beg end))))
1058        (setq simple-secs (cdr simple-secs))))
1059    sections))
1060
1061(defmacro singular-section-simple-sec (section)
1062  "Return underlying simple section of SECTION."
1063  `(aref ,section 0))
1064
1065(defmacro singular-section-type (section)
1066  "Return type of SECTION."
1067  `(aref ,section 1))
1068
1069(defmacro singular-section-start (section)
1070  "Return start of SECTION."
1071  `(aref ,section 2))
1072
1073(defmacro singular-section-end (section)
1074  "Return end of SECTION."
1075  `(aref ,section 3))
1076;;}}}
1077
1078;;{{{ Getting section contents
1079(defun singular-input-section-to-string (section &optional end raw)
1080  "Get content of SECTION as string.
1081Returns text between start of SECTION and END if optional argument END
1082is non-nil.  END should be a position inside SECTION.
1083Strips leading prompts and trailing white space unless optional argument
1084RAW is non-nil."
1085  (save-restriction
1086    (widen)
1087    (let ((string (if end
1088                      (buffer-substring (singular-section-start section) end)
1089                    (buffer-substring (singular-section-start section)
1090                                      (singular-section-end section)))))
1091      (if raw string
1092        (singular-strip-leading-prompt
1093         (singular-strip-white-space string t))))))
1094;;}}}
1095
1096;;{{{ Last input and output section
1097(defun singular-last-input-section (&optional no-error)
1098  "Return last input section.
1099Returns nil if optional argument NO-ERROR is non-nil and there is no
1100last input section defined, throws an error otherwise."
1101  (let ((last-input-start (marker-position singular-last-input-section-start))
1102        (last-input-end (marker-position singular-current-output-section-start)))
1103    (cond ((and last-input-start last-input-end)
1104           (vector (singular-simple-sec-at last-input-start) 'input
1105                   last-input-start last-input-end))
1106          (no-error nil)
1107          (t (error "No last input section defined")))))
1108
1109(defun singular-current-output-section (&optional no-error)
1110  "Return current output section.
1111Returns nil if optional argument NO-ERROR is non-nil and there is no
1112current output section defined, throws an error otherwise."
1113  (let ((current-output-start (marker-position singular-current-output-section-start))
1114        (current-output-end (save-excursion
1115                              (goto-char (singular-process-mark))
1116                              (singular-skip-prompt-backward)
1117                              (and (bolp) (point)))))
1118    (cond ((and current-output-start current-output-end)
1119           (vector (singular-simple-sec-at current-output-start) 'output
1120                   current-output-start current-output-end))
1121          (no-error nil)
1122          (t (error "No current output section defined")))))
1123
1124(defun singular-last-output-section (&optional no-error)
1125  "Return last output section.
1126Returns nil if optional argument NO-ERROR is non-nil and there is no
1127last output section defined, throws an error otherwise."
1128  (let ((last-output-start (marker-position singular-last-output-section-start))
1129        (last-output-end (marker-position singular-last-input-section-start)))
1130    (cond ((and last-output-start last-output-end)
1131           (vector (singular-simple-sec-at last-output-start) 'output
1132                   last-output-start last-output-end))
1133          (no-error nil)
1134          (t (error "No last output section defined")))))
1135
1136(defun singular-latest-output-section (&optional no-error)
1137  "Return latest output section.
1138This is the current output section if it is defined, otherwise the
1139last output section.
1140Returns nil if optional argument NO-ERROR is non-nil and there is no
1141latest output section defined, throws an error otherwise."
1142  (or (singular-current-output-section t)
1143      (singular-last-output-section t)
1144      (if no-error
1145          nil
1146        (error "No latest output section defined"))))
1147;;}}}
1148
1149;;{{{ Folding sections
1150(defvar singular-folding-ellipsis "Singular I/O ..."
1151  "Ellipsis to show for folded input or output.")
1152
1153(defun singular-fold-internal (start end fold)
1154  "(Un)fold region from START to END.
1155Folds if FOLD is non-nil, otherwise unfolds.
1156Folding affects undo information and buffer modified flag.
1157Assumes that there is no narrowing in effect."
1158  (save-excursion
1159    (if fold
1160        (progn
1161          (goto-char start) (insert ?\r)
1162          (subst-char-in-region start end ?\n ?\r t))
1163      (subst-char-in-region start end ?\r ?\n t)
1164      (goto-char start) (delete-char 1))))
1165
1166(defun singular-section-foldedp (section)
1167  "Return t iff SECTION is folded.
1168Assumes that there is no narrowing in effect."
1169  (eq (char-after (singular-section-start section)) ?\r))
1170
1171(defun singular-fold-section (section)
1172  "\(Un)fold SECTION.
1173\(Un)folds section at point and goes to beginning of section if called
1174interactively.
1175Unfolds folded sections and folds unfolded sections."
1176  (interactive (list (singular-section-at (point))))
1177  (let ((start (singular-section-start section))
1178        ;; we have to save restrictions this way since we change text
1179        ;; outside the restriction.  Note that we do not use a marker for
1180        ;; `old-point-min'.  This way, even partial narrowed sections are
1181        ;; folded properly if they have been narrowed at bol.  Nice but
1182        ;; dirty trick: The insertion of a `?\r' at beginning of section
1183        ;; advances the beginning of the restriction such that it displays
1184        ;; the `?\r' immediately before bol.  Seems worth it.
1185        (old-point-min (point-min))
1186        (old-point-max (point-max-marker)))
1187    (unwind-protect
1188        (progn
1189          (widen)
1190          (singular-fold-internal start (singular-section-end section)
1191                                  (not (singular-section-foldedp section))))
1192      ;; this is unwide-protected
1193      (narrow-to-region old-point-min old-point-max)
1194      (set-marker old-point-max nil))
1195    (if (interactive-p) (goto-char (max start (point-min))))))
1196
1197(defun singular-do-folding (where &optional unfold)
1198  "NOT READY [docu]
1199WHERE= 'last or 'all --> just output sections
1200WHERE= 'at-point --> whatever is at point"
1201  (let (which)
1202    (cond 
1203     ((eq where 'last)
1204      (setq which (list (singular-latest-output-section t))))
1205     ((eq where 'at-point)
1206      (setq which (list (singular-section-at (point)))))
1207     ((eq where 'all)
1208      (setq which (singular-section-in (point-min) (point-max)))
1209
1210      ;; just use the output sections:
1211      (let (newwhich)
1212        (while which
1213          (if (eq (singular-section-type (car which)) 'output)
1214              (setq newwhich (append (list (car which)) newwhich)))
1215          (setq which (cdr which)))
1216        (setq which newwhich)))
1217
1218     (t 
1219      (singular-debug 'interactive
1220                      (message "singular-do-folding: wrong argument"))))
1221    (while which
1222      (let* ((current (car which))
1223            (is-folded (singular-section-foldedp current)))
1224        (and (if unfold is-folded (not is-folded))
1225             (singular-fold-section current)))
1226      (setq which (cdr which))))
1227  ;; NOT READY: HACK: recenter (because of error in subst-char-in-region!?!)
1228  (recenter))
1229
1230(defun singular-fold-last-output ()
1231  "Fold last output section.
1232If it is already folded, do nothing."
1233  (interactive)
1234  (singular-do-folding 'last))
1235
1236(defun singular-fold-all-output ()
1237  "Fold all output sections."
1238  (interactive) 
1239  (singular-do-folding 'all))
1240
1241(defun singular-fold-at-point
1242  "Fold section at point (input or output section).
1243If it is already folded, do nothing."
1244  (interactive) 
1245  (singular-do-folding 'at-point))
1246
1247(defun singular-unfold-last-output ()
1248  "Unfold last output section.
1249If it is already unfolded, do nothing."
1250  (interactive)
1251  (singular-do-folding 'last 'unfold))
1252
1253(defun singular-unfold-all-output ()
1254  "Unfold all output section."
1255  (interactive)
1256  (singular-do-folding 'all 'unfold))
1257
1258(defun singular-unfold-at-point ()
1259  "Unfold section at point (input or output section).
1260If it is already unfolded, do nothing."
1261  (interactive)
1262  (singular-do-folding 'at-point 'unfold))
1263;;}}}
1264
1265;;{{{ Input and output filters
1266
1267;; debugging filters
1268(defun singular-debug-pre-input-filter (string)
1269  "Display STRING and some markers in mini-buffer."
1270  (singular-debug 'interactive-filter
1271                  (message "Pre-input filter: %s"
1272                           (singular-debug-format string)))
1273  (singular-debug 'interactive-filter
1274                  (message "Pre-input filter: (li %S ci %S lo %S co %S)"
1275                           (marker-position singular-last-input-section-start)
1276                           (marker-position singular-current-input-section-start)
1277                           (marker-position singular-last-output-section-start)
1278                           (marker-position singular-current-output-section-start)))
1279  nil)
1280
1281(defun singular-debug-post-input-filter (beg end)
1282  "Display BEG, END, and some markers in mini-buffer."
1283  (singular-debug 'interactive-filter
1284                  (message "Post-input filter: (beg %S end %S)" beg end))
1285  (singular-debug 'interactive-filter
1286                  (message "Post-input filter: (li %S ci %S lo %S co %S)"
1287                           (marker-position singular-last-input-section-start)
1288                           (marker-position singular-current-input-section-start)
1289                           (marker-position singular-last-output-section-start)
1290                           (marker-position singular-current-output-section-start))))
1291
1292(defun singular-debug-pre-output-filter (string)
1293  "Display STRING and some markers in mini-buffer."
1294  (singular-debug 'interactive-filter
1295                  (message "Pre-output filter: %s"
1296                           (singular-debug-format string)))
1297  (singular-debug 'interactive-filter
1298                  (message "Pre-output filter: (li %S ci %S lo %S co %S)"
1299                           (marker-position singular-last-input-section-start)
1300                           (marker-position singular-current-input-section-start)
1301                           (marker-position singular-last-output-section-start)
1302                           (marker-position singular-current-output-section-start)))
1303  nil)
1304
1305(defun singular-debug-post-output-filter (beg end simple-sec-start)
1306  "Display BEG, END, SIMPLE-SEC-START, and some markers in mini-buffer."
1307  (singular-debug 'interactive-filter
1308                  (message "Post-output filter: (beg %S end %S sss %S)"
1309                           beg end simple-sec-start))
1310  (singular-debug 'interactive-filter
1311                  (message "Post-output filter: (li %S ci %S lo %S co %S)"
1312                           (marker-position singular-last-input-section-start)
1313                           (marker-position singular-current-input-section-start)
1314                           (marker-position singular-last-output-section-start)
1315                           (marker-position singular-current-output-section-start))))
1316
1317;; stripping prompts
1318(defun singular-remove-prompt-filter (beg end simple-sec-start)
1319  "Strip prompts from last simple section."
1320  (if simple-sec-start (singular-remove-prompt simple-sec-start end)))
1321;;}}}
1322
1323;;{{{ Demo mode
1324(defvar singular-demo-chunk-regexp "\\(\n\n\\)"
1325  "Regular expressions to recognize chunks of a demo file.
1326If there is a subexpression specified its content is removed when the
1327chunk is displayed.")
1328
1329(defvar singular-demo-mode nil
1330  "Non-nil if Singular demo mode is on.
1331
1332This variable is buffer-local.")
1333
1334(defvar singular-demo-old-mode-name nil
1335  "Used to store previous `mode-name' before switching to demo mode.
1336
1337This variable is buffer-local.")
1338
1339(defvar singular-demo-end nil
1340  "Marker pointing to end of demo file.
1341
1342This variable is buffer-local.")
1343
1344(defvar singular-demo-command-on-enter nil
1345  "Singular command to send when entering demo mode or nil if no string to send.")
1346
1347(defvar singular-demo-command-on-leave nil
1348  "Singular command to send when leaving demo mode or nil if no string to send.")
1349 
1350(defun singular-demo-mode (mode)
1351  "Switch between demo mode states.
1352MODE may be either:
1353- `init' to initialize global variables;
1354- `exit' to clean up demo and leave Singular demo mode;
1355- `enter' to enter Singular demo mode;
1356- `leave' to leave Singular demo mode.
1357
1358Modifies the global variables `singular-demo-mode',
1359`singular-demo-end', and `singular-demo-old-mode-name' to reflect the
1360new state of Singular demo mode."
1361  (cond
1362   ;; initialization.  Should be called only once.
1363   ((eq mode 'init)
1364    (make-local-variable 'singular-demo-mode)
1365    (make-local-variable 'singular-demo-mode-old-name)
1366    (make-local-variable 'singular-demo-mode-end)
1367    (if (not (and (boundp 'singular-demo-end)
1368                  singular-demo-end))
1369        (setq singular-demo-end (make-marker))))
1370
1371   ;; final exit.  Clean up demo.
1372   ((and (eq mode 'exit)
1373         singular-demo-mode)
1374    (setq mode-name singular-demo-old-mode-name
1375          singular-demo-mode nil)
1376    ;; clean up hidden rest of demo file if existent
1377    (let ((old-point-min (point-min))
1378          (old-point-max (point-max)))
1379      (unwind-protect
1380          (progn
1381            (widen)
1382            (delete-region old-point-max singular-demo-end))
1383        ;; this is unwide-protected
1384        (narrow-to-region old-point-min old-point-max)))
1385    (if (and singular-demo-command-on-leave
1386             (singular-process))
1387        (send-string (singular-process) singular-demo-command-on-leave))
1388    (force-mode-line-update))
1389
1390   ;; enter demo mode
1391   ((and (eq mode 'enter)
1392         (not singular-demo-mode))
1393    (setq singular-demo-old-mode-name mode-name
1394          mode-name "Singular Demo"
1395          singular-demo-mode t)
1396    (if singular-demo-command-on-enter
1397        (send-string (singular-process) singular-demo-command-on-enter))
1398    (message "Hit <Return> to continue demoq")
1399    (force-mode-line-update))
1400
1401   ;; leave demo mode
1402   ((and (eq mode 'leave)
1403         singular-demo-mode)
1404    (setq mode-name singular-demo-old-mode-name
1405          singular-demo-mode nil)
1406    (if singular-demo-command-on-leave
1407        (send-string (singular-process) singular-demo-command-on-leave))
1408    (force-mode-line-update))))
1409
1410(defun singular-demo-exit ()
1411  "Prematurely exit singular demo mode."
1412  (interactive)
1413  (singular-demo-mode 'exit))
1414
1415(defun singular-demo-show-next-chunk ()
1416  "Show next chunk of demo file at input prompt.
1417Moves point to end of buffer and widenes the buffer such that the next
1418chunk of the demo file becomes visible.
1419Finds and removes chunk separators as specified by
1420`singular-demo-chunk-regexp'.
1421Removing chunk separators affects undo information and buffer-modified
1422flag.
1423Leaves demo mode after showing last chunk."
1424  (let ((old-point-min (point-min)))
1425    (unwind-protect
1426        (progn
1427          (goto-char (point-max))
1428          (widen)
1429          (if (re-search-forward singular-demo-chunk-regexp singular-demo-end 'limit)
1430              (and (match-beginning 1)
1431                   (delete-region (match-beginning 1) (match-end 1)))
1432            ;; remove trailing white-space
1433            (skip-syntax-backward "-")
1434            (delete-region (point) singular-demo-end)
1435            (singular-demo-mode 'leave)))
1436
1437      ;; this is unwind-protected
1438      (narrow-to-region old-point-min (point)))))
1439
1440(defun singular-demo-load (demo-file)
1441  "Load demo file DEMO-FILE and enter Singular demo mode.
1442For a description of the Singular demo mode one should refer to the
1443doc-string of `singular-interactive-mode'.
1444Moves point to end of buffer and inserts contents of DEMO-FILE there."
1445  (interactive "fLoad demo file: ")
1446
1447  ;; check for running demo
1448  (and singular-demo-mode
1449       (error "Another demo is already running"))
1450
1451  (let ((old-point-min (point-min)))
1452    (unwind-protect
1453        (progn
1454          (goto-char (point-max))
1455          (widen)
1456          ;; load file and remember its end
1457          (set-marker singular-demo-end
1458                      (+ (point) (nth 1 (insert-file-contents demo-file)))))
1459
1460      ;; completely hide demo file.
1461      ;; This is unwide protected.
1462      (narrow-to-region old-point-min (point)))
1463
1464    ;; switch demo mode on
1465    (singular-demo-mode 'enter)))
1466;;}}}
1467     
1468;;{{{ Some lengthy notes on input and output
1469
1470;; NOT READY[so sorry]!
1471
1472;;}}}
1473
1474;;{{{ Sending input
1475(defvar singular-pre-input-filter-functions nil
1476  "Functions to call before input is sent to process.
1477These functions get one argument, a string containing the text which
1478is to be sent to process.  The functions should return either nil
1479or a string.  In the latter case the returned string replaces the
1480string to be sent to process.
1481
1482This is a buffer-local variable, not a buffer-local hook!
1483
1484`singular-run-hook-with-arg-and-value' is used to run the functions in
1485the list.")
1486
1487(defvar singular-post-input-filter-functions nil
1488  "Functions to call after input is sent to process.
1489These functions get two arguments BEG and END.
1490If `singular-input-filter' has been called with a string as argument
1491BEG and END gives the position of this string after insertion into the
1492buffer.
1493If `singular-input-filter' has been called with a position as argument
1494BEG and END equal process mark and that position, resp.
1495The functions may assume that no narrowing is in effect and may change
1496point at will.
1497
1498This hook is buffer-local.")
1499
1500(defvar singular-current-input-section-start nil
1501  "Marker to the start of the current input section.
1502This marker points nowhere on startup or if there is no current input
1503section.
1504
1505This variable is buffer-local.")
1506
1507(defvar singular-last-input-section-start nil
1508  "Marker to the start of the last input section.
1509This marker points nowhere on startup.
1510
1511This variable is buffer-local.")
1512
1513(defun singular-input-filter-init (pos)
1514  "Initialize all variables concerning input.
1515POS is the position of the process mark."
1516  ;; localize variables not yet localized in `singular-interactive-mode'
1517  (make-local-variable 'singular-current-input-section-start)
1518  (make-local-variable 'singular-last-input-section-start)
1519
1520  ;; initialize markers
1521  (if (not (markerp singular-current-input-section-start))
1522      (setq singular-current-input-section-start (make-marker)))
1523  (if (not (markerp singular-last-input-section-start))
1524      (setq singular-last-input-section-start (make-marker))))
1525
1526(defun singular-send-string (process string)
1527  "Send newline terminated STRING to to process PROCESS.
1528Runs the hooks on `singular-pre-input-filter-functions' in the buffer
1529associated to PROCESS.  The functions get the non-terminated string."
1530  (let ((process-buffer (process-buffer process)))
1531
1532    ;; check whether buffer is still alive
1533    (if (and process-buffer (buffer-name process-buffer))
1534        (save-excursion
1535          (set-buffer process-buffer)
1536          (send-string
1537           process
1538           (concat (singular-run-hook-with-arg-and-value
1539                    singular-pre-input-filter-functions string)
1540                   "\n"))))))
1541
1542(defun singular-input-filter (process string-or-pos)
1543  "Insert/update input from user in buffer associated to PROCESS.
1544Inserts STRING-OR-POS followed by a newline at process mark if it is a
1545string.
1546Assumes that the input is already inserted and that it is placed
1547between process mark and STRING-OR-POS if the latter is a position.
1548Inserts a newline after STRING-OR-POS.
1549
1550Takes care off:
1551- current buffer as well as point and restriction in buffer associated
1552  with process, even against non-local exits.
1553Updates:
1554- process mark;
1555- current and last sections;
1556- simple sections;
1557- mode line.
1558
1559Runs the hooks on `singular-pre-input-filter-functions' and
1560`singular-post-input-filter-functions'.
1561
1562For a more detailed descriptions of the input filter, the markers it
1563sets, and input filter functions refer to the section \"Some lengthy
1564notes on input and output\" in singular.el."
1565  (let ((process-buffer (process-buffer process)))
1566
1567    ;; check whether buffer is still alive
1568    (if (and process-buffer (buffer-name process-buffer))
1569        (let ((old-buffer (current-buffer))
1570              (old-pmark (marker-position (process-mark process)))
1571              old-point old-point-min old-point-max)
1572          (unwind-protect
1573              (let (simple-sec-start)
1574                (set-buffer process-buffer)
1575                ;; the following lines are not protected since the
1576                ;; unwind-forms refer the variables being set here
1577                (setq old-point (point-marker)
1578                      old-point-min (point-min-marker)
1579                      old-point-max (point-max-marker)
1580
1581                ;; get end of last simple section (equals start of
1582                ;; current)
1583                      simple-sec-start (marker-position singular-simple-sec-last-end))
1584
1585                ;; prepare for insertion
1586                (widen)
1587                (set-marker-insertion-type old-point t)
1588                (set-marker-insertion-type old-point-max t)
1589
1590                ;; insert string at process mark and advance process
1591                ;; mark after insertion.  If it not a string simply
1592                ;; jump to desired position and insrt a newline.
1593                (if (stringp string-or-pos)
1594                    (progn
1595                      (goto-char old-pmark)
1596                      (insert string-or-pos))
1597                  (goto-char string-or-pos))
1598                (insert ?\n)
1599                (set-marker (process-mark process) (point))
1600
1601                ;; create new simple section and update section markers
1602                (cond
1603                 ((eq (singular-simple-sec-create 'input (point)) 'empty)
1604                  nil)
1605                 ;; a new simple section has been created ...
1606                 ((null (marker-position singular-current-input-section-start))
1607                  ;; ... and even a new input section has been created!
1608                  (set-marker singular-current-input-section-start
1609                              simple-sec-start)
1610                  (set-marker singular-last-output-section-start
1611                              singular-current-output-section-start)
1612                  (set-marker singular-current-output-section-start nil)))
1613
1614                ;; run post-output hooks and force mode-line update
1615                (run-hook-with-args 'singular-post-input-filter-functions
1616                                    old-pmark (point)))
1617
1618            ;; restore buffer, restrictions and point
1619            (narrow-to-region old-point-min old-point-max)
1620            (set-marker old-point-min nil)
1621            (set-marker old-point-max nil)
1622            (goto-char old-point)
1623            (set-marker old-point nil)
1624            (set-buffer old-buffer))))))
1625           
1626(defun singular-get-old-input (get-section)
1627  "Retrieve old input.
1628Retrivies from beginning of current section to point if GET-SECTION is
1629non-nil, otherwise on a per-line base."
1630  (if get-section
1631      ;; get input from input section
1632      (let ((section (singular-section-at (point))))
1633        (if (eq (singular-section-type section) 'input)
1634            (setq old-input (singular-input-section-to-string section (point)))
1635          (error "Not on an input section")))
1636    ;; get input from line
1637    (save-excursion
1638      (beginning-of-line)
1639      (singular-skip-prompt-forward)
1640      (let ((old-point (point)))
1641        (end-of-line)
1642        (buffer-substring old-point (point))))))
1643
1644(defun singular-send-or-copy-input (send-full-section)
1645  "Send input from current buffer to associated process.
1646NOT READY[old input copying, demo mode,
1647          eol-on-send, history, SEND-FULL-SECTION]!"
1648  (interactive "P")
1649
1650  (let ((process (get-buffer-process (current-buffer)))
1651        pmark)
1652    ;; some checks and initializations
1653    (or process (error "Current buffer has no process"))
1654    (setq pmark (marker-position (process-mark process)))
1655
1656    (cond
1657     (;; check for demo mode and show next chunk if necessary
1658      (and singular-demo-mode
1659          (eq (point) pmark)
1660          (eq pmark (point-max)))
1661      (singular-demo-show-next-chunk))
1662
1663     (;; get old input
1664      (< (point) pmark)
1665      (let ((old-input (singular-get-old-input send-full-section)))
1666        (goto-char pmark)
1667        (insert old-input)))
1668
1669     (;; send input from pmark to point after doing history expansion
1670      t
1671      ;; go to desired position
1672      (if comint-eol-on-send (end-of-line))
1673      (if send-full-section (goto-char (point-max)))
1674
1675      ;; do history expansion
1676      (if (eq comint-input-autoexpand 'input)
1677          (comint-replace-by-expanded-history t))
1678      (let* ((input (buffer-substring pmark (point))))
1679
1680        ;; insert input into history
1681        (if (and (funcall comint-input-filter input)
1682                 (or (null comint-input-ignoredups)
1683                     (not (ring-p comint-input-ring))
1684                     (ring-empty-p comint-input-ring)
1685                     (not (string-equal (ring-ref comint-input-ring 0) input))))
1686            (ring-insert comint-input-ring input))
1687        (setq comint-input-ring-index nil)
1688
1689        ;; send string to process ...
1690        (singular-send-string process input)
1691        ;; ... and insert it into buffer ...
1692        (singular-input-filter process (point)))))))
1693;;}}}
1694
1695;;{{{ Receiving output
1696(defvar singular-pre-output-filter-functions nil
1697  "Functions to call before output is inserted into the buffer.
1698These functions get one argument, a string containing the text sent
1699from process.  The functions should return either nil or a string.
1700In the latter case the returned string replaces the string sent from
1701process.
1702
1703This is a buffer-local variable, not a buffer-local hook!
1704
1705`singular-run-hook-with-arg-and-value' is used to run the functions in
1706this list.")
1707
1708(defvar singular-post-output-filter-functions nil
1709  "Functions to call after output is inserted into the buffer.
1710These functions get three arguments BEG, END, and SIMPLE-SEC-START.
1711The region between BEG and END is what has been inserted into the
1712buffer.
1713SIMPLE-SEC-START is the start of the simple section which has been
1714created on insertion or nil if no simple section has been created.
1715The functions may assume that no narrowing is in effect and may change
1716point at will.
1717
1718This hook is buffer-local.")
1719
1720(defvar singular-current-output-section-start nil
1721  "Marker to the start of the current output section.
1722This marker points nowhere on startup or if there is no current output
1723section.
1724
1725This variable is buffer-local.")
1726
1727(defvar singular-last-output-section-start nil
1728  "Marker to the start of the last output section.
1729This marker points nowhere on startup.
1730
1731This variable is buffer-local.")
1732
1733(defun singular-output-filter-init (pos)
1734  "Initialize all variables concerning output including process mark.
1735Set process mark to POS."
1736
1737  ;; localize variables not yet localized in `singular-interactive-mode'
1738  (make-local-variable 'singular-current-output-section-start)
1739  (make-local-variable 'singular-last-output-section-start)
1740
1741  ;; initialize markers
1742  (if (not (markerp singular-current-output-section-start))
1743      (setq singular-current-output-section-start (make-marker)))
1744  (if (not (markerp singular-last-output-section-start))
1745      (setq singular-last-output-section-start (make-marker)))
1746  (set-marker (singular-process-mark) pos))
1747
1748(defun singular-output-filter (process string)
1749  "Insert STRING containing output from PROCESS into its associated buffer.
1750Takes care off:
1751- current buffer as well as point and restriction in buffer associated
1752  with process, even against non-local exits.
1753Updates:
1754- process mark;
1755- current and last sections;
1756- simple sections;
1757- mode line.
1758Runs the hooks on `singular-pre-output-filter-functions' and
1759`singular-post-output-filter-functions'.
1760
1761For a more detailed descriptions of the output filter, the markers it
1762sets, and output filter functions refer to the section \"Some lengthy
1763notes on input and output\" in singular.el."
1764  (let ((process-buffer (process-buffer process)))
1765
1766    ;; check whether buffer is still alive
1767    (if (and process-buffer (buffer-name process-buffer))
1768        (let ((old-buffer (current-buffer))
1769              (old-pmark (marker-position (process-mark process)))
1770              old-point old-point-min old-point-max)
1771          (unwind-protect
1772              (let (simple-sec-start)
1773                (set-buffer process-buffer)
1774                ;; the following lines are not protected since the
1775                ;; unwind-forms refer the variables being set here
1776                (setq old-point (point-marker)
1777                      old-point-min (point-min-marker)
1778                      old-point-max (point-max-marker)
1779
1780                ;; get end of last simple section (equals start of
1781                ;; current)
1782                      simple-sec-start (marker-position singular-simple-sec-last-end)
1783
1784                ;; get string to insert
1785                      string (singular-run-hook-with-arg-and-value
1786                              singular-pre-output-filter-functions
1787                              string))
1788
1789                ;; prepare for insertion
1790                (widen)
1791                (set-marker-insertion-type old-point t)
1792                (set-marker-insertion-type old-point-max t)
1793
1794                ;; insert string at process mark and advance process
1795                ;; mark after insertion
1796                (goto-char old-pmark)
1797                (insert string)
1798                (set-marker (process-mark process) (point))
1799
1800                ;; create new simple section and update section markers
1801                (cond
1802                 ((eq (singular-simple-sec-create 'output (point)) 'empty)
1803                  (setq simple-sec-start nil))
1804                 ;; a new simple section has been created ...
1805                 ((null (marker-position singular-current-output-section-start))
1806                  ;; ... and even a new output section has been created!
1807                  (set-marker singular-current-output-section-start
1808                              simple-sec-start)
1809                  (set-marker singular-last-input-section-start
1810                              singular-current-input-section-start)
1811                  (set-marker singular-current-input-section-start nil)))
1812
1813                ;; run post-output hooks and force mode-line update
1814                (run-hook-with-args 'singular-post-output-filter-functions
1815                                    old-pmark (point) simple-sec-start)
1816                (force-mode-line-update))
1817
1818            ;; restore buffer, restrictions and point
1819            (narrow-to-region old-point-min old-point-max)
1820            (set-marker old-point-min nil)
1821            (set-marker old-point-max nil)
1822            (goto-char old-point)
1823            (set-marker old-point nil)
1824            (set-buffer old-buffer))))))
1825;;}}}
1826
1827;;{{{ Singular interactive mode
1828(defun singular-interactive-mode ()
1829  "Major mode for interacting with Singular.
1830
1831NOT READY [how to send input]!
1832
1833NOT READY [multiple Singulars]!
1834
1835\\{singular-interactive-mode-map}
1836Customization: Entry to this mode runs the hooks on `comint-mode-hook'
1837and `singular-interactive-mode-hook' \(in that order).  Before each
1838input, the hooks on `comint-input-filter-functions' are run.  After
1839each Singular output, the hooks on `comint-output-filter-functions'
1840are run.
1841
1842NOT READY [much more to come.  See shell.el.]!"
1843  (interactive)
1844
1845  ;; remove existing singular-start-menu from menu (XEmacs)
1846  ;, NOT READY
1847  ;; This is mayby just temporary
1848;  (cond
1849;   ;; XEmacs
1850;   ((eq singular-emacs-flavor 'xemacs)
1851;    (delete-menu-item '("Singular"))))
1852
1853  ;; run comint mode and do basic mode setup
1854  (comint-mode)
1855  (setq major-mode 'singular-interactive-mode)
1856  (setq mode-name "Singular Interaction")
1857  (use-local-map singular-interactive-mode-map)
1858  (set-syntax-table singular-interactive-mode-syntax-table)
1859  (cond
1860   ;; XEmacs
1861   ((eq singular-emacs-flavor 'xemacs)
1862    (easy-menu-add singular-interactive-mode-menu-1)
1863    (easy-menu-add singular-interactive-mode-menu-2)))
1864  (setq comment-start "// ")
1865  (setq comment-start-skip "// *")
1866  (setq comment-end "")
1867
1868  ;; customize comint for Singular
1869  (setq comint-prompt-regexp singular-prompt-regexp)
1870  (setq comint-delimiter-argument-list singular-delimiter-argument-list)
1871  (setq comint-input-ignoredups singular-input-ignoredups)
1872  (make-local-variable 'comint-buffer-maximum-size)
1873  (setq comint-buffer-maximum-size singular-buffer-maximum-size)
1874  (setq comint-input-ring-size singular-input-ring-size)
1875  (setq comint-input-filter singular-history-filter)
1876
1877  ;; get name of history file (if any)
1878  (setq comint-input-ring-file-name (getenv "SINGULARHIST"))
1879  (if (or (not comint-input-ring-file-name)
1880          (equal comint-input-ring-file-name "")
1881          (equal (file-truename comint-input-ring-file-name) "/dev/null"))
1882      (setq comint-input-ring-file-name nil))
1883
1884  ;; initialize singular demo mode, input and output filters
1885  (singular-demo-mode 'init)
1886  (make-local-variable 'singular-pre-input-filter-functions)
1887  (make-local-hook 'singular-post-input-filter-functions)
1888  (make-local-variable 'singular-pre-output-filter-functions)
1889  (make-local-hook 'singular-post-output-filter-functions)
1890
1891  ;; selective display
1892  (setq selective-display t)
1893  (setq selective-display-ellipses t)
1894  (cond
1895   ;; Emacs
1896   ((eq singular-emacs-flavor 'emacs)
1897    (setq buffer-display-table (or (copy-sequence standard-display-table)
1898                                   (make-display-table)))
1899    (set-display-table-slot buffer-display-table
1900     'selective-display (vconcat singular-folding-ellipsis)))
1901    ;; XEmacs
1902   (t
1903    (set-glyph-image invisible-text-glyph singular-folding-ellipsis (current-buffer))))
1904
1905  ;; debugging filters
1906  (singular-debug 'interactive-filter
1907                  (add-hook 'singular-pre-input-filter-functions
1908                            'singular-debug-pre-input-filter nil t))
1909  (singular-debug 'interactive-filter
1910                  (add-hook 'singular-post-input-filter-functions
1911                            'singular-debug-post-input-filter nil t))
1912  (singular-debug 'interactive-filter
1913                  (add-hook 'singular-pre-output-filter-functions
1914                            'singular-debug-pre-output-filter nil t))
1915  (singular-debug 'interactive-filter
1916                  (add-hook 'singular-post-output-filter-functions
1917                            'singular-debug-post-output-filter nil t))
1918
1919  ;; other input or output filters
1920  (add-hook 'singular-post-output-filter-functions
1921            'singular-remove-prompt-filter nil t)
1922
1923  ;; font-locking
1924  (cond
1925   ;; Emacs
1926   ((eq singular-emacs-flavor 'emacs)
1927    (make-local-variable 'font-lock-defaults)
1928    (singular-debug 'interactive (message "Setting up font-lock for emacs"))
1929    (setq font-lock-defaults singular-font-lock-defaults)))
1930
1931  (run-hooks 'singular-interactive-mode-hook))
1932;;}}}
1933
1934;;{{{ Starting singular
1935(defvar singular-start-file "~/.emacs_singularrc"
1936  "Name of start-up file to pass to Singular.
1937If the file named by this variable exists it is given as initial input
1938to any Singular process being started.  Note that this may lose due to
1939a timing error if Singular discards input when it starts up.")
1940
1941(defvar singular-default-executable "Singular"
1942  "Default name of Singular executable.
1943Used by `singular' when new Singular processes are started.")
1944
1945(defvar singular-default-name "singular"
1946  "Default process name for Singular process.
1947Used by `singular' when new Singular processes are started.")
1948
1949(defvar singular-default-switches '("-t")
1950  "Default switches for Singular processes.
1951Used by `singular' when new Singular processes are started.")
1952
1953(defun singular-exit-sentinel (process message)
1954 "Clean up after termination of Singular.
1955Writes back input ring after regular termination of Singular if
1956process buffer is still alive."
1957  (save-excursion
1958    (singular-debug 'interactive
1959                    (message "Sentinel: %s" (substring message 0 -1)))
1960    ;; exit demo mode if necessary
1961    (singular-demo-mode 'exit)
1962    (if (string-match "finished\\|exited" message)
1963        (let ((process-buffer (process-buffer process)))
1964          (if (and process-buffer
1965                   (buffer-name process-buffer)
1966                   (set-buffer process-buffer))
1967              (progn
1968                (singular-debug 'interactive (message "Writing input ring back"))
1969                (comint-write-input-ring)))))))
1970
1971(defun singular-exec (buffer name executable start-file switches)
1972  "Start a new Singular process NAME in BUFFER, running EXECUTABLE.
1973EXECUTABLE should be a string denoting an executable program.
1974SWITCHES should be a list of strings that are passed as command line
1975switches.  START-FILE should be the name of a file which contents is
1976sent to the process.
1977
1978Deletes any old processes running in that buffer.
1979Moves point to the end of BUFFER.
1980Initializes all important markers and the simple sections.
1981Runs `comint-exec-hook' and `singular-exec-hook' (in that order).
1982Returns BUFFER."
1983  (let ((old-buffer (current-buffer)))
1984    (unwind-protect
1985        (progn
1986          (set-buffer buffer)
1987
1988          ;; delete any old processes
1989          (let ((process (get-buffer-process buffer)))
1990            (if process (delete-process process)))
1991
1992          ;; create new process
1993          (singular-debug 'interactive (message "Starting new Singular"))
1994          (let ((process (comint-exec-1 name buffer executable switches)))
1995
1996            ;; set process filter and sentinel
1997            (set-process-filter process 'singular-output-filter)
1998            (set-process-sentinel process 'singular-exit-sentinel)
1999            (make-local-variable 'comint-ptyp)
2000            (setq comint-ptyp process-connection-type) ; T if pty, NIL if pipe.
2001
2002            ;; go to the end of the buffer, initialize I/O and simple
2003            ;; sections
2004            (goto-char (point-max))
2005            (singular-input-filter-init (point))
2006            (singular-output-filter-init (point))
2007            (singular-simple-sec-init (point))
2008
2009            ;; feed process with start file and read input ring.  Take
2010            ;; care about the undo information.
2011            (if start-file
2012                (let ((buffer-undo-list t) start-string)
2013                  (singular-debug 'interactive (message "Feeding start file"))
2014                  (sleep-for 1)                 ; try to avoid timing errors
2015                  (insert-file-contents start-file)
2016                  (setq start-string (buffer-substring (point) (point-max)))
2017                  (delete-region (point) (point-max))
2018                  (send-string process start-string)))
2019            (singular-debug 'interactive (message "Reading input ring"))
2020            (comint-read-input-ring t)
2021
2022            ;; execute hooks
2023            (run-hooks 'comint-exec-hook)
2024            (run-hooks 'singular-exec-hook))
2025         
2026          buffer)
2027      ;; this code is unwide-protected
2028      (set-buffer old-buffer))))
2029
2030;; Note:
2031;;
2032;; In contrast to shell.el, `singular' does not run
2033;; `singular-interactive-mode' every time a new Singular process is
2034;; started, but only when a new buffer is created.  This behaviour seems
2035;; more intuitive w.r.t. local variables and hooks.
2036
2037(defun singular (&optional executable name switches)
2038  "Run an inferior Singular process, with I/O through an Emacs buffer.
2039
2040NOT READY [arguments, default values, and interactive use]!
2041
2042If buffer exists but Singular is not running, starts new Singular.
2043If buffer exists and Singular is running, just switches to buffer.
2044If a file `~/.emacs_singularrc' exists, it is given as initial input.
2045Note that this may lose due to a timing error if Singular discards
2046input when it starts up.
2047
2048If a new buffer is created it is put in Singular interactive mode,
2049giving commands for sending input and handling ouput of Singular.  See
2050`singular-interactive-mode'.
2051
2052Every time `singular' starts a new Singular process it runs the hooks
2053on `comint-exec-hook' and `singular-exec-hook' \(in that order).
2054
2055Type \\[describe-mode] in the Singular buffer for a list of commands."
2056  ;; handle interactive calls
2057  (interactive (list singular-default-executable
2058                     singular-default-name
2059                     singular-default-switches))
2060
2061  (let* (;; get default values for optional arguments
2062         (executable (or executable singular-default-executable))
2063         (name (or name singular-default-name))
2064         (switches (or switches singular-default-switches))
2065
2066         (buffer-name (singular-process-name-to-buffer-name name))
2067         ;; buffer associated with Singular, nil if there is none
2068         (buffer (get-buffer buffer-name)))
2069
2070    (if (not buffer)
2071        (progn
2072          ;; create new buffer and call `singular-interactive-mode'
2073          (singular-debug 'interactive (message "Creating new buffer"))
2074          (setq buffer (get-buffer-create buffer-name))
2075          (set-buffer buffer)
2076          (singular-debug 'interactive (message "Calling `singular-interactive-mode'"))
2077          (singular-interactive-mode)))
2078
2079    (if (not (comint-check-proc buffer))
2080        ;; create new process if there is none
2081        (singular-exec buffer name executable
2082                       (if (file-exists-p singular-start-file)
2083                           singular-start-file)
2084                       switches))
2085
2086    ;; pop to buffer
2087    (singular-debug 'interactive (message "Calling `pop-to-buffer'"))
2088    (pop-to-buffer buffer)))
2089
2090;; for convenience only
2091(defalias 'Singular 'singular)
2092
2093(defun singular-generate-new-buffer-name (name)
2094  "NOT READY [docu]
2095name: should be without stars.
2096Try to create a buffer named *name*.
2097If fails, try to create buffer named *name<number>*
2098Return buffer name with stars at start/end"
2099  (let ((new-name (singular-process-name-to-buffer-name name))
2100        (count 2))
2101    (while (get-buffer new-name)
2102      (setq new-name (singular-process-name-to-buffer-name
2103                      (concat name "<" (format "%d" count) ">")))
2104      (setq count (1+ count)))
2105    new-name))
2106 
2107(defun singular-other (file) 
2108  "NOT READY [docu]"
2109  (interactive "fSingular executable: ")
2110  ;; NOT READY [code]
2111  (let ((name (singular-generate-new-buffer-name 
2112               (downcase (file-name-nondirectory file))))
2113        (switches "")
2114        temp)
2115
2116    ;; Read buffer name from minibuffer at strip surrounding stars
2117    (setq name (read-from-minibuffer "Singular buffer name: " name))
2118    (if (string-match "^\\*\\(.*\\)\\*$" name)
2119        (setq name (substring name (match-beginning 1) (match-end 1))))
2120
2121    ;; make one string of options from list of default options
2122    (setq temp singular-default-switches)
2123    (while temp
2124      (setq switches (concat switches (car temp) " "))
2125      (setq temp (cdr temp)))
2126    ;; in minibuffer omit display of option "-t "
2127    (setq switches (read-from-minibuffer "Singular options: " 
2128                                         (replace-in-string switches "-t " "")))
2129
2130    ;; make list of strings of switch-string
2131    (setq temp '("-t"))
2132    (while (string-match "-[^ ]*" switches)
2133      (setq temp (append temp (list (substring switches (match-beginning 0) 
2134                                               (match-end 0)))))
2135      (setq switches (substring switches (match-end 0) nil)))
2136    (setq switches temp)
2137
2138    (singular file name switches)))
2139;;}}}
2140;;}}}
2141
2142(provide 'singular)
2143
2144;;; singular.el ends here.
Note: See TracBrowser for help on using the repository browser.