source: git/emacs/singular.el @ 5ec0264

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