home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / clisp / src / archive / clisp.faslsp.lha / editor.lsp < prev    next >
Lisp/Scheme  |  1996-07-24  |  117KB  |  3,142 lines

  1. (in-package "LISP")
  2. (export '(editor ed *use-ed*))
  3. (pushnew 'editor *features*)
  4. #+(or DOS OS/2) (eval-when (compile load eval) (pushnew 'dose *features*))
  5. (in-package "EDITOR")
  6.  
  7. ;###############################################################################
  8. ;;;; Screen-Verwaltung, dritte Version
  9. ;;;;
  10. ;;;; Michael Stoll, Februar 1992
  11. ;;;; Bruno Haible, Mai 1992
  12. ;;;;
  13. ;;;; Spezifikation siehe SCREEN2.DOC
  14.  
  15. (defvar *window*) ; aktuelles Ausgabefenster
  16. (defvar global-screen-height) ; Höhe des Fensters
  17. (defvar global-screen-width)  ; Breite des Fensters
  18. (defvar blanks) ; Array voller Spaces
  19.  
  20. (defmacro with-window (&body body)
  21.   `(LET* ((*WINDOW* (SCREEN:MAKE-WINDOW)))
  22.      (UNWIND-PROTECT
  23.        (MULTIPLE-VALUE-BIND (GLOBAL-SCREEN-HEIGHT GLOBAL-SCREEN-WIDTH) (SCREEN:WINDOW-SIZE *WINDOW*)
  24.          (LET ((BLANKS (MAKE-STRING GLOBAL-SCREEN-WIDTH :INITIAL-ELEMENT #\SPACE)))
  25.            ,@body
  26.        ) )
  27.        #+AMIGA (SCREEN:WINDOW-CURSOR-ON *WINDOW*)
  28.        (CLOSE *WINDOW*)
  29.    ) )
  30. )
  31.  
  32. ;;; Zunächst einige Macros zur Bildschirmsteuerung
  33.  
  34. (defmacro bell () `(WRITE-CHAR #\Bell *TERMINAL-IO*))
  35.  
  36. (defmacro screen-set-cursor (lin col)
  37.   `(SCREEN:SET-WINDOW-CURSOR-POSITION *WINDOW* ,lin ,col)
  38. )
  39.  
  40. (defmacro screen-home ()
  41.   `(SCREEN-SET-CURSOR 0 0)
  42. )
  43.  
  44. (defmacro screen-clear-screen ()
  45.   `(SCREEN:CLEAR-WINDOW *WINDOW*)
  46. )
  47.  
  48. (defmacro screen-clear-end-of-screen ()
  49.   `(SCREEN:CLEAR-WINDOW-TO-EOT *WINDOW*)
  50. )
  51.  
  52. (defmacro screen-clear-end-of-line ()
  53.   `(SCREEN:CLEAR-WINDOW-TO-EOL *WINDOW*)
  54. )
  55.  
  56. (defmacro screen-insert-line ()
  57.   `(SCREEN:INSERT-WINDOW-LINE *WINDOW*)
  58. )
  59.  
  60. (defmacro screen-delete-line ()
  61.   `(SCREEN:DELETE-WINDOW-LINE *WINDOW*)
  62. )
  63.  
  64. (defmacro screen-cursor-on ()
  65.   `(SCREEN:WINDOW-CURSOR-ON *WINDOW*)
  66. )
  67.  
  68. (defmacro screen-cursor-off ()
  69.   `(SCREEN:WINDOW-CURSOR-OFF *WINDOW*)
  70. )
  71.  
  72. (defmacro screen-reverse-on ()
  73.   `(SCREEN:HIGHLIGHT-ON *WINDOW*)
  74. )
  75.  
  76. (defmacro screen-reverse-off ()
  77.   `(SCREEN:HIGHLIGHT-OFF *WINDOW*)
  78. )
  79.  
  80. ;-------------------------------------------------------------------------------
  81.  
  82. ;;; Es werden drei Arten von Koordinaten verwendet:
  83. ;;; (Immer zuerst Zeile, dann Spalte)
  84. ;;;
  85. ;;; (a) Bildschirmkoordinaten
  86. ;;; =========================
  87. ;;;    Sie bezeichnen den Ort auf dem Bildschirm. Der erlaubte Bereich ist
  88. ;;;    [0..global-screen-height[ x [0..global-screen-width[. Dabei ist Zeile 0
  89. ;;;    die oberste Zeile, Spalte 0 die linkeste Spalte.
  90. ;;;
  91. ;;; (b) Fensterkoordinaten
  92. ;;; ======================
  93. ;;;    Sie beziehen sich jeweils auf ein Fenster. Der Ursprung ist dabei die
  94. ;;;    linke obere Ecke des Fensterinneren (d.h. ohne Rahmen). Der erlaubte
  95. ;;;    Bereich ist für ein Fenster screen im Falle, daß es nicht der ganze
  96. ;;;    Bildschirm ist (d.h. screen.full? = nil)
  97. ;;;    [-1..screen.height+1[ x [-1..screen.width+1[, wobei die Randwerte sich
  98. ;;;    auf Orte im Rahmen beziehen. Umfaßt das Fenster den ganzen Bildschirm,
  99. ;;;    sind die Fensterkoordinaten mit den Bildschirmkoordinaten identisch.
  100. ;;;
  101. ;;; (c) Textkoordinaten
  102. ;;; ===================
  103. ;;;    Sie beziehen sich auf den Text, der in einem Fenster dargestellt wird.
  104. ;;;    Die Zeilenkoordinate läuft im Bereich [0..length(screen.text)[, die
  105. ;;;    zur Zeilenkoordineate lin gehörige Spaltenkoordinate läuft im Bereich
  106. ;;;    [0..length(screen.text[lin])[ (manchmal auch einschließlich der rechten
  107. ;;;    Grenze).
  108. ;;;
  109. ;;; Umrechnung:
  110. ;;; ===========
  111. ;;; (a) -> (b):
  112. ;;;   (lin, col) --> (lin - screen.phys-top-lin, col - screen.phys-left-col)
  113. ;;; (b) -> (c):
  114. ;;;   (lin, col) --> (lin + screen.top-lin, col + screen.left-col)
  115.  
  116. ;-------------------------------------------------------------------------------
  117.  
  118. ;;; Datenstrukturen für Screens
  119.  
  120. ;; Eine ZEILE ist ein String, adjustable mit Fill-pointer.
  121.  
  122. ;; Liefert neue Zeile der Größe >= size und der Länge size
  123. (defun get-new-line (size)
  124.   (make-array size
  125.               :element-type 'string-char
  126.               :adjustable t :fill-pointer size
  127. ) )
  128.  
  129. ;; Ein TEXT ist ein Push-Vektor von Zeilen.
  130. (defun make-empty-text (&optional (len global-screen-height))
  131.   (let ((text (make-array len :adjustable t :fill-pointer 0)))
  132.     (vector-push (get-new-line 0) text)
  133.     text
  134. ) )
  135.  
  136. ;; Eine MARKE besteht aus zwei Integers >= 0 (Zeile, Spalte)
  137. (defmacro make-mark (lin col) `(CONS ,lin ,col))
  138. (defmacro mark-lin (mark) `(CAR ,mark))
  139. (defmacro mark-col (mark) `(CDR ,mark))
  140.  
  141. ;; Die Marke (lin,col) heißt für den Text text GÜLTIG, wenn gilt
  142. ;; 0 <= lin < length(text), 0 <= col <= length(text[lin])
  143. ;; (Marken sind immer in Textkoordinaten angegeben.)
  144.  
  145. ;; Ein SCREEN besteht u.a. aus einem Text mit Cursorposition und Marken, sowie
  146. ;; Angaben über den Fensterausschnitt und die physikalische Lage auf dem Schirm
  147. (defstruct (screen (:copier nil) (:constructor mk-screen))
  148.   (text (make-empty-text))    ; Text des Screens
  149.   (lin 0 :type integer)       ; Cursorzeile
  150.   (col 0 :type integer)       ; Cursorspalte, (lin,col) ist für den Text gültig
  151.   (saved-col 0 :type integer) ; gemerkte Spalte
  152.   (marks (make-array 12 :adjustable t :fill-pointer 12 :initial-element nil))
  153.     ; Vektor von Marken, die für den Text gültig sind, oder NIL; Länge >= 12.
  154.     ; Die ersten beiden bestimmen den markierten Block.
  155.   (height global-screen-height :type integer) ; Höhe des Bildausschnitts
  156.   (width  global-screen-width  :type integer) ; Breite des Bildausschnitts
  157.   (top-lin  0 :type integer) ; Index der obersten Zeile im Fenster
  158.   (left-col 0 :type integer) ; Index der linkesten Spalte im Fenster
  159.                              ; (Textkoordinaten)
  160.   (visibility nil :type vector) ; Vektor von Listen von Conses: Zu jeder Zeile
  161.                                 ;  die sichtbaren Abschnitte
  162.   (full? t)                  ; Flag, ob ganzer Schirm
  163.   (phys-left-col 0 :type integer) ; physikalische Koordinaten der linken oberen
  164.   (phys-top-lin  0 :type integer) ; Fensterecke (ohne Rahmen)
  165.                                   ; (Bildschirmkoordinaten)
  166.   (title "" :type string)    ; Titel, nur wenn nicht full?
  167.   (olchar nil :type (or null character)) ; obere linke Ecke, nur wenn nicht full?
  168. )
  169.  
  170. ;; Bedingungen:
  171. ;; 0 <= top-lin < length(text)
  172. ;; 0 <= left-col
  173.  
  174. ;; 0 <= phys-left-col
  175. ;; phys-left-col + width <= global-screen-width
  176. ;; 0 <= phys-top-lin
  177. ;; phys-top-lin + height <= global-screen-height
  178. ;; Falls not full?: jeweils < statt <=
  179.  
  180. ;; visibility ist ein Vektor der Länge height + 2, Einträge sind Listen
  181. ;; ((l_1 . r_1) (l_2 . r_2) ... (l_n . r_n)) mit
  182. ;; -1 <= l_1 < r_1 < l_2 < r_2 < ... < l_n < r_n <= width + 1.
  183. ;; Bedeutung der Liste visibility[i]: Von Zeile i-1 (Zeile -1 ist die
  184. ;; Titelzeile, Zeile height die untere Rahmenzeile, analog für Spalten
  185. ;; -1, width; das sind Fensterkoordinaten) sind die Abschnitte
  186. ;; [l_1..r_1[, [l_2..r_2[, ..., [l_n..r_n[ sichtbar.
  187.  
  188. ;; make-screen erzeugt einen Screen. Ohne Argumente erhält man einen Screen,
  189. ;; der den ganzen Bildschirm umfaßt, ansonsten einen mit Rahmen.
  190. (defun make-screen (&key height width left-col top-lin title olchar)
  191.   (if (or height width left-col top-lin title olchar)
  192.     ;; wenigstens ein Argument angegeben
  193.     (let ((min-height 1) (min-width 10))
  194.       (setq height
  195.             (max min-height ; Höhe in den erlaubten Bereich bringen (>= min-height)
  196.               (if height
  197.                 (min height (- global-screen-height 2))
  198.                 ;; Default: Zwei Drittel der Bildschirmhöhe
  199.                 (- (floor (* global-screen-height 0.67s0)) 2)
  200.       )     ) )
  201.       (setq width
  202.             (max min-width ; Breite in den erlaubten Bereich bringen (>= min-width)
  203.               (if width
  204.                 (min width (- global-screen-width 2))
  205.                 ;; Default: Halbe Bildschirmbreite
  206.                 (- (ash global-screen-width -1) 2)
  207.       )     ) )
  208.       (if top-lin
  209.         ;; Oberste Zeile in den erlaubten Bereich bringen und ggfs. Höhe
  210.         ;; anpassen
  211.         (setq top-lin (min (max 1 top-lin) (- global-screen-height min-height 1))
  212.               height (min height (- global-screen-height top-lin 1))
  213.         )
  214.         ;; Default: So, daß Fenster in der Mitte sitzt
  215.         (setq top-lin (max 1 (ash (- global-screen-height height) -1)))
  216.       )
  217.       (if left-col
  218.         ;; Linkeste Spalte in den erlaubten Bereich bringen und ggfs. Breite
  219.         ;; anpassen
  220.         (setq left-col (min (max 1 left-col) (- global-screen-width min-width 1))
  221.               width (min width (- global-screen-width left-col 1))
  222.         )
  223.         ;; Default: So, daß Fenster in der Mitte sitzt
  224.         (setq left-col (max 1 (ash (- global-screen-width width) -1)))
  225.       )
  226.       (mk-screen :height height :width width :full? nil
  227.                  :title (or title "") :olchar olchar
  228.                  :phys-left-col left-col :phys-top-lin top-lin
  229.                  :text (make-empty-text height)
  230.                  :visibility (make-array (+ height 2) :initial-element '())
  231.     ) )
  232.     (mk-screen :visibility
  233.                (make-array (+ global-screen-height 2) :initial-element '())
  234. ) ) )
  235.  
  236. ;-------------------------------------------------------------------------------
  237.  
  238. ;; Hilfsfunktion: Testet, ob gegebener adjustable Array mit Fillpointer
  239. ;; groß genug ist, und vergrößert, wenn nicht
  240. ;; Fill-pointer wird auf neue Größe gesetzt
  241. (defun resize-array (array size &optional (increment 10))
  242.   (if (>= (array-dimension array 0) size)
  243.     (setf (fill-pointer array) size)
  244.     (adjust-array array (+ size increment) :fill-pointer size)
  245. ) )
  246.  
  247. ;; Hilfsfunktion: verringert den Fill-Pointer eines gegebenen
  248. ;; adjustable Array und löscht die dabei wegfallenden Elemente.
  249. (defun shrink-array (array delta)
  250.   (let* ((end (fill-pointer array))
  251.          (start (- end delta)))
  252.     (setf (fill-pointer array) start)
  253.     (when (eq (array-element-type array) 'T)
  254.       (do ((index start (1+ index)))
  255.           ((eql index end))
  256.         (setf (aref array index) nil)
  257. ) ) ) )
  258.  
  259. ;-------------------------------------------------------------------------------
  260.  
  261. ;;; Funktionen für das Textfenster (intern)
  262.  
  263. ;; Ausgabe eines mit Leerstellen gefüllten Zeilenstücks:
  264. (defun display-blanks (left-col right-col)
  265.   ; Auf Terminals sind diese vielen Leerstellen laangsaam...
  266.   (let ((count (- right-col left-col)))
  267.     (if (and (> count 3) (>= right-col global-screen-width))
  268.       (screen-clear-end-of-line)
  269.       (write-string blanks *window* :end count)
  270.   ) )
  271. )
  272.  
  273. ;; Ausgabe einer Zeile:
  274. ;; line:     auszugebende Zeile
  275. ;; mark-start, mark-end:   NIL oder zu markierender Bereich der Zeile
  276. ;; [left-col..right-col[:  darzustellendes Intervall der Zeile
  277. ;; left-arrow?: Flag, ob in der ersten Spalte ein Pfeil nach rechts ausgegeben
  278. ;;              werden soll, wenn dort ein Zeichen stünde
  279. ;; right-arrow? : Analog für die letzte Spalte
  280. ;; Cursor muß sich an der richtigen Position auf dem Bildschirm befinden,
  281. ;; reverse off, wrap off
  282. ;; right-col - left-col >= [left-arrow?] + [right-arrow?]
  283. (defun display-line (line mark-start mark-end left-col right-col
  284.                      #+DOSE left-arrow? #+DOSE right-arrow?
  285.                     )
  286.   (unless (> (length line) left-col) ; Zeile vorher zu Ende
  287.     (display-blanks left-col right-col)
  288.     (return-from display-line)
  289.   )
  290.   #+DOSE
  291.   (when left-arrow? ; Pfeil nach links ist evtl. auszugeben
  292.     (write-char #\Code17 *window*) ; Pfeil nach links
  293.     (incf left-col) ; jetzt right-col - left-col >= [right-arrow?]
  294.   ) ; hier stets length(line) >= left-col
  295.   (let ((right-col-1 right-col))
  296.     #+DOSE
  297.     (when right-arrow? (decf right-col-1)) ; Pfeil nach rechts ist evtl. auszugeben
  298.     (let ((end-col (min (length line) right-col-1))) ; stets end-col >= left-col
  299.       (cond
  300.         ((or (null mark-start) (null mark-end)
  301.              (<= mark-end left-col) (>= mark-start end-col)
  302.          )
  303.           ;; Zeile ganz außerhalb des markierten Bereichs
  304.           (write-string line *window* :start left-col :end end-col)
  305.         )
  306.         ((and (<= mark-start left-col) (<= end-col mark-end))
  307.           ;; Zeile ganz innerhalb des markierten Bereichs: reverse darstellen
  308.           (screen-reverse-on)
  309.           (write-string line *window* :start left-col :end end-col)
  310.           (screen-reverse-off)
  311.         )
  312.         (t ;; sonst: markierten Teil herauspicken und reverse darstellen
  313.            (setq mark-start (max mark-start left-col))
  314.            (setq mark-end (min mark-end end-col))
  315.            (write-string line *window* :start left-col :end mark-start)
  316.            (screen-reverse-on)
  317.            (write-string line *window* :start mark-start :end mark-end)
  318.            (screen-reverse-off)
  319.            (write-string line *window* :start mark-end :end end-col)
  320.       ) )
  321.       (if (eql end-col (length line)) ; Zeile vor dem rechten Rand zu Ende?
  322.         (display-blanks end-col right-col)
  323.         #+DOSE
  324.         (when right-arrow?
  325.           (write-char #\Code16 *window*) ; Pfeil nach rechts
  326.         )
  327. ) ) ) )
  328.  
  329. ;; Ausgabe eines Zeilenstücks:
  330. ;; Zeile lin des screens von Spalte left (einschl.) bis right (ausschl.)
  331. ;; anzeigen (Fensterkoordinaten)
  332. (let ((ohchar #-DOSE #\= #+DOSE #\Code205) ; oberer horizontaler Balken
  333.       (olchar #-DOSE #\# #+DOSE #\Code213) ; obere linke Ecke
  334.       (orchar #-DOSE #\# #+DOSE #\Code184) ; obere rechte Ecke
  335.       (uhchar #-DOSE #\- #+DOSE #\Code196) ; unterer horizontaler Balken
  336.       (ulchar #-DOSE #\+ #+DOSE #\Code192) ; untere linke Ecke
  337.       (urchar #-DOSE #\+ #+DOSE #\Code217) ; untere rechte Ecke
  338.       (lvchar #-DOSE #\| #+DOSE #\Code179) ; linker vertikaler Balken
  339.       (rvchar #-DOSE #\| #+DOSE #\Code179) ; rechter vertikaler Balken
  340.      )
  341.   (defun show-screen-line (screen lin left right)
  342.     (let ((height (screen-height screen)) ; Größe und Position des Screens
  343.           (width (screen-width screen))
  344.           (phys-left-col (screen-phys-left-col screen))
  345.           (phys-top-lin (screen-phys-top-lin screen))
  346.          )
  347.       ;; Bereichsüberschreitungen abfangen:
  348.       (if (screen-full? screen)
  349.         (setq left (max left 0) right (min right width))
  350.         (setq left (max left -1) right (min right (+ width 1)))
  351.       )
  352.       (when (and (> right left) ; Trifft angegebener Bereich das Fenster?
  353.                  (if (screen-full? screen) (< -1 lin height) (<= -1 lin height))
  354.             )
  355.         ;; Cursor positionieren
  356.         (screen-set-cursor (+ phys-top-lin lin) (+ phys-left-col left))
  357.         (cond
  358.           ((eql lin -1) ; Titelzeile
  359.             (let* ((title (screen-title screen))
  360.                    (tstr (string-concat
  361.                            (string (or (screen-olchar screen) olchar))
  362.                            (if (< (length title) width)
  363.                              (format nil "~V,,0,V:@<~A~>" width ohchar title)
  364.                              (subseq title 0 width)
  365.                            )
  366.                            (string orchar)
  367.                   ))     )
  368.               (write-string tstr *window* :start (1+ left) :end (1+ right))
  369.           ) )
  370.           ((eql lin height) ; untere Rahmenzeile
  371.             (when (eql left -1) (write-char ulchar *window*) (setq left 0))
  372.             (dotimes (i (- (if (eql right (+ width 1)) width right) left))
  373.               (write-char uhchar *window*)
  374.             )
  375.             (when (eql right (+ width 1)) (write-char urchar *window*))
  376.           )
  377.           (t (let* ((text (screen-text screen))
  378.                     (text-lin (+ lin (screen-top-lin screen)))
  379.                     (left-col (screen-left-col screen))
  380.                     (line (if (< text-lin (length text))
  381.                             (aref text text-lin)
  382.                             ""
  383.                     )     )
  384.                     (marks (screen-marks screen))
  385.                     (mark-start (aref marks 0)) ; Blockanfang
  386.                     (mark-end (aref marks 1))   ; Blockende
  387.                    )
  388.                ;; evtl. Stück vom linken Rahmen
  389.                (when (eql left -1) (write-char lvchar *window*) (setq left 0))
  390.                ;; Teil der Zeile ausgeben
  391.                (display-line
  392.                  line
  393.                  ;; Beginn Markierung oder nil
  394.                  (and mark-start
  395.                       (cond ((eql (mark-lin mark-start) text-lin)
  396.                               (mark-col mark-start)
  397.                             )
  398.                             ((< (mark-lin mark-start) text-lin) 0)
  399.                             (t nil)
  400.                  )    )
  401.                  ;; Ende Markierung oder nil
  402.                  (and mark-end
  403.                       (cond ((eql (mark-lin mark-end) text-lin)
  404.                               (mark-col mark-end)
  405.                             )
  406.                             ((> (mark-lin mark-end) text-lin) (length line))
  407.                             (t nil)
  408.                  )    )
  409.                  ;; linke Spalte (Textkoord.)
  410.                  (+ left-col left)
  411.                  ;; rechte Spalte + 1 (Textkoord.)
  412.                  (+ left-col (min right width))
  413.                  ;; Left-Arrow, falls left-col > 0 und erste Fensterspalte
  414.                  ;; dargestellt wird
  415.                  #+DOSE (and (plusp left-col) (eql left 0))
  416.                  ;; Right-Arrow, falls letzte Fensterspalte
  417.                  ;; dargestellt wird
  418.                  #+DOSE (>= right width)
  419.                )
  420.                ;; evtl. Stück vom rechten Rahmen
  421.                (when (eql right (+ width 1)) (write-char rvchar *window*))
  422.   ) ) ) ) )  )
  423. )
  424.  
  425. ;; Ausgabe eines Zeilenstücks:
  426. ;; Zeile lin des screens (im Inneren) von Spalte left (einschl.) bis right
  427. ;; (ausschl.) (Fensterkoordinaten) anzeigen unter Berücksichtigung des
  428. ;; visibility-Vektors.
  429. (defun show-screen-line-v (screen lin left right)
  430.   (let ((height (screen-height screen))
  431.         (width (screen-width screen))
  432.         (visibility (screen-visibility screen))
  433.        )
  434.     ;; Bereichsüberschreitungen abfangen:
  435.     (setq left (max left 0) right (min right width))
  436.     (when (and (< left right) (< -1 lin height))
  437.       ;; trifft angegebener Bereich das Fensterinnere?
  438.       ;; Ja: dann die einzelnen Abschnitte abarbeiten
  439.       (dolist (part (aref visibility (1+ lin)))
  440.         (when (and (> (cdr part) left) (< (car part) right))
  441.           (show-screen-line screen lin (max left (car part))
  442.                                        (min right (cdr part))
  443. ) ) ) ) ) )
  444.  
  445. ;; Ausgabe eines Fensters:
  446. ;; screen: Auszugebendes Textfenster
  447. ;; start-lin: Zeile, ab der angezeigt werden soll
  448. ;; end-lin: Zeile, bis vor die angezeigt werden soll (Fensterkoordinaten)
  449. ;; 0 <= start-lin <= end-lin <= screen.height
  450. ;; Liefert screen zurück.
  451. ;; reverse off, wrap off
  452. (defun display-screen (screen &optional (start-lin 0)
  453.                                         (end-lin (screen-height screen))
  454.                       )
  455.   (do ((width (screen-width screen))
  456.        (screen-lin start-lin (1+ screen-lin))
  457.       )
  458.       ((eql screen-lin end-lin) t)
  459.     (show-screen-line-v screen screen-lin 0 width)
  460. ) )
  461.  
  462. ;;; Funktionen zur Verwaltung der visibility-Vektoren
  463.  
  464. ;; Nimm aus einer visibility-Liste das Intervall [left..right[ heraus
  465. (defun update-visibility-list-1 (vl left right)
  466.   ;; Entferne die Einträge, die ganz verdeckt werden
  467.   (setq vl (delete-if #'(lambda (pair)
  468.                           (and (<= left (car pair)) (<= (cdr pair) right))
  469.                         )
  470.                       vl
  471.   )        )
  472.   ;; Bestimme die Einträge (falls vorhanden), in deren Bereich eine der Grenzen
  473.   ;; fällt: diese müssen verkürzt werden
  474.   (let ((left-v (member-if #'(lambda (pair) (< (car pair) left (cdr pair))) vl))
  475.         (right-v (member-if #'(lambda (pair) (< (car pair) right (cdr pair))) vl)))
  476.     ;; (car left-v) und (car right-v) sind zu verkürzen:
  477.     (if (and left-v right-v (eq left-v right-v))
  478.       ;; zu entfernender Bereich innerhalb eines Teilintervalls: in zwei teilen
  479.       ; (... (A . B) ...) --> (... (A . left) (right . B) ...)
  480.       (push (cons right (shiftf (cdr (car left-v)) left)) (cdr left-v))
  481.       (progn
  482.         (when left-v (setf (cdr (car left-v)) left))
  483.         (when right-v (setf (car (car right-v)) right))
  484.   ) ) )
  485.   ;; veränderte Liste zurückgeben
  486.   vl
  487. )
  488.  
  489. ;; Füge in eine visibility-Liste das Intervall [left..right[ ein (unter der
  490. ;; Annahme, daß es zu den vorhandenen Intervallen disjunkt ist).
  491. (defun update-visibility-list-2 (vl left right)
  492.   (let ((vl1 nil) (vl2 vl))
  493.     (loop ; vl1 und vl2 laufen durch die Liste vl.
  494.           ; Entweder vl1 = nil oder (cdr vl1) = vl2.
  495.           ; Das Intervall [left..right[ ist jedenfalls nach vl1 einzufügen.
  496.       (when (or (null vl2) (<= right (caar vl2))) (return))
  497.       (shiftf vl1 vl2 (cdr vl2))
  498.     )
  499.     ; Das Intervall ist zwischen vl1 und vl2 einzukleben.
  500.     (if (or (null vl2) (< right (caar vl2)))
  501.       (push (cons left right) vl2)
  502.       (setf (caar vl2) left) ; ersetze (caar vl2) = right durch left
  503.     )
  504.     ; Nun ist (caar vl2) = left. vl2 ist an vl1 anzuschließen.
  505.     (if (null vl1)
  506.       (setq vl vl2)
  507.       (if (eql (cdar vl1) left)
  508.         ; (car vl1) und (car vl2) vereinigen:
  509.         (setf (cdar vl1) (cdar vl2) (cdr vl1) (cdr vl2))
  510.         ; vl2 als (cdr vl1) anschließen:
  511.         (setf (cdr vl1) vl2)
  512.   ) ) )
  513.   vl
  514. )
  515.  
  516. ;; Nimm aus dem visibility-Vektor von Screen den Bereich heraus, der durch
  517. ;; [top-lin..bot-lin[ x [left-col..right-col[ (in Bildschirmkoordinaten)
  518. ;; gegeben ist.
  519. (defun update-visibility (screen top-lin bot-lin left-col right-col)
  520.   (let* ((s-top-lin (screen-phys-top-lin screen))
  521.          (s-left-col (screen-phys-left-col screen))
  522.          (visibility (screen-visibility screen))
  523.          ;; Umrechnen auf Fensterkoordinaten
  524.          (rel-top-lin (max -1 (- top-lin s-top-lin)))
  525.          (rel-bot-lin (min (+ (screen-height screen) 1) (- bot-lin s-top-lin)))
  526.          (rel-left-col (max -1 (- left-col s-left-col)))
  527.          (rel-right-col (min (+ (screen-width screen) 1) (- right-col s-left-col)))
  528.         )
  529.     (when (and (> rel-bot-lin rel-top-lin) (> rel-right-col rel-left-col))
  530.       ;; Schnitt ist nicht leer
  531.       (do ((index (1+ rel-top-lin) (1+ index))
  532.            (end-index (1+ rel-bot-lin))
  533.           )
  534.           ((eql index end-index))
  535.         ;; Für jede Zeile im Schnitt visibility-Liste updaten
  536.         (setf (aref visibility index)
  537.               (update-visibility-list-1 (aref visibility index)
  538.                                         rel-left-col rel-right-col
  539. ) ) ) ) )     )
  540.  
  541. ;; Mache alle Screens der Liste screens im Bereich lin, [left..right[
  542. ;; (Bildschirmkoordinaten) sichtbar, soweit sie sich nicht überlappen.
  543. ;; (Vorher waren sie dort nicht sichtbar gewesen.)
  544. ;; Die visibility-Listen werden entsprechend aktualisiert.
  545. (defun show-newly-visible-line-parts (screens lin left right)
  546.   (unless (null screens) ; nur etwas zu tun, wenn Screens vorhanden
  547.     (let* ((screen (first screens))
  548.            (screens (rest screens))
  549.            ;; Wir können hier davon ausgehen, daß jeder Screen einen Rand
  550.            ;; der Breite 1 hat, denn der einzige Screen mit full? = nil
  551.            ;; ist der ganze Bildschirm, und dessen "Rand" wäre unsichtbar.
  552.            ;; (Es ist ja 0 <= left < right <= global-screen-width und
  553.            ;; und 0 <= lin < global-screen-height.)
  554.            (height (screen-height screen))
  555.            (width+1 (+ (screen-width screen) 1))
  556.            (left-col (screen-phys-left-col screen))
  557.            (visibility (screen-visibility screen))
  558.            ;; Umrechnen auf Fensterkoordinaten
  559.            (rel-lin (- lin (screen-phys-top-lin screen)))
  560.            (rel-left (- left left-col))
  561.            (rel-right (- right left-col))
  562.           )
  563.       (if (and (<= -1 rel-lin height) (<= 0 rel-right) (< rel-left width+1))
  564.         ;; Screen screen ist betroffen
  565.         (progn
  566.           ;; visibility-Liste updaten
  567.           (setf (aref visibility (1+ rel-lin))
  568.                 (update-visibility-list-2 (aref visibility (1+ rel-lin))
  569.                                           (max -1 rel-left)
  570.                                           (min width+1 rel-right)
  571.           )     )
  572.           ;; falls nötig, links darunter liegende Screens ansprechen
  573.           (when (< rel-left -1)
  574.             (show-newly-visible-line-parts screens lin left (1- left-col))
  575.           )
  576.           ;; betroffenes Zeilenstück ausgeben
  577.           (show-screen-line screen rel-lin rel-left rel-right)
  578.           ;; falls nötig, rechts darunter liegende Screens ansprechen
  579.           (when (> rel-right width+1)
  580.             (show-newly-visible-line-parts screens lin (+ left-col width+1) right)
  581.         ) )
  582.         ;; sonst direkt zu den nächsten Screens weitergehen
  583.         (show-newly-visible-line-parts screens lin left right)
  584. ) ) ) )
  585.  
  586. ;-------------------------------------------------------------------------------
  587.  
  588. ;;; Implementierung der Interface-Funktionen
  589.  
  590. ;; Liste der auf dem Bildschirm dargestellten Screens, geordnet nach ihrer
  591. ;; Verdeckungs-Rangfolge (d.h. der oberste zuerst).
  592. (defvar *screens* '())
  593.  
  594. ;; Cursorposition im screen setzen (Textkoordinaten), Wert T.
  595. (defun set-cursor (screen lin &optional (col (screen-saved-col screen) col-s))
  596.   (let* ((text (screen-text screen))
  597.          (text-len (length text)))
  598.     ;; Bereichsüberschreitungen abfangen:
  599.     (setq lin (max 0 (min lin (1- text-len))))
  600.     (setq col (max 0 (min col (length (aref text lin)))))
  601.     ;; neue Position vermerken
  602.     (setf (screen-lin screen) lin (screen-col screen) col)
  603.     ;; falls Spalte angegeben, gemerkte Spalte setzen
  604.     (when col-s (setf (screen-saved-col screen) col))
  605.     t
  606. ) )
  607.  
  608. ;; vertikales Scrollen eines Textfensters; upgedateter screen wird zurück-
  609. ;; gegeben
  610. ;; n > 0: n Zeilen nach oben scrollen
  611. ;; n = 0: nichts tun
  612. ;; n < 0: -n Zeilen nach unten scrollen
  613. ;; flag /= nil: Cursor mitverschieben
  614. (defun scroll-vertical (screen n &optional (flag nil))
  615.   (let* ((text (screen-text screen))
  616.          (text-len (length text))
  617.          (top-lin (screen-top-lin screen))
  618.         )
  619.     ;; evtl. Cursor updaten
  620.     (when flag (set-cursor screen (+ (screen-lin screen) n)))
  621.     ;; Bereichsüberschreitungen abfangen:
  622.     (setq n (max (- top-lin) (min n (- text-len 1 top-lin))))
  623.     ;; Datenstruktur updaten
  624.     (setf (screen-top-lin screen) (+ top-lin n))
  625.     (when (eql n 0) (return-from scroll-vertical screen))
  626.     (cond ((or (> (abs n) 10)
  627.                (not (screen-full? screen))
  628.                (null *screens*)
  629.                (not (eq screen (first *screens*)))
  630.            )
  631.             ;; n groß oder nicht der ganze Bildschirm oder nicht oberster
  632.             ;; Screen: Fenster neu schreiben
  633.             (display-screen screen)
  634.           )
  635.           ((plusp n) ; nach oben
  636.             (screen-home)
  637.             (dotimes (i n) (screen-delete-line))
  638.             (display-screen screen (- (screen-height screen) n))
  639.           )
  640.           (t ; nach unten
  641.             (screen-home)
  642.             (dotimes (i (- n)) (screen-insert-line))
  643.             (display-screen screen 0 (- n))
  644. ) ) )     )
  645.  
  646. ;; horizontales Scrollen des Textfensters; upgedateter screen zurück
  647. ;; n > 0: um n Spalten nach links scrollen
  648. ;; n = 0: nichts tun
  649. ;; n < 0: um -n Spalten nach rechts scrollen
  650. (defun scroll-horizontal (screen n)
  651.   (let ((left-col (screen-left-col screen)))
  652.     (when (minusp (+ left-col n)) (setq n (- left-col)))
  653.     (if (eql n 0)
  654.       screen
  655.       (progn (setf (screen-left-col screen) (+ left-col n))
  656.              (display-screen screen)
  657. ) ) ) )
  658.  
  659. ;; Cursor setzen und Textfenster ggfs. so verändern, daß Cursor im Fenster ist,
  660. ;; Cursor einschalten - nur wenn oberster Screen
  661. ;; center: Flag, ob Cursor möglichst in der Mitte erscheinen soll
  662. ;; liefert T zurück
  663. (defun set-cursor-visible (screen &optional (center nil))
  664.   (let* ((lin (screen-lin screen))
  665.          (col (screen-col screen))
  666.          (top-lin (screen-top-lin screen))
  667.          (left-col (screen-left-col screen))
  668.          (height (screen-height screen))
  669.          (width (screen-width screen))
  670.         )
  671.     (cond
  672.       ((<= (if (eql left-col 0) 0 (1+ left-col)) col (+ left-col width -2))
  673.         ;; Cursorspalte im Fensterbereich
  674.         (cond
  675.           ((< lin top-lin)
  676.             ;; Cursorzeile über dem Fenster -> nach unten scrollen
  677.             (scroll-vertical screen
  678.                              (- lin top-lin (if center (ash height -1) 0))
  679.           ) )
  680.           ((>= lin (+ top-lin height))
  681.             ;; Cursorzeile unter dem Fenster -> nach oben scrollen
  682.             (scroll-vertical screen
  683.                         (- lin top-lin -1 (if center (ash height -1) height))
  684.       ) ) ) )
  685.       ((<= top-lin lin (+ top-lin height -1))
  686.         ;; Cursorzeile im Fensterbereich, Cursorspalte aber nicht ->
  687.         ;;  nach rechts oder links scrollen
  688.         (scroll-horizontal screen
  689.             (- col left-col
  690.                (if (or center (< width 40))
  691.                  (ash width -1)
  692.                  (if (<= col left-col) (- width 20) 20)
  693.       ) )   )  )
  694.       ;; sonst: Fensterausschnitt neu setzen
  695.       (t (let ((new-left-col (if (< col (1- width))
  696.                                0
  697.                                (- col (if (or center (< width 40))
  698.                                         (ash width -1)
  699.                                         20
  700.                )             ) )      )
  701.                (new-top-lin (max 0 (- lin (ash height -1))))
  702.               )
  703.            (setf (screen-left-col screen) new-left-col
  704.                  (screen-top-lin screen) new-top-lin
  705.            )
  706.            (display-screen screen)
  707.   ) ) )  )
  708.   (when (and *screens* (eq screen (first *screens*))) ; oberster Screen?
  709.     (screen-set-cursor                    ; Cursor setzen
  710.       (+ (- (screen-lin screen) (screen-top-lin screen))
  711.          (screen-phys-top-lin screen)
  712.       )
  713.       (+ (- (screen-col screen) (screen-left-col screen))
  714.          (screen-phys-left-col screen)
  715.     ) )
  716.     (screen-cursor-on)                    ; und einschalten
  717.   )
  718.   t
  719. )
  720.  
  721. ;; Zeile lin ab Spalte col (Textkoordinaten) auffrischen, Wert T.
  722. (defun refresh-line (screen lin col)
  723.   (show-screen-line-v screen (- lin (screen-top-lin screen))
  724.                              (- col (screen-left-col screen))
  725.                              (screen-width screen)
  726.   )
  727.   t
  728. )
  729.  
  730. ;; Fenster ab Zeile lin bis vor Zeile end-lin (Textkoordinaten) auffrischen,
  731. ;; ab Zeile end-lin um |n| Zeilen scrollen (n>0: nach oben, n<0: nach unten),
  732. ;; Wert T.
  733. (defun refresh-screen (screen lin end-lin &optional (n 0))
  734.   (let ((top-lin (screen-top-lin screen))
  735.         (height (screen-height screen)))
  736.     (when (<= (+ top-lin height) lin)
  737.       ;; Bildschirminhalt kann unverändert bleiben
  738.       (return-from refresh-screen t)
  739.     )
  740.     (when (<= end-lin top-lin)
  741.       ;; Bildschirminhalt kann unverändert bleiben
  742.       (setf (screen-top-lin screen) (+ top-lin n))
  743.       (return-from refresh-screen t)
  744.     )
  745.     ;; Bildschirminhalt muß teilweise gescrollt werden
  746.     (when (or (> (abs n) 10)
  747.               (not (screen-full? screen))
  748.               (null *screens*)
  749.               (not (eq screen (first *screens*)))
  750.           )
  751.       ;; n groß oder nicht der ganze Bildschirm oder nicht oberster
  752.       ;; Screen: Fenster neu schreiben
  753.       (display-screen screen)
  754.       (return-from refresh-screen t)
  755.     )
  756.     ;; Scrollen
  757.     (cond ((minusp n) ; nach unten
  758.             (setq end-lin (max end-lin (- top-lin n)))
  759.             ; Wir haben  end-lin >= top-lin + |n|  erzwungen.
  760.             (let ((scroll-top (- (+ end-lin n) top-lin))) ; >=0
  761.               (when (< (- scroll-top n) height)
  762.                 (screen-set-cursor scroll-top 0)
  763.                 (dotimes (i (- n)) (screen-insert-line))
  764.           ) ) )
  765.           ((plusp n) ; nach oben
  766.             (let ((scroll-top (- end-lin top-lin))) ; >0
  767.               (when (< scroll-top height)
  768.                 (if (>= (+ scroll-top n) height)
  769.                   (display-screen screen scroll-top height)
  770.                   (progn
  771.                     (screen-set-cursor scroll-top 0)
  772.                     (dotimes (i n) (screen-delete-line))
  773.                     (display-screen screen (- height n) height)
  774.     )     ) ) ) ) )
  775.     ;; Bereich zwischen lin und end-lin anzeigen
  776.     (let ((screen-lin (max 0 (- lin top-lin)))
  777.           (screen-end-lin (min (- end-lin top-lin) height)))
  778.       (when (< screen-lin screen-end-lin)
  779.         (display-screen screen screen-lin screen-end-lin)
  780.   ) ) )
  781.   t
  782. )
  783.  
  784. ;; Fenster vom Bildschirm nehmen, Wert: neuer oberster Screen, falls vorhanden,
  785. ;; sonst NIL
  786. (defun hide-screen (screen)
  787.   (let* ((height+2 (+ (screen-height screen) 2))
  788.          (top-lin (screen-phys-top-lin screen))
  789.          (left-col (screen-phys-left-col screen))
  790.          (visibility (screen-visibility screen))
  791.          ;; screen in *screens* suchen
  792.          (screens (member screen *screens* :test #'eq))
  793.         )
  794.     (when screens ; wenn nicht da, ist nichts zu tun
  795.       (do ((index 0 (1+ index))
  796.            (lin (1- top-lin) (1+ lin))
  797.           )
  798.           ((eql index height+2))
  799.         ;; Zeilen einzeln durchgehen
  800.         (dolist (part (aref visibility index))
  801.           ;; freiwerdende Teile anzeigen
  802.           (show-newly-visible-line-parts
  803.             (rest screens) lin (+ left-col (car part)) (+ left-col (cdr part))
  804.         ) )
  805.         ;; Sichtbarkeit löschen
  806.         (setf (aref visibility index) '())
  807.       )
  808.       ;; screen aus den aktiven Screens entfernen
  809.       (setq *screens* (delete screen *screens* :test #'eq))
  810.     )
  811.     (first *screens*)
  812. ) )
  813.  
  814. ;; Fenster nach oben bringen
  815. (defun activate-screen (screen)
  816.   (let* ((height (screen-height screen))
  817.          (width (screen-width screen))
  818.          (top-lin (screen-phys-top-lin screen))
  819.          (left-col (screen-phys-left-col screen))
  820.          (bot-lin (+ top-lin height))
  821.          (right-col (+ left-col width))
  822.          (visibility (screen-visibility screen))
  823.          (left 0)
  824.          (right width)
  825.         )
  826.     (unless (and (not (null *screens*)) (eq screen (first *screens*)))
  827.       ;; falls schon oben, ist nichts zu tun
  828.       (unless (screen-full? screen)
  829.         ;; Rahmen berücksichtigen
  830.         (decf top-lin) (incf bot-lin)
  831.         (decf left-col) (incf right-col)
  832.         (decf left) (incf right)
  833.       )
  834.       ;; [top-lin..bot-lin[ x [left-col..right-col[ ist Screenbereich auf
  835.       ;; dem Bildschirm (in Bildschirmkoordinaten)
  836.       (do ((screens *screens* (rest screens)))
  837.           ((or (null screens) (eq (first screens) screen)))
  838.         ;; visibility updaten für darüber gewesenen Screen
  839.         (update-visibility (first screens) top-lin bot-lin left-col right-col)
  840.       )
  841.       ;; screen in der Liste nach vorne bringen
  842.       (setq *screens* (cons screen (delete screen *screens* :test #'eq)))
  843.       ;; visibility-Listen setzen und Zeilen anzeigen, wenn nötig
  844.       (if (screen-full? screen)
  845.         (dotimes (lin height)
  846.           (let ((new-vl (list (cons left right))))
  847.             (unless (equal (aref visibility (1+ lin)) new-vl)
  848.               (setf (aref visibility (1+ lin)) new-vl)
  849.               (show-screen-line screen lin left right)
  850.         ) ) )
  851.         (dotimes (lin (+ height 2))
  852.           (let ((new-vl (list (cons left right))))
  853.             (unless (equal (aref visibility lin) new-vl)
  854.               (setf (aref visibility lin) new-vl)
  855.               (show-screen-line screen (1- lin) left right)
  856.   ) ) ) ) ) )
  857.   t
  858. )
  859.  
  860. ;; Cursor und Marken mitführen bei Einfüge- und Löschoperationen
  861. (defun update-marks (screen lin1 col1 lin2 col2)
  862.   (flet ((new-lin-col (lin col) ; Berechne neue Koordinaten
  863.            (cond
  864.              ((eql lin1 lin2) ; alles in einer Zeile
  865.                (if (eql lin lin1) ; ändert sich nur, wenn in dieser Zeile
  866.                  (if (< col1 col)
  867.                    (values lin (+ col (- col2 col1)))
  868.                    (values lin (min col col2))
  869.                  )
  870.                  (values lin col)
  871.              ) )
  872.              ((> lin1 lin2) ; Löschen eines Textteils über mehrere Zeilen
  873.                (cond ((eql lin lin2) (values lin (min col col2)))
  874.                      ((eql lin lin1)
  875.                        (values lin2 (max (+ col (- col2 col1)) col2))
  876.                      )
  877.                      ((< lin2 lin lin1) (values lin2 col2))
  878.                      ((< lin1 lin) (values (+ lin (- lin2 lin1)) col))
  879.                      (t (values lin col))
  880.              ) )
  881.              (t (cond ((eql lin lin1) ; Einfügen eines Textteils über mehrere
  882.                         (if (> col col1) ; Zeilen
  883.                           (values lin2 (+ col (- col2 col1)))
  884.                           (values lin col)
  885.                       ) )
  886.                       ((< lin1 lin) (values (+ lin (- lin2 lin1)) col))
  887.                       (t (values lin col))
  888.         )) ) )  )
  889.     (let ((lin (screen-lin screen))
  890.           (col (screen-col screen))
  891.          )
  892.       ;; Cursor updaten
  893.       (if (and (eql lin lin1) (eql col col1))
  894.         (setf (screen-lin screen) lin2
  895.               (screen-col screen) col2
  896.               (screen-saved-col screen) col2
  897.         )
  898.         (multiple-value-bind (new-lin new-col) (new-lin-col lin col)
  899.           (setf (screen-lin screen) new-lin
  900.                 (screen-col screen) new-col
  901.     ) ) ) )
  902.     (let ((marks (screen-marks screen)))
  903.       ;; Marken updaten
  904.       (dotimes (i (length marks))
  905.         (let ((mark (aref marks i)))
  906.           (when mark
  907.             (multiple-value-bind (new-lin new-col)
  908.                 (new-lin-col (mark-lin mark) (mark-col mark))
  909.               (setf (mark-lin mark) new-lin
  910.                     (mark-col mark) new-col
  911. ) ) ) ) ) ) ) )
  912.  
  913. ;; Screen scrollen um n nach oben, dabei Cursor mitführen
  914. (defun scroll-screen (screen n)
  915.   (scroll-vertical screen n t)
  916.   t
  917. )
  918.  
  919. ;; mehrere Fenster nacheinander nach oben bringen
  920. ;; sozusagen  (mapc #'activate-screen screen-list)
  921. (defun activate-screens (screen-list)
  922.   (let ((pos (or (position-if #'screen-full? screen-list :from-end t) 0)))
  923.     ; Alle Screens vor pos werden vom Screen bei pos überdeckt, brauchen
  924.     ; also nicht gezeichnet zu werden.
  925.     (mapc #'activate-screen (nthcdr pos screen-list))
  926. ) )
  927.  
  928. ;###############################################################################
  929. ;;;; Full-Screen-Editor
  930. ;;;;
  931. ;;;; Michael Stoll, Jan./Feb. 1992
  932. ;;;; Bruno Haible 30.3.1992, 13.5.1992
  933.  
  934. (defmacro defun-doc (name lambdalist doc &body body)
  935.   `(PROGN
  936.      (DEFUN ,name ,lambdalist ,@body)
  937.      (SETF (DOCUMENTATION ',name 'FUNCTION) ,doc)
  938.      ',name
  939.    )
  940. )
  941.  
  942. ;===========================================================================
  943. ;  G R U N D F U N K T I O N E N   Z U R   T E X T M A N I P U L A T I O N
  944. ;===========================================================================
  945.  
  946. ;; Liste der bei Undo durchzuführenden Aktionen:
  947. (defvar *undo* '())
  948.  
  949. #|
  950. ; erstrangige, alles Bisherige überschattende Undo-Aktion:
  951. (defun undo1 (function)
  952.   (setq *undo* (list function))
  953. )
  954.  
  955. ; zweitrangige, akkumulierende Undo-Aktion:
  956. (defun undo2 (function)
  957.   (push function *undo*)
  958. )
  959.  
  960. ; drittrangige, nur Cursor-bewegende, Undo-Aktion:
  961. (defun undo3 (screen)
  962.   (let ((function
  963.           (let ((lin (screen-lin screen))
  964.                 (col (screen-col screen)))
  965.             #'(lambda () (set-cursor screen lin col))
  966.        )) )
  967.     (undo2 function)
  968. ) )
  969. |# ; vorerst:
  970. (defun undo1 (function) (declare (ignore function)))
  971. (defun undo2 (function) (declare (ignore function)))
  972. (defun undo3 (screen) (declare (ignore screen)))
  973.  
  974. ;-------------------------------------------------------------------------------
  975.  
  976. ;;; Cursor-Bewegung
  977.  
  978. (defun-doc cursor-up (screen)
  979.   #L{
  980.   DEUTSCH "Cursor nach oben"
  981.   ENGLISH "cursor up"
  982.   FRANCAIS "curseur vers le haut"
  983.   }
  984.   (let ((lin (screen-lin screen)))
  985.     (and (plusp lin)
  986.          (progn (undo3 screen) (set-cursor screen (1- lin)))
  987. ) ) )
  988.  
  989. (defun-doc cursor-down (screen)
  990.   #L{
  991.   DEUTSCH "Cursor nach unten"
  992.   ENGLISH "cursor down"
  993.   FRANCAIS "curseur vers le bas"
  994.   }
  995.   (let ((lin (screen-lin screen)))
  996.     (and (< lin (1- (length (screen-text screen))))
  997.          (progn (undo3 screen) (set-cursor screen (1+ lin)))
  998. ) ) )
  999.  
  1000. (defun-doc cursor-left (screen)
  1001.   #L{
  1002.   DEUTSCH "Cursor nach links"
  1003.   ENGLISH "cursor left"
  1004.   FRANCAIS "curseur à gauche"
  1005.   }
  1006.   (let ((lin (screen-lin screen))
  1007.         (col (screen-col screen)))
  1008.     (cond ((plusp col) (decf col))
  1009.           ((plusp lin)
  1010.             (decf lin) (setq col (length (aref (screen-text screen) lin))) )
  1011.           (t (return-from cursor-left nil))
  1012.     )
  1013.     (undo3 screen)
  1014.     (set-cursor screen lin col)
  1015. ) )
  1016.  
  1017. (defun-doc cursor-right (screen)
  1018.   #L{
  1019.   DEUTSCH "Cursor nach rechts"
  1020.   ENGLISH "cursor right"
  1021.   FRANCAIS "curseur à droite"
  1022.   }
  1023.   (let ((text (screen-text screen))
  1024.         (lin (screen-lin screen))
  1025.         (col (screen-col screen)))
  1026.     (cond ((< col (length (aref text lin))) (incf col))
  1027.           ((< lin (1- (length text))) (incf lin) (setq col 0))
  1028.           (t (return-from cursor-right nil))
  1029.     )
  1030.     (undo3 screen)
  1031.     (set-cursor screen lin col)
  1032. ) )
  1033.  
  1034. (defun-doc cursor-to-start-of-line (screen)
  1035.   #L{
  1036.   DEUTSCH "Cursor an den Zeilenanfang"
  1037.   ENGLISH "cursor to start of line"
  1038.   FRANCAIS "curseur au début de la ligne"
  1039.   }
  1040.   (let ((lin (screen-lin screen)))
  1041.     (undo3 screen)
  1042.     (set-cursor screen lin 0)
  1043. ) )
  1044.  
  1045. (defun-doc cursor-to-end-of-line (screen)
  1046.   #L{
  1047.   DEUTSCH "Cursor ans Zeilenende"
  1048.   ENGLISH "cursor to end of line"
  1049.   FRANCAIS "curseur à la fin de la ligne"
  1050.   }
  1051.   (let ((lin (screen-lin screen)))
  1052.     (undo3 screen)
  1053.     (set-cursor screen lin (length (aref (screen-text screen) lin)))
  1054. ) )
  1055.  
  1056. (defun-doc cursor-to-start-of-text (screen)
  1057.   #L{
  1058.   DEUTSCH "Cursor an den Textanfang"
  1059.   ENGLISH "cursor to start of text"
  1060.   FRANCAIS "curseur au début du texte"
  1061.   }
  1062.   (undo3 screen)
  1063.   (set-cursor screen 0 0)
  1064. )
  1065.  
  1066. (defun-doc cursor-to-end-of-text (screen)
  1067.   #L{
  1068.   DEUTSCH "Cursor ans Textende"
  1069.   ENGLISH "cursor to end of text"
  1070.   FRANCAIS "curseur à la fin du texte"
  1071.   }
  1072.   (undo3 screen)
  1073.   (let* ((text (screen-text screen))
  1074.          (text-len-1 (1- (length text))))
  1075.     (set-cursor screen text-len-1 (length (aref text text-len-1)))
  1076. ) )
  1077.  
  1078. (defun-doc page-up (screen)
  1079.   #L{
  1080.   DEUTSCH "Seite nach oben"
  1081.   ENGLISH "page up"
  1082.   FRANCAIS "une page plus haut"
  1083.   }
  1084.   (undo3 screen)
  1085.   (scroll-screen screen (- 1 (screen-height screen)))
  1086. )
  1087.  
  1088. (defun-doc page-down (screen)
  1089.   #L{
  1090.   DEUTSCH "Seite nach unten"
  1091.   ENGLISH "page down"
  1092.   FRANCAIS "une page plus bas"
  1093.   }
  1094.   (undo3 screen)
  1095.   (scroll-screen screen (- (screen-height screen) 1))
  1096. )
  1097.  
  1098. (defun-doc line-up (screen)
  1099.   #L{
  1100.   DEUTSCH "Zeile nach oben"
  1101.   ENGLISH "line up"
  1102.   FRANCAIS "une ligne plus haut"
  1103.   }
  1104.   (undo3 screen)
  1105.   (scroll-screen screen -1)
  1106. )
  1107.  
  1108. (defun-doc line-down (screen)
  1109.   #L{
  1110.   DEUTSCH "Zeile nach unten"
  1111.   ENGLISH "line down"
  1112.   FRANCAIS "une ligne plus bas"
  1113.   }
  1114.   (undo3 screen)
  1115.   (scroll-screen screen 1)
  1116. )
  1117.  
  1118. ;-------------------------------------------------------------------------------
  1119.  
  1120. ;; Marken
  1121.  
  1122. (defun set-mark-fn (n)
  1123.   (let ((index (+ n 2)))
  1124.     (labels ((set-mark (screen &optional (lin (screen-lin screen))
  1125.                                          (col (screen-col screen)) )
  1126.                (undo2 (let ((mark-n (aref (screen-marks screen) index)))
  1127.                         (if mark-n
  1128.                           #'(lambda () (setf (aref (screen-marks screen) index) nil))
  1129.                           (let ((old-lin (mark-lin mark-n)) (old-col (mark-col mark-n)))
  1130.                             #'(lambda () (set-mark screen old-lin old-col))
  1131.                )      ) ) )
  1132.                (setf (aref (screen-marks screen) index) (make-mark lin col))
  1133.             ))
  1134.       #'set-mark
  1135. ) ) )
  1136. (defun set-mark-doc (n)
  1137.   (format nil 
  1138.           #L{
  1139.           DEUTSCH "Marke ~D setzen"
  1140.           ENGLISH "set mark ~D"
  1141.           FRANCAIS "placer la marque ~D"
  1142.           }
  1143.           n
  1144. ) )
  1145.  
  1146. (defun cursor-to-mark-fn (n)
  1147.   (let ((index (+ n 2)))
  1148.     #'(lambda (screen)
  1149.         (undo3 screen)
  1150.         (let ((mark (aref (screen-marks screen) index)))
  1151.           (and mark (set-cursor screen (mark-lin mark) (mark-col mark)))
  1152.       ) )
  1153. ) )
  1154. (defun cursor-to-mark-doc (n)
  1155.   (format nil 
  1156.           #L{
  1157.           DEUTSCH "Cursor zu Marke ~D"
  1158.           ENGLISH "cursor to mark ~D"
  1159.           FRANCAIS "curseur à la marque ~D"
  1160.           }
  1161.               n
  1162. ) )
  1163.  
  1164. ;-------------------------------------------------------------------------------
  1165.  
  1166. ;; Region (start-lin start-col end-lin end-col) = Der Textbereich
  1167. ;; von (make-mark start-lin start-col) bis (make-mark end-lin end-col).
  1168.  
  1169. ;; Eine linelist ist eine umgedrehte nichtleere Liste von Zeilen, die keine
  1170. ;; Newlines enthalten und zwischen denen jeweils ein Newline zu denken ist:
  1171. ;; (stringn ... string0) mit n>=0 steht für den String
  1172. ;; (string-concat string0 newline-as-string ... newline-as-string stringn).
  1173.  
  1174. (defconstant newline-as-string (string #\Newline))
  1175.  
  1176. ;; Eine Region in eine Liste von Zeilen umwandeln
  1177. (defun region-to-linelist (screen start-lin start-col end-lin end-col)
  1178.   (let ((text (screen-text screen))
  1179.         (linelist '()))
  1180.     (if (eql start-lin end-lin)
  1181.       (push (subseq (aref text start-lin) start-col end-col) linelist)
  1182.       (progn
  1183.         (push (subseq (aref text start-lin) start-col) linelist)
  1184.         (do ((index (1+ start-lin) (1+ index)))
  1185.             ((eql index end-lin))
  1186.           (push (copy-seq (aref text index)) linelist)
  1187.         )
  1188.         (push (subseq (aref text end-lin) 0 end-col) linelist)
  1189.     ) )
  1190.     linelist
  1191. ) )
  1192.  
  1193. ;; String (der Newlines enthalten kann) in Linelist umwandeln:
  1194. (defun string-to-linelist (string)
  1195.   (let ((nlpos (position #\Newline string)))
  1196.     (if (null nlpos)
  1197.       (list string)
  1198.       (macrolet ((subseq (string a b)
  1199.                    `(make-array (- ,b ,a) :element-type 'string-char
  1200.                       :displaced-to ,string :displaced-index-offset ,a
  1201.                     )
  1202.                 ))
  1203.         (let ((linelist (list (subseq string 0 nlpos))))
  1204.           (loop
  1205.             (let ((pos (1+ nlpos)))
  1206.               (when (null (setq nlpos (position #\Newline string :start pos)))
  1207.                 (push (subseq string pos (length string)) linelist)
  1208.                 (return)
  1209.               )
  1210.               (push (subseq string pos nlpos) linelist)
  1211.           ) )
  1212.           linelist
  1213.       ) )
  1214. ) ) )
  1215.  
  1216. ;-------------------------------------------------------------------------------
  1217.  
  1218. ;;; Löschfunktionen
  1219.  
  1220. ;; delete-char löscht das Zeichen unter dem Cursor und liefert T zurück,
  1221. ;; wenn nicht am Zeilenende gewesen und Zeichen gelöscht, sonst NIL.
  1222. (defun-doc delete-char (screen)
  1223.   #L{
  1224.   DEUTSCH "Zeichen unter dem Cursor löschen"
  1225.   ENGLISH "delete character at cursor"
  1226.   FRANCAIS "effacer le caractère sous le curseur"
  1227.   }
  1228.   (let* ((text (screen-text screen))
  1229.          (lin (screen-lin screen))
  1230.          (col (screen-col screen))
  1231.          (line (aref text lin))
  1232.          (line-len (length line))
  1233.         )
  1234.     ;; Am Zeilenende?
  1235.     (when (eql col line-len) (return-from delete-char nil))
  1236.     ;; Zeichen löschen
  1237.     (undo2 (let ((c (aref line col)))
  1238.              #'(lambda () (insert-char screen c) (cursor-left screen))
  1239.     )      )
  1240.     (replace line line :start1 col :start2 (1+ col))
  1241.     (decf (fill-pointer line))
  1242.     ;; Updaten
  1243.     (update-marks screen lin (1+ col) lin col)
  1244.     (refresh-line screen lin col)
  1245. ) )
  1246.  
  1247. ;; combine-lines vereinigt die Cursorzeile mit der folgenden
  1248. ;; liefert T zurück, wenn Cursorzeile nicht die letzte war, sonst NIL.
  1249. (defun-doc combine-lines (screen)
  1250.   #L{
  1251.   DEUTSCH "Cursorzeile mit der nächsten vereinigen"
  1252.   ENGLISH "combine two lines"
  1253.   FRANCAIS "joindre la ligne du curseur à la suivante"
  1254.   }
  1255.   (let* ((text (screen-text screen))
  1256.          (lin (screen-lin screen))
  1257.          (lin+1 (1+ lin))
  1258.          (line (aref text lin))
  1259.          (line-len (length line))
  1260.         )
  1261.     ;; Letzte Zeile?
  1262.     (when (eql lin+1 (length text)) (return-from combine-lines nil))
  1263.     ;; Zeilen zusammenhängen
  1264.     (undo2
  1265.       (let ((col (screen-col screen)))
  1266.         #'(lambda ()
  1267.             (set-cursor screen lin line-len)
  1268.             (insert-line screen)
  1269.             (set-cursor screen lin col)
  1270.     ) )   )
  1271.     (let ((second-line (aref text lin+1)))
  1272.       (resize-array line (+ line-len (length second-line)))
  1273.       (replace line second-line :start1 line-len)
  1274.     )
  1275.     ;; Zeilen darunter hinaufschieben
  1276.     (replace text text :start1 lin+1 :start2 (1+ lin+1))
  1277.     (shrink-array text 1)
  1278.     ;; Updaten
  1279.     (update-marks screen lin+1 0 lin line-len)
  1280.     (refresh-screen screen lin lin+1 1)
  1281. ) )
  1282.  
  1283. (defun-doc delete-char-1 (screen)
  1284.   #L{
  1285.   DEUTSCH "Zeichen unter dem Cursor löschen, zeilenübergreifend"
  1286.   ENGLISH "delete character at cursor, across lines"
  1287.   FRANCAIS "effacer le caractère sous le curseur, à travers lignes"
  1288.   }
  1289.   (or (delete-char screen) (combine-lines screen))
  1290. )
  1291.  
  1292. (defun-doc backspace (screen)
  1293.   #L{
  1294.   DEUTSCH "Zeichen links vom Cursor löschen"
  1295.   ENGLISH "delete character before cursor"
  1296.   FRANCAIS "effacer le caractère avant le curseur"
  1297.   }
  1298.   (and (plusp (screen-col screen))
  1299.        (cursor-left screen)
  1300.        (delete-char screen)
  1301. ) )
  1302.  
  1303. (defun-doc backspace-1 (screen)
  1304.   #L{
  1305.   DEUTSCH "Zeichen links vom Cursor löschen, zeilenübergreifend"
  1306.   ENGLISH "delete character before cursor, across lines"
  1307.   FRANCAIS "effacer le caractère avant le curseur, à travers lignes"
  1308.   }
  1309.   (and (cursor-left screen) (delete-char-1 screen))
  1310. )
  1311.  
  1312. ;; Eine Region löschen
  1313. (defun delete-region (screen start-lin start-col end-lin end-col)
  1314.   (let ((text (screen-text screen)))
  1315.     (undo3 screen)
  1316.     (undo2
  1317.       (let ((linelist (region-to-linelist screen start-lin start-col end-lin end-col)))
  1318.         #'(lambda ()
  1319.             (set-cursor screen start-lin start-col)
  1320.             (insert-linelist screen linelist)
  1321.     ) )   )
  1322.     (cond
  1323.       ((eql start-lin end-lin) ; innerhalb einer Zeile
  1324.         (let ((line (aref text start-lin)))
  1325.           ;; Stück der Zeile löschen
  1326.           (replace line line :start1 start-col :start2 end-col)
  1327.           (decf (fill-pointer line) (- end-col start-col))
  1328.           ;; Updaten
  1329.           (update-marks screen end-lin end-col start-lin start-col)
  1330.           (refresh-line screen start-lin start-col)
  1331.       ) )
  1332.       (t (let* ((line1 (aref text start-lin))
  1333.                 (line2 (aref text end-lin))
  1334.                 (new-size-1 (+ start-col (- (length line2) end-col))))
  1335.            ;; Teile der ersten und letzten Zeile zusammenhängen
  1336.            (resize-array line1 new-size-1)
  1337.            (replace line1 line2 :start1 start-col :start2 end-col)
  1338.            ;; Zeilen dazwischen werden frei
  1339.            ;; Zeilen darunter hochschieben
  1340.            (replace text text :start1 (1+ start-lin) :start2 (1+ end-lin))
  1341.            (shrink-array text (- end-lin start-lin))
  1342.            ;; Updaten
  1343.            (update-marks screen end-lin end-col start-lin start-col)
  1344.            (refresh-screen screen start-lin (1+ start-lin) (- end-lin start-lin))
  1345. ) ) ) )  )
  1346.  
  1347. ;; Eine Zeile löschen (Zeile, in der der Cursor steht)
  1348. (defun-doc delete-line (screen)
  1349.   #L{
  1350.   DEUTSCH "Zeile löschen"
  1351.   ENGLISH "delete line"
  1352.   FRANCAIS "effacer la ligne"
  1353.   }
  1354.   (let* ((text (screen-text screen))
  1355.          (lin (screen-lin screen)))
  1356.     (if (eql lin (1- (length text)))
  1357.       (delete-region screen lin 0 lin (length (aref text lin)))
  1358.       (delete-region screen lin 0 (1+ lin) 0)
  1359. ) ) )
  1360.  
  1361. (defun-doc clear-start-of-line (screen)
  1362.   #L{
  1363.   DEUTSCH "Vom Zeilenanfang bis Cursorposition löschen"
  1364.   ENGLISH "delete part of line left to the cursor"
  1365.   FRANCAIS "effacer la partie de la ligne avant le curseur"
  1366.   }
  1367.   (let ((lin (screen-lin screen))
  1368.         (col (screen-col screen)))
  1369.     (delete-region screen lin 0 lin col)
  1370. ) )
  1371.  
  1372. (defun-doc clear-end-of-line (screen)
  1373.   #L{
  1374.   DEUTSCH "Bis zum Zeilenende löschen"
  1375.   ENGLISH "delete up to end of line"
  1376.   FRANCAIS "effacer la partie de la ligne à partir du curseur"
  1377.   }
  1378.   (let ((text (screen-text screen))
  1379.         (lin (screen-lin screen))
  1380.         (col (screen-col screen)))
  1381.     (delete-region screen lin col lin (length (aref text lin)))
  1382. ) )
  1383.  
  1384. ;-------------------------------------------------------------------------------
  1385.  
  1386. ;;; Einfügefunktionen
  1387.  
  1388. ;; insert-char fügt an der Cursorpos. ein Zeichen ein, Cursor nach rechts,
  1389. ;; liefert T zurück.
  1390. (defun insert-char (screen char)
  1391.   (let* ((text (screen-text screen))
  1392.          (lin (screen-lin screen))
  1393.          (col (screen-col screen))
  1394.          (line (aref text lin))
  1395.          (line-len (length line)))
  1396.     ;; Zeichen einfügen
  1397.     (undo2 #'(lambda () (backspace screen)))
  1398.     (resize-array line (1+ line-len))
  1399.     (replace line line :start1 (1+ col) :start2 col)
  1400.     (setf (aref line col) char)
  1401.     ;; Updaten
  1402.     (update-marks screen lin col lin (1+ col))
  1403.     (refresh-line screen lin col)
  1404. ) )
  1405.  
  1406. ;; An Cursorpos. einen Zeilenumbruch einfügen und Cursor an den Anfang
  1407. ;; der neuen Zeile setzen
  1408. (defun-doc insert-line (screen)
  1409.   #L{
  1410.   DEUTSCH "Zeilenumbruch einfügen"
  1411.   ENGLISH "begin new line at cursor"
  1412.   FRANCAIS "casser la ligne en deux"
  1413.   }
  1414.   (let* ((text (screen-text screen))
  1415.          (lin (screen-lin screen))
  1416.          (lin+1 (1+ lin))
  1417.          (col (screen-col screen))
  1418.          (line (aref text lin)))
  1419.     ;; Neue Zeile einfügen
  1420.     (undo2 #'(lambda () (backspace-1 screen)))
  1421.     (let ((new-line (get-new-line (- (length line) col))))
  1422.       (replace new-line line :start2 col)
  1423.       (setf (fill-pointer line) col)
  1424.       (resize-array text (1+ (length text)))
  1425.       (replace text text :start1 (1+ lin+1) :start2 lin+1)
  1426.       (setf (aref text lin+1) new-line)
  1427.     )
  1428.     ;; Updaten
  1429.     (update-marks screen lin col lin+1 0)
  1430.     (refresh-screen screen lin (1+ lin+1) -1)
  1431. ) )
  1432.  
  1433. ;; Eine Liste von Zeilen in umgekehrter Reihenfolge an Cursorposition einfügen
  1434. (defun insert-linelist (screen linelist)
  1435.   (let ((text (screen-text screen))
  1436.         (lin (screen-lin screen))
  1437.         (col (screen-col screen)))
  1438.     (cond
  1439.       ((null linelist) t)
  1440.       ((null (rest linelist))
  1441.         ;; kein Zeilenumbruch: String in Zeile einbauen
  1442.         (let* ((line (aref text lin))
  1443.                (piece (first linelist))
  1444.                (piece-len (length piece))
  1445.                (new-col (+ col piece-len)))
  1446.           ;; Zeile um piece-len verlängern
  1447.           (resize-array line (+ (length line) piece-len))
  1448.           ;; Platz freimachen
  1449.           (replace line line :start1 new-col :start2 col)
  1450.           ;; und String einkopieren
  1451.           (replace line piece :start1 col)
  1452.           ;; Updaten
  1453.           (update-marks screen lin col lin new-col)
  1454.           (undo2 #'(lambda () (delete-region screen lin col lin new-col)))
  1455.           (refresh-line screen lin col)
  1456.       ) )
  1457.       (t
  1458.         (let* ((nl-count (1- (length linelist)))
  1459.                (last-lin (+ lin nl-count)))
  1460.           ;; Text-Buffer vergrößern
  1461.           (resize-array text (+ (length text) nl-count))
  1462.           ;; Platz freimachen
  1463.           (replace text text :start1 (1+ last-lin) :start2 (1+ lin))
  1464.           ;; und Zeilen einfügen
  1465.           (let* ((line (aref text lin))
  1466.                  (index last-lin)
  1467.                  (last-line (pop linelist))
  1468.                  (last-len (length last-line)))
  1469.             ;; Letzte neue Zeile mit Rest der Cursorzeile verbinden
  1470.             (let ((new-line (get-new-line (+ last-len (- (length line) col)))))
  1471.               (replace new-line last-line)
  1472.               (replace new-line line :start1 last-len :start2 col)
  1473.               (setf (aref text index) new-line)
  1474.             )
  1475.             ;; Die mittleren Zeilen einfügen
  1476.             (loop
  1477.               (when (null (rest linelist)) (return))
  1478.               (decf index)
  1479.               (let* ((curr-line (pop linelist))
  1480.                      (new-line (get-new-line (length curr-line))))
  1481.                 (replace new-line curr-line)
  1482.                 (setf (aref text index) new-line)
  1483.             ) )
  1484.             ;; Cursorzeilenanfang mit erster einzufügender Zeile kombinieren
  1485.             (let ((first-line (first linelist)))
  1486.               (resize-array line (+ col (length first-line)))
  1487.               (replace line first-line :start1 col)
  1488.             )
  1489.             ;; Updaten
  1490.             (update-marks screen lin col last-lin last-len)
  1491.             (undo2 #'(lambda () (delete-region screen lin col last-lin last-len)))
  1492.             (refresh-screen screen lin (1+ last-lin) (- nl-count))
  1493. ) ) ) ) ) )
  1494.  
  1495. ;; An Cursorpos. einen String einfügen und Cursor an das Ende des eingefügten
  1496. ;; Textes setzen
  1497. (defun insert-string (screen string)
  1498.   (insert-linelist screen (string-to-linelist string))
  1499. )
  1500.  
  1501. ;-------------------------------------------------------------------------------
  1502.  
  1503. ;; Eine Region auf einen Stream schreiben
  1504. (defun write-region (screen start-lin start-col end-lin end-col stream)
  1505.   (let ((text (screen-text screen)))
  1506.     (if (eql start-lin end-lin)
  1507.       (write-string (aref text start-lin) stream :start start-col :end end-col)
  1508.       (progn
  1509.         (write-line (aref text start-lin) stream :start start-col)
  1510.         (do ((index (1+ start-lin) (1+ index)))
  1511.             ((eql index end-lin))
  1512.           (write-line (aref text index) stream)
  1513.         )
  1514.         (write-string (aref text end-lin) stream :end end-col)
  1515.   ) ) )
  1516.   t
  1517. )
  1518.  
  1519. ;; Von einem Stream lesen und einfügen an Cursorposition
  1520. (defun insert-stream (screen stream)
  1521.   (insert-linelist screen
  1522.     (let ((eof "EOF")
  1523.           (linelist '()))
  1524.       (loop
  1525.         (multiple-value-bind (line eof-reached) (read-line stream nil eof)
  1526.           (when (eq line eof) (push "" linelist) (return))
  1527.           (push line linelist)
  1528.           (when eof-reached (return))
  1529.       ) )
  1530.       linelist
  1531. ) ) )
  1532.  
  1533. ;-------------------------------------------------------------------------------
  1534.  
  1535. ;;; Block
  1536.  
  1537. (defun-doc cursor-to-start-of-block (screen)
  1538.   #L{
  1539.   DEUTSCH "Cursor zum Blockanfang"
  1540.   ENGLISH "cursor to start of block"
  1541.   FRANCAIS "curseur au début du bloc"
  1542.   }
  1543.   (let* ((marks (screen-marks screen))
  1544.          (mark1 (aref marks 0))
  1545.          (mark2 (aref marks 1)))
  1546.     (and mark1 mark2
  1547.          (progn (undo3 screen)
  1548.                 (set-cursor screen (mark-lin mark1) (mark-col mark1))
  1549. ) ) )    )
  1550.  
  1551. (defun-doc cursor-to-end-of-block (screen)
  1552.   #L{
  1553.   DEUTSCH "Cursor zum Blockende"
  1554.   ENGLISH "cursor to end of block"
  1555.   FRANCAIS "curseur à la fin du bloc"
  1556.   }
  1557.   (let* ((marks (screen-marks screen))
  1558.          (mark1 (aref marks 0))
  1559.          (mark2 (aref marks 1)))
  1560.     (and mark1 mark2
  1561.          (progn (undo3 screen)
  1562.                 (set-cursor screen (mark-lin mark2) (mark-col mark2))
  1563. ) ) )    )
  1564.  
  1565. (defun-doc set-block-start (screen &optional (lin (screen-lin screen))
  1566.                                              (col (screen-col screen)) )
  1567.   #L{
  1568.   DEUTSCH "Blockanfang setzen"
  1569.   ENGLISH "set block start"
  1570.   FRANCAIS "placer le début du bloc"
  1571.   }
  1572.   (undo-blockmarks screen)
  1573.   (let* ((marks (screen-marks screen))
  1574.          (mark1 (aref marks 0))
  1575.          (mark2 (aref marks 1))
  1576.          (end-lin (and mark2 (mark-lin mark2)))
  1577.          (end-col (and mark2 (mark-col mark2)))
  1578.          (start-lin (if mark1 (min (mark-lin mark1) lin) lin)))
  1579.     (unless ; existiert mark2 und liegt hinter (lin,col) ?
  1580.             (and mark2 (or (> end-lin lin)
  1581.                            (and (= end-lin lin) (>= end-col col))
  1582.             )          )
  1583.       (let ((text (screen-text screen)))
  1584.         (setq end-lin (1- (length text)))
  1585.         (setq end-col (length (aref text end-lin)))
  1586.         (setf (aref marks 1) (make-mark end-lin end-col))
  1587.     ) )
  1588.     (setf (aref marks 0) (make-mark lin col))
  1589.     (refresh-screen screen start-lin (1+ end-lin))
  1590. ) )
  1591.  
  1592. (defun-doc set-block-end (screen &optional (lin (screen-lin screen))
  1593.                                            (col (screen-col screen)) )
  1594.   #L{
  1595.   DEUTSCH "Blockende setzen"
  1596.   ENGLISH "set block end"
  1597.   FRANCAIS "placer la fin du bloc"
  1598.   }
  1599.   (undo-blockmarks screen)
  1600.   (let* ((marks (screen-marks screen))
  1601.          (mark1 (aref marks 0))
  1602.          (mark2 (aref marks 1))
  1603.          (start-lin (and mark1 (mark-lin mark1)))
  1604.          (start-col (and mark1 (mark-col mark1)))
  1605.          (end-lin (if mark2 (max (mark-lin mark2) lin) lin)))
  1606.     (unless ; existiert mark1 und liegt vor (lin,col) ?
  1607.             (and mark1 (or (< start-lin lin)
  1608.                            (and (= start-lin lin) (<= start-col col))
  1609.             )          )
  1610.       (setq start-lin 0)
  1611.       (setq start-col 0)
  1612.       (setf (aref marks 0) (make-mark start-lin start-col))
  1613.     )
  1614.     (setf (aref marks 1) (make-mark lin col))
  1615.     (refresh-screen screen start-lin (1+ end-lin))
  1616. ) )
  1617.  
  1618. (defun-doc hide-block (screen)
  1619.   #L{
  1620.   DEUTSCH "Block demarkieren"
  1621.   ENGLISH "remove block marks"
  1622.   FRANCAIS "enlever les marques du bloc"
  1623.   }
  1624.   (undo-blockmarks screen)
  1625.   (let* ((marks (screen-marks screen))
  1626.          (mark1 (aref marks 0))
  1627.          (mark2 (aref marks 1)))
  1628.     (setf (aref marks 0) nil (aref marks 1) nil)
  1629.     (and mark1 mark2
  1630.          (refresh-screen screen (mark-lin mark1) (1+ (mark-lin mark2)))
  1631. ) ) )
  1632.  
  1633. (defun undo-blockmarks (screen)
  1634.   (let* ((marks (screen-marks screen))
  1635.          (mark1 (aref marks 0))
  1636.          (mark2 (aref marks 1)))
  1637.     (when mark2
  1638.       (undo2 (let ((lin (mark-lin mark2)) (col (mark-col mark2)))
  1639.                #'(lambda () (set-block-end screen lin col))
  1640.     ) )      )
  1641.     (when mark1
  1642.       (undo2 (let ((lin (mark-lin mark1)) (col (mark-col mark1)))
  1643.                #'(lambda () (set-block-start screen lin col))
  1644.     ) )      )
  1645.     (undo2 #'(lambda () (hide-block screen)))
  1646. ) )
  1647.  
  1648. (defun mark-region (screen lin1 col1 lin2 col2)
  1649.   (and lin1
  1650.        (let* ((marks (screen-marks screen))
  1651.               (mark1 (aref marks 0))
  1652.               (mark2 (aref marks 1)))
  1653.          (setf (aref marks 0) (make-mark lin1 col1)
  1654.                (aref marks 1) (make-mark lin2 col2)
  1655.          )
  1656.          (when (and mark1 mark2)
  1657.            (setq lin1 (min lin1 (mark-lin mark1))
  1658.                  lin2 (max lin2 (mark-lin mark2))
  1659.          ) )
  1660.          (refresh-screen screen lin1 (1+ lin2))
  1661. ) )    )
  1662.  
  1663. (defun get-block (screen)
  1664.   (let* ((marks (screen-marks screen))
  1665.          (mark1 (aref marks 0))
  1666.          (mark2 (aref marks 1)))
  1667.     (if (and mark1 mark2)
  1668.       (values (mark-lin mark1) (mark-col mark1)
  1669.               (mark-lin mark2) (mark-col mark2)
  1670.       )
  1671.       (values nil nil nil nil)
  1672. ) ) )
  1673.  
  1674. (defun-doc delete-block (screen)
  1675.   #L{
  1676.   DEUTSCH "Block löschen"
  1677.   ENGLISH "delete block"
  1678.   FRANCAIS "effacer le bloc"
  1679.   }
  1680.   (let* ((marks (screen-marks screen))
  1681.          (mark1 (aref marks 0))
  1682.          (mark2 (aref marks 1)))
  1683.     (unless (and mark1 mark2) (return-from delete-block nil))
  1684.     (undo-blockmarks screen)
  1685.     (setf (aref marks 0) nil (aref marks 1) nil)
  1686.     (delete-region screen (mark-lin mark1) (mark-col mark1)
  1687.                           (mark-lin mark2) (mark-col mark2)
  1688. ) ) )
  1689.  
  1690. ; Undo ab hier implementieren??
  1691.  
  1692. (defun-doc move-block (screen) ; Block an Cursorposition verschieben
  1693.   #L{
  1694.   DEUTSCH "Block an Cursorposition verschieben"
  1695.   ENGLISH "move block to cursor position"
  1696.   FRANCAIS "transporter le bloc à la position du curseur"
  1697.   }
  1698.   (let* ((marks (screen-marks screen))
  1699.          (mark1 (aref marks 0))
  1700.          (mark2 (aref marks 1)))
  1701.     (unless (and mark1 mark2) (return-from move-block nil))
  1702.     (let* ((lin1 (mark-lin mark1))
  1703.            (col1 (mark-col mark1))
  1704.            (lin2 (mark-lin mark2))
  1705.            (col2 (mark-col mark2))
  1706.            ;; Block in Zeilenliste packen:
  1707.            (linelist (region-to-linelist screen lin1 col1 lin2 col2)))
  1708.       ;; und löschen:
  1709.       (delete-region screen lin1 col1 lin2 col2)
  1710.       (let ((lin (screen-lin screen)) ; Cursorpos. merken
  1711.             (col (screen-col screen)))
  1712.         (insert-linelist screen linelist) ; Block an Cursorpos. einfügen
  1713.         (setf (mark-lin mark1) lin    ; alte Cursorpos. = Anfang
  1714.               (mark-col mark1) col
  1715.         )
  1716.         (setf (mark-lin mark2) (screen-lin screen) ; neue Cursorpos. = Ende
  1717.               (mark-col mark2) (screen-col screen)
  1718.         )
  1719.         (refresh-screen screen lin (1+ (screen-lin screen)))
  1720. ) ) ) )
  1721.  
  1722. (defun-doc copy-block (screen) ; Block kopieren (ohne Marken)
  1723.   #L{
  1724.   DEUTSCH "Block an Cursorposition kopieren"
  1725.   ENGLISH "copy block to cursor position"
  1726.   FRANCAIS "placer une copie du bloc à la position du curseur"
  1727.   }
  1728.   (multiple-value-bind (lin1 col1 lin2 col2) (get-block screen)
  1729.     (and lin1
  1730.          (insert-linelist screen
  1731.                           (region-to-linelist screen lin1 col1 lin2 col2)
  1732. ) ) )    )
  1733.  
  1734. ;-------------------------------------------------------------------------------
  1735.  
  1736. ;;; Block und Cut-and-Paste-Buffer
  1737.  
  1738. ;; Enthält umgedrehte Zeilenliste
  1739. (defvar *cut-and-paste-buffer* '())
  1740.  
  1741. (defun-doc copy-block-buffer (screen)
  1742.   #L{
  1743.   DEUTSCH "Block in Cut-and-Paste-Buffer übertragen"
  1744.   ENGLISH "copy block into cut-and-paste buffer"
  1745.   FRANCAIS "garder une copie du bloc en mémoire"
  1746.   }
  1747.   (multiple-value-bind (lin1 col1 lin2 col2) (get-block screen)
  1748.     (and lin1
  1749.          (progn
  1750.            (setq *cut-and-paste-buffer*
  1751.                  (region-to-linelist screen lin1 col1 lin2 col2)
  1752.            )
  1753.            t
  1754. ) ) )    )
  1755.  
  1756. (defun-doc delete-block-buffer (screen)
  1757.   #L{
  1758.   DEUTSCH "Block löschen und in Cut-and-Paste-Buffer übertragen"
  1759.   ENGLISH "yank block into cut-and-paste buffer"
  1760.   FRANCAIS "effacer le bloc, mais le garder en mémoire"
  1761.   }
  1762.   (let* ((marks (screen-marks screen))
  1763.          (mark1 (aref marks 0))
  1764.          (mark2 (aref marks 1)))
  1765.     (and mark1 mark2
  1766.          (progn
  1767.            (setf (aref marks 0) nil (aref marks 1) nil)
  1768.            (let ((lin1 (mark-lin mark1))
  1769.                  (col1 (mark-col mark1))
  1770.                  (lin2 (mark-lin mark2))
  1771.                  (col2 (mark-col mark2)))
  1772.              (setq *cut-and-paste-buffer*
  1773.                    (region-to-linelist screen lin1 col1 lin2 col2)
  1774.              )
  1775.              (delete-region screen lin1 col1 lin2 col2)
  1776. ) ) )    ) )
  1777.  
  1778. (defun-doc paste-buffer (screen)
  1779.   #L{
  1780.   DEUTSCH "Inhalt des Cut-and-Paste-Buffer einfügen"
  1781.   ENGLISH "insert cut-and-paste buffer contents"
  1782.   FRANCAIS "ajouter le bloc en mémoire dans le texte"
  1783.   }
  1784.   (insert-linelist screen *cut-and-paste-buffer*)
  1785. )
  1786.  
  1787. ;-------------------------------------------------------------------------------
  1788.  
  1789. ;; Macro zum Auswerten von Formen, wobei Fehler abgefangen werden und den Wert
  1790. ;; von errorval liefern
  1791. (defconstant errorval "ERROR")
  1792.  
  1793. (defmacro with-ignored-errors (&body body)
  1794.   (let ((blockvar (gensym)))
  1795.     `(BLOCK ,blockvar
  1796.        (LET ((*ERROR-HANDLER*
  1797.                #'(LAMBDA (&REST ARGS)
  1798.                    (DECLARE (IGNORE ARGS))
  1799.                    (RETURN-FROM ,blockvar ERRORVAL)
  1800.             ))   )
  1801.          ,@body
  1802.      ) )
  1803. ) )
  1804.  
  1805. ;; Dito, mit Ausgabe der Fehlermeldung auf *error-output*
  1806. (defmacro with-trapped-errors (&body body)
  1807.   (let ((blockvar (gensym)))
  1808.     `(BLOCK ,blockvar
  1809.        (LET ((*ERROR-HANDLER*
  1810.                #'(LAMBDA (CONTINUE ERRSTR &REST ARGS)
  1811.                    (DECLARE (IGNORE CONTINUE)) ; vorläufig
  1812.                    (FRESH-LINE *ERROR-OUTPUT*)
  1813.                    (APPLY #'FORMAT *ERROR-OUTPUT* ERRSTR ARGS)
  1814.                    (RETURN-FROM ,blockvar ERRORVAL)
  1815.             ))  )
  1816.          ,@body
  1817.      ) )
  1818. ) )
  1819.  
  1820. ;===========================================================================
  1821. ;                        E D I T O R - T O P L E V E L
  1822. ;===========================================================================
  1823.  
  1824. ;; Eine key-table ist eine Hashtable  char -> fun,  die Tastendrücken Prozeduren
  1825. ;; zuordnet. fun ist eine Funktion von einem screen-Argument und gibt einen
  1826. ;; booleschen Wert zurück: t bei Erfolg, nil bei Mißerfolg
  1827.  
  1828. ;; Full-Screen-Tabelle
  1829. (defconstant full-table (make-hash-table :test #'eql))
  1830. ;; Read-Only-Tabelle
  1831. (defconstant half-table (make-hash-table :test #'eql))
  1832. ;; Tabelle für Line-Edit
  1833. (defconstant line-edit-table (make-hash-table :test #'eql))
  1834.  
  1835. ;; Control-Table-Default: Nur Escape
  1836. (defconstant null-table (make-hash-table :test #'eql))
  1837. (setf (gethash #\Escape null-table) '(:LEAVE))
  1838. ;; Volle Control-Table des Editors
  1839. (defconstant control-table (make-hash-table :test #'eql))
  1840.  
  1841. (defconstant docstrings-table (make-hash-table :test #'eql))
  1842.  
  1843. (defun bind-key (keys flag fun &optional (docstring nil))
  1844.   (unless (listp keys) (setq keys (list keys)))
  1845.   (when (and (symbolp fun) (not (null fun)))
  1846.     (unless docstring (setq docstring (documentation fun 'function)))
  1847.     (setq fun (symbol-function fun))
  1848.   )
  1849.   (let ((tables
  1850.           (case flag
  1851.             (:CONTROL (list control-table))
  1852.             (:ALL (list full-table half-table line-edit-table))
  1853.             (:WRITABLE (list full-table line-edit-table))
  1854.             (:MULTILINE (list full-table half-table))
  1855.             (:AND-WRITABLE-MULTILINE (list full-table))
  1856.             (:AND-WRITABLE-NOT-MULTILINE (list line-edit-table))
  1857.        )) )
  1858.     (dolist (key keys)
  1859.       (dolist (table tables)
  1860.         (setf (gethash key table) fun)
  1861.       )
  1862.       (when docstring
  1863.         (setf (gethash key docstrings-table) docstring)
  1864.     ) )
  1865. ) )
  1866.  
  1867. ;; ob der Editor aktiv ist
  1868. (defvar *editor-active* nil)
  1869. ;; während der Editor inaktiv ist: letzter Wert von *screens*
  1870. (defvar *saved-screens* '())
  1871. ;; Vektor aller Screens des Editors
  1872. (defvar *edit-screens* (make-array 13 :initial-element nil))
  1873. ;; Vektor dazugehöriger Pathnames bzw. Conses (package . env)
  1874. (defvar *screen-paths* (make-array 13 :initial-element nil))
  1875. ;; momentan aktiver Screen
  1876. (defvar *active-screen*)
  1877.  
  1878. ;; Fenster für Fehlermeldungen
  1879. (defvar error-screen)
  1880. ;; Fenster für Traces
  1881. (defvar trace-screen)
  1882. ;; Hilfefenster, enthält Tastenzuordnungen
  1883. (defvar help-screen)
  1884. ;; Hauptfenster (ganzer Bildschirm)
  1885. (defvar main-screen)
  1886.  
  1887. ;; Editor
  1888. (defun edit (&optional start-command)
  1889.   (if *editor-active*
  1890.     (throw 'editor-active start-command) ; Editor nicht rekursiv aufrufen!
  1891.     (#-AMIGA with-keyboard
  1892.      #+AMIGA progn
  1893.       (with-window
  1894.         (unless (boundp 'main-screen)
  1895.           (setf (aref *edit-screens* 0)
  1896.             (setf main-screen (make-screen))
  1897.         ) )
  1898.         (unless (boundp 'error-screen)
  1899.           (setf (aref *edit-screens* 10)
  1900.             (setf error-screen
  1901.               (make-screen :title " Errors: " :olchar #\E :height 10 :width 50
  1902.                            :top-lin 2 :left-col (- global-screen-width 53)
  1903.         ) ) ) )
  1904.         (unless (boundp 'trace-screen)
  1905.           (setf (aref *edit-screens* 11)
  1906.             (setf trace-screen
  1907.               (make-screen :title " Trace: " :olchar #\T :height 15 :width 70
  1908.                            :top-lin 8 :left-col 3
  1909.         ) ) ) )
  1910.         (unless (boundp 'help-screen)
  1911.           (setf (aref *edit-screens* 12)
  1912.             (setf help-screen
  1913.               (make-screen :title 
  1914.                            #L{
  1915.                            DEUTSCH " Tastenzuordnung "
  1916.                            ENGLISH " Key bindings "
  1917.                            FRANCAIS " Associations des touches "
  1918.                            }
  1919.                            :olchar #\H
  1920.                            :height 15 :width 78
  1921.           ) ) )
  1922.           (insert-linelist help-screen
  1923.             (reverse
  1924.               `(" ==========================================================================="
  1925.                 ,
  1926.                 #L{
  1927.                 DEUTSCH "                         T A S T E N B E L E G U N G"
  1928.                 ENGLISH "                           K E Y   B I N D I N G S"
  1929.                 FRANCAIS "               A S S O C I A T I O N S   D E S   T O U C H E S"
  1930.                  }
  1931.                 " ==========================================================================="
  1932.                 ""
  1933.                 ""
  1934.           ) )  )
  1935.           ;(maphash #'(lambda (key docstring)
  1936.           ;             (insert-string help-screen (format nil "~:@C~25T --> ~A~%" key docstring))
  1937.           ;             (line-up help-screen)
  1938.           ;           )
  1939.           ;         docstrings-table
  1940.           ;)
  1941.           ; Das ist reichlich langsam! Geht's so schneller?
  1942.           (insert-linelist help-screen
  1943.             (reverse
  1944.               (let ((lines '()))
  1945.                 (maphash #'(lambda (key docstring)
  1946.                              (push (format nil "~:@C~25T --> ~A" key (eval docstring)) lines)
  1947.                            )
  1948.                          docstrings-table
  1949.                 )
  1950.                 lines
  1951.           ) ) )
  1952.           (set-cursor help-screen 0 0)
  1953.         )
  1954.         (unless (boundp '*active-screen*)
  1955.           (setf *active-screen* 0)
  1956.         )
  1957.         (unwind-protect
  1958.           (block editor
  1959.             ; Ab hier kann der Editor als aktiv angesehen werden.
  1960.             (activate-screens (cons main-screen *saved-screens*))
  1961.             ; Schleife zum Abfangen und Behandeln der Kommandos:
  1962.             (flet ((handle-command (command &rest args)
  1963.                      (catch 'handle-command
  1964.                        (case command
  1965.                          (:LEAVE (return-from editor))
  1966.                          (:ERROR (setq *active-screen* 10))
  1967.                          (:TRACE (setq *active-screen* 11))
  1968.                          (:HELP (setq *active-screen* 12))
  1969.                          (:TOP
  1970.                            (if (null (aref *edit-screens* (first args)))
  1971.                              (bell)
  1972.                              (setq *active-screen* (first args))
  1973.                          ) )
  1974.                          (:HIDE
  1975.                            (unless args (setq args (list *active-screen*)))
  1976.                            (if (null (aref *edit-screens* (first args)))
  1977.                              (bell)
  1978.                              (let ((new-active
  1979.                                      (hide-screen (aref *edit-screens* (first args)))
  1980.                                   ))
  1981.                                (setq *active-screen*
  1982.                                      (or (and (not (null new-active))
  1983.                                               (position new-active *edit-screens*
  1984.                                                         :test #'eq
  1985.                                          )    )
  1986.                                          0
  1987.                          ) ) ) )     )
  1988.                          (:DELETE
  1989.                            (cond
  1990.                              ((< 0 *active-screen* 10)
  1991.                                (let ((new-active
  1992.                                        (hide-screen (aref *edit-screens* *active-screen*))
  1993.                                     ))
  1994.                                  (setf (aref *edit-screens* *active-screen*) nil)
  1995.                                  (setf (aref *screen-paths* *active-screen*) nil)
  1996.                                  (setq *active-screen*
  1997.                                        (or (and (not (null new-active))
  1998.                                                 (position new-active *edit-screens*
  1999.                                                           :test #'eq
  2000.                                            )    )
  2001.                                            0
  2002.                              ) ) )     )
  2003.                              (t (bell))
  2004.                          ) )
  2005.                          (:SAVE
  2006.                            (unless (aref *screen-paths* *active-screen*)
  2007.                              (setf (aref *screen-paths* *active-screen*) (get-save-path))
  2008.                            )
  2009.                            (let ((screen (aref *edit-screens* *active-screen*))
  2010.                                  (destination (aref *screen-paths* *active-screen*)))
  2011.                              (if (atom destination) ; Pathname oder Cons?
  2012.                                (screen-to-file screen destination)
  2013.                                ; Load vom Screen:
  2014.                                (let ((f (make-read-from-screen-stream screen 0 0))
  2015.                                      (*package* (car destination)) ; *PACKAGE* binden
  2016.                                      (env (cdr destination)) ; Evaluator-Environment
  2017.                                      (end-of-file "EOF")) ; einmaliges Objekt
  2018.                                  (loop
  2019.                                    (let ((obj (read f nil end-of-file)))
  2020.                                      (when (eql obj end-of-file) (return))
  2021.                                      (evalhook obj nil nil env)
  2022.                                ) ) )
  2023.                          ) ) )
  2024.                          (:SAVE-AS
  2025.                            (screen-to-file (aref *edit-screens* *active-screen*) (get-save-path))
  2026.                          )
  2027.                          (:LOAD ; (:LOAD path)
  2028.                            (let ((new-active (position nil *edit-screens*)))
  2029.                              (if (null new-active)
  2030.                                (bell)
  2031.                                (let ((path
  2032.                                        (if args
  2033.                                          (first args)
  2034.                                          (line-edit 
  2035.                                           #L{
  2036.                                           DEUTSCH " Lade: "
  2037.                                           ENGLISH " File to load: "
  2038.                                           FRANCAIS " Fichier à charger: "
  2039.                                           }
  2040.                                     )) ) )
  2041.                                  (setq path (with-ignored-errors (pathname path)))
  2042.                                  (if (eq path errorval)
  2043.                                    (bell)
  2044.                                    (progn
  2045.                                      (setf (aref *edit-screens* new-active)
  2046.                                            (file-to-screen path new-active)
  2047.                                      )
  2048.                                      (setf (aref *screen-paths* new-active) path)
  2049.                                      (setq *active-screen* new-active)
  2050.                          ) ) ) ) ) )
  2051.                          (:FORM ; (:FORM sym package env string)
  2052.                            (let ((new-active (position nil *edit-screens*)))
  2053.                              (if (null new-active)
  2054.                                (bell)
  2055.                                (let ((screen (make-screen
  2056.                                                :title (format nil " ~A " (first args))
  2057.                                                :olchar (digit-char new-active)
  2058.                                                :top-lin new-active :width 78 :height 13
  2059.                                     ))       )
  2060.                                  (insert-string screen (fourth args))
  2061.                                  (insert-line screen)
  2062.                                  (set-cursor screen 0 0)
  2063.                                  (setf (aref *edit-screens* new-active) screen)
  2064.                                  (setf (aref *screen-paths* new-active) (cons (second args) (third args)))
  2065.                                  (setq *active-screen* new-active)
  2066.                          ) ) ) )
  2067.                          (t (bell))
  2068.                   )) ) )
  2069.               (loop
  2070.                 (setq start-command
  2071.                   (catch 'editor-active
  2072.                     (let ((*editor-active* t))
  2073.                       ; nächstes Kommando holen und abarbeiten:
  2074.                       (apply #'handle-command
  2075.                         (or start-command
  2076.                             (edit1 (aref *edit-screens* *active-screen*)
  2077.                                    control-table
  2078.                                    (if (< *active-screen* 10) full-table half-table)
  2079.                       ) )   )
  2080.                       nil
  2081.               ) ) ) )
  2082.           ) )
  2083.           (setq *saved-screens* (nreverse (copy-list *screens*)))
  2084.           (doseq (screen *edit-screens*)
  2085.             (unless (null screen) (hide-screen screen))
  2086.           )
  2087.           (screen-clear-screen)
  2088. ) ) ) ) )
  2089.  
  2090. #|
  2091. ;; Editierfunktion: Editiere ein Fenster
  2092. (defun edit-screen (screen &optional (key-table-1 null-table)
  2093.                                      (key-table-2 full-table)
  2094.                    )
  2095.   (edit1 screen key-table-1 key-table-2)
  2096. )
  2097. |#
  2098.  
  2099. ;; Defaultfunktion für Tastenzuordnung: Nichts tun, Mißerfolg melden (= NIL)
  2100. (defun return-nil (&rest args)
  2101.   (declare (ignore args))
  2102.   nil
  2103. )
  2104.  
  2105. ;; Editier-Hauptschleife
  2106. (defun edit1 (screen key-table-1 key-table-2)
  2107.   (activate-screen screen)
  2108.   (catch 'edit
  2109.     (flet ((read-edit-command ()
  2110.              (prog2
  2111.                (set-cursor-visible screen) ; Cursor ins Fenster und einschalten
  2112.                (screen:read-keyboard-char *window*)
  2113.                (screen-cursor-off) ; Cursor abschalten
  2114.            ) )
  2115.            (execute-edit-command (char)
  2116.              (catch 'handle-command
  2117.                (if (and (string-char-p char)
  2118.                         (char>= char #\Space)
  2119.                         (not (char= char #\Rubout))
  2120.                    )
  2121.                  ;; normales Zeichen: unter Key :string-char nachschauen
  2122.                  (or (funcall (gethash :string-char key-table-2 #'return-nil)
  2123.                               screen char
  2124.                      )
  2125.                      (bell)
  2126.                  )
  2127.                  ;; sonst: erst Bedeutung für Editier-Ende nachsehen
  2128.                  (multiple-value-bind (return-value presentp)
  2129.                      (gethash char key-table-1)
  2130.                    (when presentp (throw 'edit return-value))
  2131.                    ;; sonst Editierfunktion ausführen
  2132.                    (or (funcall (gethash char key-table-2 #'return-nil) screen)
  2133.                        (bell) ; falls undefiniert oder ohne Erfolg
  2134.           )) ) ) ) )
  2135.       (loop (execute-edit-command (read-edit-command)))
  2136. ) ) )
  2137.  
  2138. ;; Einen Pfad fürs Abspeichern erfragen
  2139. (defun get-save-path ()
  2140.   (let (path)
  2141.     (loop
  2142.       (setq path (line-edit 
  2143.                   #L{
  2144.                   DEUTSCH " Abspeichern als: "
  2145.                   ENGLISH " Save as: "
  2146.                   FRANCAIS " Garder sous le nom: "
  2147.                   }
  2148.       )          )
  2149.       (setq path (with-ignored-errors (pathname path)))
  2150.       (unless (eq path errorval) (return))
  2151.       (bell)
  2152.     )
  2153.     path
  2154. ) )
  2155.  
  2156. ;; Eine Zeile editieren und Ergebnis zurückliefern
  2157. (defun line-edit (title &optional (old ""))
  2158.   (let ((query-screen (make-screen :height 1 :width 40 :title title)))
  2159.     (insert-string query-screen old)
  2160.     (let ((command
  2161.             (edit1 query-screen null-table line-edit-table)
  2162.          ))
  2163.       (hide-screen query-screen)
  2164.       (when (eq (first command) ':LEAVE) ; bei Escape
  2165.         (throw 'handle-command nil) ; aktuelles Kommando abbrechen
  2166.       )
  2167.       (copy-seq (aref (screen-text query-screen) 0))
  2168. ) ) )
  2169.  
  2170. ;===========================================================================
  2171. ;                      A R B E I T E N   M I T   F I L E S
  2172. ;===========================================================================
  2173.  
  2174. ;; Ein File in einen Screen einlesen, leerer Screen, falls File nicht vorhanden
  2175. (defun file-to-screen (path number) ; 1 <= number <= 9
  2176.   (let ((screen (make-screen
  2177.                   :title (format nil " ~A " (enough-namestring path))
  2178.                   :olchar (digit-char number)
  2179.                   :top-lin number :width 78 :height 13
  2180.        ))       )
  2181.     (when (probe-file path)
  2182.       (with-open-file (s path :direction :input) (insert-stream screen s))
  2183.       (set-cursor screen 0 0)
  2184.     )
  2185.     screen
  2186. ) )
  2187.  
  2188. ;; Screen in ein File schreiben
  2189. (defun screen-to-file (screen file)
  2190.   (let* ((text (screen-text screen))
  2191.          (text-len-1 (1- (length text)))
  2192.         )
  2193.     (with-open-file (s file :direction :output :if-exists :rename)
  2194.       (write-region screen 0 0 text-len-1 (length (aref text text-len-1)) s)
  2195.   ) )
  2196.   t
  2197. )
  2198.  
  2199. ;===========================================================================
  2200. ;  E I N Z E L F U N K T I O N E N   F Ü R   T A S T E N Z U O R D N U N G
  2201. ;===========================================================================
  2202.  
  2203. (defun finish (screen)
  2204.   (declare (ignore screen))
  2205.   (throw 'edit '(:FINISH))
  2206. )
  2207.  
  2208. ;; Erzeuge einen Stream, der aus dem screen ab Position lin1,col1 bis Position
  2209. ;; lin2,col2 (optional, Default Textende) liest;
  2210. ;; Zweiter Wert ist eine Funktion von 0 Argumenten, die die Position, bis zu
  2211. ;; der gelesen wurde, angibt (als (values lin col)).
  2212. ;; Solange der Stream verwendet wird, sollten Modifikationen des screen
  2213. ;; unterbleiben.
  2214. (defun make-read-from-screen-stream (screen lin1 col1 &optional lin2 col2)
  2215.   (let ((text (screen-text screen)))
  2216.     (unless lin2 (setq lin2 (1- (length text))))
  2217.     (unless col2 (setq col2 (length (aref text lin2))))
  2218.     ; Region von (lin1,col1) bis (lin2,col2) lesen:
  2219.     (let* ((lastlin nil)
  2220.            (lastcol nil)
  2221.            (stream
  2222.              (make-buffered-input-stream
  2223.                ; Funktion, die abwechselnd ein Textstück und ein Newline
  2224.                ; durchreicht, bis die Region zu Ende ist:
  2225.                #'(lambda ()
  2226.                    ; lin1, col1 laufen.
  2227.                    (if (or (> lin1 lin2) (and (= lin1 lin2) (>= col1 col2)))
  2228.                      nil ; Ende der Region
  2229.                      (let ((line (aref text lin1)))
  2230.                        (setq lastlin lin1 lastcol col1)
  2231.                        (if (>= col1 (length line)) ; am Zeilenende?
  2232.                          ; Zeilenende: Newline durchreichen
  2233.                          (progn
  2234.                            (incf lin1) (setq col1 0)
  2235.                            (values newline-as-string 0 1)
  2236.                          )
  2237.                          ; sonst: Zeile bzw. Zeilenrest durchreichen
  2238.                          (values line col1 (setq col1 (length line)))
  2239.                  ) ) ) )
  2240.                nil
  2241.           )) )
  2242.       (values
  2243.         stream
  2244.         ; Funktion, die die Position im Screen liefert, an der der Stream
  2245.         ; sich gerade befindet:
  2246.         ; Stream hat einen String und einen internen Index.
  2247.         ; Zustand 1 (sofort nach Initialisierung):
  2248.         ;           String = "", Index = 0, liefere (lin1,col1).
  2249.         ; Zustand 2 (nach Zeilen-Übergabe):
  2250.         ;           String = Zeile, lastcol <= index <= col1, lastlin = lin1,
  2251.         ;           liefere (lin1,index).
  2252.         ; Zustand 3 (nach Newline-Übergabe):
  2253.         ;           String = Newline-as-String, col1 = 0,
  2254.         ;           bei Index = 0 liefere (lastlin,lastcol),
  2255.         ;           bei Index = 1 liefere (lin1,col1).
  2256.         #'(lambda ()
  2257.             (let ((index (sys::buffered-input-stream-index stream)))
  2258.               (if (eql index 0)
  2259.                 ; Zustand 1 oder 2 oder 3a
  2260.                 (values lastlin lastcol)
  2261.                 ; Zustand 2 oder 3b
  2262.                 (values lin1 (min index col1))
  2263.           ) ) )
  2264.       )
  2265. ) ) )
  2266.  
  2267. ;; Erzeuge einen Stream, der ab Cursorposition in den screen schreibt
  2268. (defun make-write-to-screen-stream (screen)
  2269.   (make-buffered-output-stream
  2270.     #'(lambda (string) (insert-string screen string))
  2271.     (screen-col screen)
  2272. ) )
  2273.  
  2274. ;; Erzeuge einen Stream, der ab Textende in den screen schreibt und ein
  2275. ;; Flag setzt, wenn etwas geschrieben wurde
  2276. (defmacro make-write-to-screen-stream-with-flag (screenform flagvar)
  2277.   (let ((stringvar (gensym)) (screenvar (gensym)))
  2278.     `(LET ((,screenvar ,screenform))
  2279.        (CURSOR-TO-END-OF-TEXT ,screenvar)
  2280.        (MAKE-BUFFERED-OUTPUT-STREAM
  2281.          #'(LAMBDA (,stringvar)
  2282.              (INSERT-STRING ,screenvar ,stringvar)
  2283.              (WHEN (PLUSP (LENGTH ,stringvar)) (SETQ ,flagvar T))
  2284.            )
  2285.          (SCREEN-COL ,screenvar)
  2286. ) )  ) )
  2287.  
  2288. ;; Lies ein Objekt aus dem angegebenen Bereich, werte es aus und schreibe das
  2289. ;; Ergebnis in den Haupt-Text.
  2290. ;; Vorläufige Version: Keine Umleitung von *query-io* und *debug-io* auf
  2291. ;; Fenster.
  2292. (defun eval-region (screen lin1 col1 lin2 col2)
  2293.   (unless lin1 (return-from eval-region nil))
  2294.   (let* ((errorflag nil)
  2295.          (traceflag nil)
  2296.          (instream (make-read-from-screen-stream screen lin1 col1 lin2 col2))
  2297.          (*standard-output* (make-write-to-screen-stream main-screen))
  2298.          (*error-output*
  2299.            (make-write-to-screen-stream-with-flag error-screen errorflag))
  2300.          (*trace-output*
  2301.            (make-write-to-screen-stream-with-flag trace-screen traceflag))
  2302.          (results
  2303.            (multiple-value-list (with-trapped-errors (eval (read instream))))
  2304.         ))
  2305.     (close instream)
  2306.     ;; Werte dazu
  2307.     (unless (or (null results) errorflag)
  2308.       (fresh-line)
  2309.       (loop
  2310.         (prin1 (pop results))
  2311.         (when (null results) (return))
  2312.         (write-char #\Space) (write-char #\;) (terpri)
  2313.     ) )
  2314.     (fresh-line)
  2315.     (close *standard-output*)
  2316.     (close *error-output*)
  2317.     (close *trace-output*)
  2318.     (when errorflag (throw 'edit '(:ERROR)))
  2319.     (when traceflag (throw 'edit '(:TRACE)))
  2320.     t
  2321. ) )
  2322.  
  2323. ;; Lies ein Objekt aus dem Block, werte es aus und schreibe das Ergebnis
  2324. ;; in den Text.
  2325. (defun-doc eval-block (screen)
  2326.   #L{
  2327.   DEUTSCH "Block-Inhalt auswerten"
  2328.   ENGLISH "evaluate block contents"
  2329.   FRANCAIS "évaluer le contenu du bloc"
  2330.   }
  2331.   (multiple-value-call #'eval-region screen (get-block screen))
  2332. )
  2333.  
  2334. (defun get-whitespace-right (screen &optional (lin (screen-lin screen))
  2335.                                               (col (screen-col screen)) )
  2336.   (let* ((text (screen-text screen))
  2337.          (text-len-1 (1- (length text)))
  2338.          (line (aref text lin)))
  2339.     (loop
  2340.       (let ((col1 (position #\Space line :start col :test-not #'eql)))
  2341.         (when col1 (return (values lin col1)))
  2342.       )
  2343.       (when (eql lin text-len-1) (return nil))
  2344.       (incf lin)
  2345.       (setq col 0)
  2346.       (setq line (aref text lin))
  2347. ) ) )
  2348.  
  2349. (defun-doc skip-whitespace-right (screen)
  2350.   #L{
  2351.   DEUTSCH "Whitespace nach rechts überspringen"
  2352.   ENGLISH "skip whitespace right"
  2353.   FRANCAIS "sauter le blanc à droite"
  2354.   }
  2355.   (multiple-value-bind (lin col) (get-whitespace-right screen)
  2356.     (and lin
  2357.          (set-cursor screen lin col)
  2358. ) ) )
  2359.  
  2360. ; Eine Kopie der Readtable *readtable*, modifiziert für den Syntaxcheck.
  2361. (defun modified-readtable ()
  2362.   (let ((readtable (copy-readtable)))
  2363.     (set-macro-character #\|
  2364.       #'(lambda (stream char)
  2365.           (declare (ignore char))
  2366.           (when (eql (peek-char nil stream nil) #\#)
  2367.             (sys::error-of-type 'stream-error
  2368.               :stream stream
  2369.               #L{
  2370.               DEUTSCH "~S von ~S: |# ist nur nach #| zulässig."
  2371.               ENGLISH "~S from ~S: |# is legal only after #|"
  2372.               FRANCAIS "~S de ~S : |# est permis qu'après #|"
  2373.               }
  2374.               'read stream
  2375.         ) ) )
  2376.       nil ; terminating macro character
  2377.       readtable
  2378.     )
  2379.     readtable
  2380. ) )
  2381.  
  2382. (defun get-next-object (screen &optional (old-lin (screen-lin screen))
  2383.                                          (old-col (screen-col screen))
  2384.                                          (readtable (modified-readtable)) )
  2385.   (multiple-value-bind (lin col) (get-whitespace-right screen old-lin old-col)
  2386.     (if lin
  2387.       (multiple-value-bind (instream get-end-pos)
  2388.           (make-read-from-screen-stream screen lin col)
  2389.         (unwind-protect
  2390.           (if (eq (with-ignored-errors ; Errors abfangen
  2391.                     (let ((*read-suppress* t) ; nur Syntaxcheck
  2392.                           (sys::*backquote-level* most-positive-fixnum) ; Bei Komma kein Error!
  2393.                           (*readtable* readtable)) ; |# soll Error liefern
  2394.                       (read-preserving-whitespace instream t nil t)
  2395.                   ) )
  2396.                   errorval
  2397.               )
  2398.             (values nil nil nil nil)
  2399.             (multiple-value-call #'values lin col (funcall get-end-pos))
  2400.           )
  2401.           (close instream)
  2402.       ) )
  2403.       (values nil nil nil nil)
  2404. ) ) )
  2405.  
  2406. (defun-doc mark-next-object (screen)
  2407.   #L{
  2408.   DEUTSCH "Nächstes LISP-Objekt markieren"
  2409.   ENGLISH "mark next Lisp object"
  2410.   FRANCAIS "marquer le prochain objet Lisp"
  2411.   }
  2412.   (multiple-value-call #'mark-region screen (get-next-object screen))
  2413. )
  2414.  
  2415. (defun get-toplevel-form (screen)
  2416.   (let ((text (screen-text screen))
  2417.         (lin (screen-lin screen))
  2418.         (col (screen-col screen)))
  2419.     ;; Klettere Zeilen hoch. Zeilen, die (nach evtl. Spaces) mit Semikolon
  2420.     ;; oder Klammer zu beginnen, werden ignoriert. Zeilen, deren Einrücktiefe
  2421.     ;; größer als eine weiter unten angetroffene ist, werden ebenfalls
  2422.     ;; ignoriert. Passiert eine Zeile diese Kriterien, wird versucht, ab ihr
  2423.     ;; zu lesen, und zwischen dem Ende der dabei erkannten Form und der
  2424.     ;; aktuellen Position darf nur Whitespace vorkommen.
  2425.     ; 1. Schritt: Whitespace nach links übergehen:
  2426.     (let ((line (aref text lin)))
  2427.       (loop
  2428.         (let ((col1 (position #\Space line :end col :test-not #'eql :from-end t)))
  2429.           (when col1 ; Non-Space gefunden, col verkleinern
  2430.             (setq col (1+ col1))
  2431.             (return)
  2432.           )
  2433.           ; Keines gefunden, probiere Zeile davor:
  2434.           (when (eql lin 0) (setq col 0) (return))
  2435.           (decf lin)
  2436.           (setq line (aref text lin))
  2437.           (setq col (length line))
  2438.     ) ) )
  2439.     ; 2. Schritt: Hochklettern:
  2440.     (let ((readtable (modified-readtable)) ; modifizierte Readtable pre-allozieren
  2441.           (lin1 lin)
  2442.           (older-marks '())
  2443.           (older-indent most-positive-fixnum))
  2444.       (loop
  2445.         (let* ((line (aref text lin1))
  2446.                (indent (position #\Space line :test-not #'eql)))
  2447.           (when (and indent
  2448.                      (not (member (char line indent) '( #\; #\) ))) ; (
  2449.                      (<= indent older-indent)
  2450.                 )
  2451.             (setq older-indent indent)
  2452.             (multiple-value-bind (lin0 col0 lin2 col2)
  2453.                 (get-next-object screen lin1 indent readtable)
  2454.               (when lin0
  2455.                 ; Ein Objekt geht von (lin0,col0) bis (lin2,col2).
  2456.                 (when (or (< lin0 lin)
  2457.                           (and (= lin0 lin) (<= col0 col))
  2458.                       )
  2459.                   ; Es fängt vor (lin,col) an.
  2460.                   (when (or (< lin lin2)
  2461.                             (and (= lin lin2) (<= col col2))
  2462.                         )
  2463.                     ; Es hört hinter (lin,col) auf.
  2464.                     (push (list lin0 col0 lin2 col2) older-marks)
  2465.         ) ) ) ) ) )
  2466.         (when (eql lin1 0) (return))
  2467.         (decf lin1)
  2468.       )
  2469.       ; Wenn passende Objekte gefunden wurden, dann liefere den äußersten:
  2470.       (if older-marks
  2471.         (values-list (first older-marks))
  2472.         (values nil nil nil nil)
  2473.       )
  2474. ) ) )
  2475.  
  2476. (defun-doc mark-toplevel-form (screen)
  2477.   #L{
  2478.   DEUTSCH "Toplevel-Form markieren"
  2479.   ENGLISH "mark surrounding top level form"
  2480.   FRANCAIS "marquer la forme entourante extérieure"
  2481.   }
  2482.   (multiple-value-call #'mark-region screen (get-toplevel-form screen))
  2483. )
  2484.  
  2485. (defun-doc eval-toplevel-form (screen)
  2486.   #L{
  2487.   DEUTSCH "Toplevel-Form auswerten"
  2488.   ENGLISH "evaluate surrounding top level form"
  2489.   FRANCAIS "évaluer la forme entourante extérieure"
  2490.   }
  2491.   (multiple-value-call #'eval-region screen (get-toplevel-form screen))
  2492. )
  2493.  
  2494. (defun get-next-tab-pos (screen lin col)
  2495.   (let* ((text (screen-text screen))
  2496.          (line (aref text lin))
  2497.          (line-len (length line))
  2498.         )
  2499.     (cond ((>= col line-len) line-len)
  2500.           ((eql (char line col) #\Space)
  2501.             (or (position #\Space line :start col :test-not #'eql) line-len)
  2502.           )
  2503.           ((eql (char line col) #\( ) ; )
  2504.             (min (+ col 2) line-len)
  2505.           )
  2506.           (t (let ((col1 (position #\Space line :start col)))
  2507.                (if col1
  2508.                  (or (position #\Space line :start col1 :test-not #'eql)
  2509.                      line-len
  2510.                  )
  2511.                  line-len
  2512. ) ) )     )  ) )
  2513.  
  2514. (defun cursor-to-col (screen col)
  2515.   (let* ((text (screen-text screen))
  2516.          (lin (screen-lin screen))
  2517.          (line (aref text lin))
  2518.          (line-len (length line))
  2519.         )
  2520.     (when (> col line-len)
  2521.       (resize-array line col)
  2522.       (fill line #\Space :start line-len)
  2523.       (refresh-line screen lin line-len)
  2524.     )
  2525.     (set-cursor screen lin col)
  2526. ) )
  2527.  
  2528. (defun-doc next-indent (screen)
  2529.   #L{
  2530.   DEUTSCH "Leerstellen bis zur nächsten Einrückung"
  2531.   ENGLISH "insert spaces up to next tab stop"
  2532.   FRANCAIS "ajouter des espaces jusqu'au prochain tabulateur"
  2533.   }
  2534.   (let ((lin (screen-lin screen))
  2535.         (col (screen-col screen)))
  2536.     (if (eql lin 0)
  2537.       (cursor-to-col screen (+ col 2))
  2538.       (cursor-to-col screen (get-next-tab-pos screen (1- lin) col))
  2539. ) ) )
  2540.  
  2541. (defvar *search-string* "") ; String, nach dem gesucht werden soll
  2542.  
  2543. (defun-doc search-first (screen)
  2544.   #L{
  2545.   DEUTSCH "Nach Textstück Suchen"
  2546.   ENGLISH "search for a string"
  2547.   FRANCAIS "chercher une chaîne"
  2548.   }
  2549.   (setq *search-string*
  2550.     (line-edit 
  2551.      #L{
  2552.      DEUTSCH " Suche: "
  2553.      ENGLISH " Search: "
  2554.      FRANCAIS " Chercher: "
  2555.      }
  2556.      *search-string*
  2557.   ) )
  2558.   (search-next screen)
  2559. )
  2560.  
  2561. (defun-doc search-next (screen)
  2562.   #L{
  2563.   DEUTSCH "Weitersuchen"
  2564.   ENGLISH "continue searching"
  2565.   FRANCAIS "continuer à chercher"
  2566.   }
  2567.   (let* ((text (screen-text screen))
  2568.          (lin (screen-lin screen))
  2569.          (col (screen-col screen))
  2570.          (text-len (length text))
  2571.          (index (if (< col (length (aref text lin)))
  2572.                   (search *search-string* (aref text lin) :start2 (1+ col))
  2573.                   nil
  2574.         ))      )
  2575.     (if index
  2576.       (set-cursor screen lin index)
  2577.       (loop (when (eql (incf lin) text-len) (return nil))
  2578.             (setq index (search *search-string* (aref text lin)))
  2579.             (when index (return (set-cursor screen lin index)))
  2580. ) ) ) )
  2581.  
  2582. ;===========================================================================
  2583. ;                        T A S T E N B E L E G U N G
  2584. ;===========================================================================
  2585.  
  2586. ;; Brunos Tastenbelegung:
  2587.  
  2588. #+DOSE
  2589. (progn
  2590.  
  2591. (defun C-H-doc (n)
  2592.   (format nil 
  2593.           #L{
  2594.           DEUTSCH "Fenster Nr. ~D nach oben bringen"
  2595.           ENGLISH "show window ~D"
  2596.           FRANCAIS "montrer la fenêtre ~D"
  2597.           }
  2598.           (1+ n)
  2599. ) )
  2600. (defun M-H-doc (n)
  2601.   (format nil 
  2602.           #L{
  2603.           DEUTSCH "Fenster Nr. ~D unsichtbar machen"
  2604.           ENGLISH "hide window ~D"
  2605.           FRANCAIS "cacher la fenêtre ~D"
  2606.           }
  2607.           (1+ n)
  2608. ) )
  2609.  
  2610. (bind-key #\C-F1       :control '(:TOP 0) '(C-H-doc 0))
  2611. (bind-key #\C-F2       :control '(:TOP 1) '(C-H-doc 1))
  2612. (bind-key #\C-F3       :control '(:TOP 2) '(C-H-doc 2))
  2613. (bind-key #\C-F4       :control '(:TOP 3) '(C-H-doc 3))
  2614. (bind-key #\C-F5       :control '(:TOP 4) '(C-H-doc 4))
  2615. (bind-key #\C-F6       :control '(:TOP 5) '(C-H-doc 5))
  2616. (bind-key #\C-F7       :control '(:TOP 6) '(C-H-doc 6))
  2617. (bind-key #\C-F8       :control '(:TOP 7) '(C-H-doc 7))
  2618. (bind-key #\C-F9       :control '(:TOP 8) '(C-H-doc 8))
  2619. (bind-key #\C-F10      :control '(:TOP 9) '(C-H-doc 9))
  2620.  
  2621. #+DOSE
  2622. (bind-key #\M-H        :control '(:HELP) '
  2623.           #L{
  2624.           DEUTSCH "Hilfefenster (diesen Text) nach oben bringen"
  2625.           ENGLISH "show help window (this text)"
  2626.           FRANCAIS "montrer la fenêtre d'aide (celle-ci)"
  2627.           }
  2628. )
  2629.  
  2630. (bind-key #\C-E        :control '(:ERROR) '
  2631.           #L{
  2632.           DEUTSCH "Errorfenster nach oben bringen"
  2633.           ENGLISH "show error window"
  2634.           FRANCAIS "montrer la fenêtre des erreurs"
  2635.           }
  2636. )
  2637. (bind-key #\C-T        :control '(:TRACE) '
  2638.           #L{
  2639.           DEUTSCH "Tracefenster nach oben bringen"
  2640.           ENGLISH "show trace window"
  2641.           FRANCAIS "montrer la fenêtre des traces"
  2642.           }
  2643. )
  2644.  
  2645. (bind-key #\M-F2       :control '(:HIDE 1) '(M-H-doc 1))
  2646. (bind-key #\M-F3       :control '(:HIDE 2) '(M-H-doc 2))
  2647. (bind-key #\M-F4       :control '(:HIDE 3) '(M-H-doc 3))
  2648. (bind-key #\M-F5       :control '(:HIDE 4) '(M-H-doc 4))
  2649. (bind-key #\M-F6       :control '(:HIDE 5) '(M-H-doc 5))
  2650. (bind-key #\M-F7       :control '(:HIDE 6) '(M-H-doc 6))
  2651. (bind-key #\M-F8       :control '(:HIDE 7) '(M-H-doc 7))
  2652. (bind-key #\M-F9       :control '(:HIDE 8) '(M-H-doc 8))
  2653. (bind-key #\M-F10      :control '(:HIDE 9) '(M-H-doc 9))
  2654.  
  2655. (bind-key #\M-Q        :control '(:DELETE) '
  2656.           #L{
  2657.           DEUTSCH "oberes Fenster wegwerfen"
  2658.           ENGLISH "delete current window"
  2659.           FRANCAIS "enlever la fenêtre courante"
  2660.           }
  2661. )
  2662. (bind-key #\M-X        :control '(:LOAD) '
  2663.           #L{
  2664.           DEUTSCH "File laden"
  2665.           ENGLISH "load file"
  2666.           FRANCAIS "charger fichier"
  2667.           }
  2668. )
  2669. (bind-key #\M-S        :control '(:SAVE) '
  2670.           #L{
  2671.           DEUTSCH "oberes Fenster abspeichern"
  2672.           ENGLISH "store to file"
  2673.           FRANCAIS "placer le contenu dans le fichier"
  2674.           }
  2675. )
  2676. (bind-key #\M-W        :control '(:SAVE-AS) '
  2677.           #L{
  2678.           DEUTSCH "oberes Fenster als neues File abspeichern"
  2679.           ENGLISH "store to new file"
  2680.           FRANCAIS "placer le contenu dans un nouveau fichier"
  2681.           }
  2682. )
  2683.  
  2684. (bind-key #\Escape     :control '(:LEAVE) '
  2685.           #L{
  2686.           DEUTSCH "Editor verlassen"
  2687.           ENGLISH "quit editor"
  2688.           FRANCAIS "quitter l'éditeur"
  2689.           }
  2690. )
  2691.  
  2692. (bind-key :string-char :writable #'insert-char)
  2693.  
  2694. ;; Ziffernblock wie gewöhnliche Tasten behandeln, dazu Shift-Space
  2695. (dolist (c '(#\( #\) #\+ #\- #\* #\/ #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\. #\,))
  2696.   (let* ((c c)
  2697.          (keypad-c (set-char-bit c :hyper t))
  2698.          (sh-keypad-c (set-char-bit c :super t)))
  2699.     (bind-key (list keypad-c sh-keypad-c)
  2700.               :writable
  2701.               #'(lambda (screen) (insert-char screen c))
  2702. ) ) )
  2703. #-DOSE (bind-key #\S-Space     :writable  #'(lambda (screen) (insert-char screen #\Space)))
  2704. #+DOSE (progn
  2705. (bind-key #\F11         :writable  #'(lambda (screen) (insert-char screen #\()))
  2706. (bind-key #\F12         :writable  #'(lambda (screen) (insert-char screen #\))))
  2707. )
  2708.  
  2709. (bind-key #\Up          :multiline 'cursor-up)
  2710. (bind-key #\Down        :multiline 'cursor-down)
  2711. (bind-key #\Left        :all       'cursor-left)
  2712. (bind-key #\Right       :all       'cursor-right)
  2713. #-DOSE (progn
  2714. (bind-key #\S-Up        :multiline 'line-up)
  2715. (bind-key #\S-Down      :multiline 'line-down)
  2716. (bind-key #\C-Up        :multiline 'page-up)
  2717. (bind-key #\C-Down      :multiline 'page-down)
  2718. (bind-key #\S-Left      :all       'cursor-to-start-of-line)
  2719. (bind-key #\S-Right     :all       'cursor-to-end-of-line)
  2720. )
  2721. #+DOSE (progn
  2722. (bind-key #\C-Up        :multiline 'line-up)
  2723. (bind-key #\C-Down      :multiline 'line-down)
  2724. (bind-key #\PgUp        :multiline 'page-up)
  2725. (bind-key #\PgDn        :multiline 'page-down)
  2726. (bind-key #\Home        :all       'cursor-to-start-of-line)
  2727. (bind-key #\End         :all       'cursor-to-end-of-line)
  2728. )
  2729.  
  2730. ; Emacs-like:
  2731. (bind-key #\C-P         :multiline 'cursor-up)
  2732. (bind-key #\C-N         :multiline 'cursor-down)
  2733. (bind-key #\C-S         :all       'cursor-left)
  2734. (bind-key #\C-D         :all       'cursor-right)
  2735. #-DOSE (progn
  2736. (bind-key #\S-C-P       :multiline 'line-up)
  2737. (bind-key #\S-C-N       :multiline 'line-down)
  2738. (bind-key #\S-C-S       :all       'cursor-to-start-of-line)
  2739. (bind-key #\S-C-D       :all       'cursor-to-end-of-line)
  2740. )
  2741.  
  2742. #+DOSE (progn
  2743. (bind-key #\C-PgUp      :multiline 'cursor-to-start-of-text)
  2744. (bind-key #\C-PgDn      :multiline 'cursor-to-end-of-text)
  2745. )
  2746.  
  2747. (bind-key #\C-B         :all       'set-block-start)
  2748. (bind-key #\C-K         :all       'set-block-end)
  2749. (bind-key #\M-B         :all       'cursor-to-start-of-block)
  2750. (bind-key #\M-K         :all       'cursor-to-end-of-block)
  2751. (bind-key #\C-H         :all       'hide-block)
  2752.  
  2753. (bind-key '(#\Return #\Enter) :and-writable-multiline 'insert-line)
  2754. (bind-key '(#\Return #\Enter) :and-writable-not-multiline 'finish)
  2755. (bind-key #\C-Y         :and-writable-multiline 'delete-line)
  2756. (bind-key #\C-J         :and-writable-multiline 'combine-lines)
  2757. (bind-key #\Delete      :writable  'delete-char)
  2758. #+DOSE (progn
  2759. (bind-key #\C-Delete    :and-writable-multiline 'delete-char-1)
  2760. (bind-key #\C-Delete    :and-writable-not-multiline 'delete-char)
  2761. )
  2762. (bind-key #\Backspace   :writable  'backspace)
  2763. #+DOSE (progn
  2764. (bind-key #\C-Backspace :and-writable-multiline 'backspace-1)
  2765. (bind-key #\C-Backspace :and-writable-not-multiline 'backspace)
  2766. )
  2767.  
  2768. (bind-key #\C-Right     :all       'mark-next-object)
  2769. (bind-key #\C-Enter     :all       'mark-toplevel-form)
  2770. #+DOSE
  2771. (bind-key '(#\C-Return #\C-Enter) :and-writable-multiline 'eval-toplevel-form)
  2772. ;(bind-key #\C-E         :and-writable-multiline 'eval-block)
  2773. ;(bind-key #\C-E         :and-writable-multiline 'eval-buffer)
  2774.  
  2775. (bind-key #\C-X         :writable  'delete-block-buffer)
  2776. (bind-key #\C-C         :all       'copy-block-buffer)
  2777. (bind-key #\C-V         :writable  'paste-buffer)
  2778. ;(bind-key #\M-C         :writable  'copy-block)
  2779. ;(bind-key #\M-V         :writable  'move-block)
  2780.  
  2781. (bind-key #\Tab         :writable  'next-indent)
  2782.  
  2783. (bind-key #\C-0         :all       (set-mark-fn 0) '(set-mark-doc 0))
  2784. (bind-key #\C-1         :all       (set-mark-fn 1) '(set-mark-doc 1))
  2785. (bind-key #\C-2         :all       (set-mark-fn 2) '(set-mark-doc 2))
  2786. (bind-key #\C-3         :all       (set-mark-fn 3) '(set-mark-doc 3))
  2787. (bind-key #\C-4         :all       (set-mark-fn 4) '(set-mark-doc 4))
  2788. (bind-key #\C-5         :all       (set-mark-fn 5) '(set-mark-doc 5))
  2789. (bind-key #\C-6         :all       (set-mark-fn 6) '(set-mark-doc 6))
  2790. (bind-key #\C-7         :all       (set-mark-fn 7) '(set-mark-doc 7))
  2791. (bind-key #\C-8         :all       (set-mark-fn 8) '(set-mark-doc 8))
  2792. (bind-key #\C-9         :all       (set-mark-fn 9) '(set-mark-doc 9))
  2793. (bind-key #\M-0         :all       (cursor-to-mark-fn 0) '(cursor-to-mark-doc 0))
  2794. (bind-key #\M-1         :all       (cursor-to-mark-fn 1) '(cursor-to-mark-doc 1))
  2795. (bind-key #\M-2         :all       (cursor-to-mark-fn 2) '(cursor-to-mark-doc 2))
  2796. (bind-key #\M-3         :all       (cursor-to-mark-fn 3) '(cursor-to-mark-doc 3))
  2797. (bind-key #\M-4         :all       (cursor-to-mark-fn 4) '(cursor-to-mark-doc 4))
  2798. (bind-key #\M-5         :all       (cursor-to-mark-fn 5) '(cursor-to-mark-doc 5))
  2799. (bind-key #\M-6         :all       (cursor-to-mark-fn 6) '(cursor-to-mark-doc 6))
  2800. (bind-key #\M-7         :all       (cursor-to-mark-fn 7) '(cursor-to-mark-doc 7))
  2801. (bind-key #\M-8         :all       (cursor-to-mark-fn 8) '(cursor-to-mark-doc 8))
  2802. (bind-key #\M-9         :all       (cursor-to-mark-fn 9) '(cursor-to-mark-doc 9))
  2803.  
  2804. #+DOSE (progn
  2805. (bind-key #\M-Left      :writable  'clear-start-of-line)
  2806. (bind-key #\M-Right     :writable  'clear-end-of-line)
  2807. )
  2808.  
  2809. #+DOSE
  2810. (bind-key #\M-L         :multiline 'search-first)
  2811. (bind-key #\C-L         :multiline 'search-next)
  2812.  
  2813. )
  2814.  
  2815. #+(or UNIX WIN32-UNIX)
  2816. (progn ; noch sehr rudimentär und unvollständig! ??
  2817.  
  2818. (defun C-H-doc (n)
  2819.   (format nil 
  2820.           #L{
  2821.           DEUTSCH "Fenster Nr. ~D nach oben bringen"
  2822.           ENGLISH "show window ~D"
  2823.           FRANCAIS "montrer la fenêtre ~D"
  2824.           }
  2825.           (1+ n)
  2826. ) )
  2827.  
  2828. (bind-key #\F1         :control '(:TOP 0) '(C-H-doc 0))
  2829. (bind-key #\F2         :control '(:TOP 1) '(C-H-doc 1))
  2830. (bind-key #\F3         :control '(:TOP 2) '(C-H-doc 2))
  2831. (bind-key #\F4         :control '(:TOP 3) '(C-H-doc 3))
  2832. (bind-key #\F5         :control '(:TOP 4) '(C-H-doc 4))
  2833. (bind-key #\F6         :control '(:TOP 5) '(C-H-doc 5))
  2834. (bind-key #\F7         :control '(:TOP 6) '(C-H-doc 6))
  2835. (bind-key #\F8         :control '(:TOP 7) '(C-H-doc 7))
  2836. (bind-key #\F9         :control '(:TOP 8) '(C-H-doc 8))
  2837. (bind-key #\F10        :control '(:TOP 9) '(C-H-doc 9))
  2838.  
  2839. (bind-key #\C-G        :control '(:HELP) '
  2840.           #L{
  2841.           DEUTSCH "Hilfefenster (diesen Text) nach oben bringen"
  2842.           ENGLISH "show help window (this text)"
  2843.           FRANCAIS "montrer la fenêtre d'aide (celle-ci)"
  2844.           }
  2845. )
  2846. (bind-key #\C-E        :control '(:ERROR) '
  2847.           #L{
  2848.           DEUTSCH "Errorfenster nach oben bringen"
  2849.           ENGLISH "show error window"
  2850.           FRANCAIS "montrer la fenêtre des erreurs"
  2851.           }
  2852. )
  2853. (bind-key #\C-T        :control '(:TRACE) '
  2854.           #L{
  2855.           DEUTSCH "Tracefenster nach oben bringen"
  2856.           ENGLISH "show trace window"
  2857.           FRANCAIS "montrer la fenêtre des traces"
  2858.           }
  2859. )
  2860.  
  2861. (bind-key #\C-Q        :control '(:DELETE) '
  2862.           #L{
  2863.           DEUTSCH "oberes Fenster wegwerfen"
  2864.           ENGLISH "delete current window"
  2865.           FRANCAIS "enlever la fenêtre courante"
  2866.           }
  2867. )
  2868. (bind-key #\C-X        :control '(:LOAD) '
  2869.           #L{
  2870.           DEUTSCH "File laden"
  2871.           ENGLISH "load file"
  2872.           FRANCAIS "charger fichier"
  2873.           }
  2874. )
  2875. (bind-key #\C-W        :control '(:SAVE-AS) '
  2876.           #L{
  2877.           DEUTSCH "oberes Fenster als neues File abspeichern"
  2878.           ENGLISH "store to new file"
  2879.           FRANCAIS "placer le contenu dans un nouveau fichier"
  2880.           }
  2881. )
  2882.  
  2883. (bind-key '#\Escape    :control '(:LEAVE) '
  2884.           #L{
  2885.           DEUTSCH "Editor verlassen"
  2886.           ENGLISH "quit editor"
  2887.           FRANCAIS "quitter l'éditeur"
  2888.           }
  2889. )
  2890.  
  2891. (bind-key :string-char :writable #'insert-char)
  2892.  
  2893. (bind-key #\Up          :multiline 'cursor-up)
  2894. (bind-key #\Down        :multiline 'cursor-down)
  2895. (bind-key #\Left        :all       'cursor-left)
  2896. (bind-key #\Right       :all       'cursor-right)
  2897. (bind-key #\PgUp        :multiline 'page-up)
  2898. (bind-key #\PgDn        :multiline 'page-down)
  2899.  
  2900. ; Emacs-like:
  2901. (bind-key #\C-P         :multiline 'cursor-up)
  2902. (bind-key #\C-N         :multiline 'cursor-down)
  2903. (bind-key #\C-S         :all       'cursor-left)
  2904. (bind-key #\C-D         :all       'cursor-right)
  2905. (bind-key #\C-A         :all       'cursor-to-start-of-line)
  2906. (bind-key #\C-F         :all       'cursor-to-end-of-line)
  2907.  
  2908. (bind-key #\C-B         :all       'set-block-start)
  2909. (bind-key #\C-K         :all       'set-block-end)
  2910. (bind-key #\C-U         :all       'hide-block)
  2911.  
  2912. (bind-key #\Return      :and-writable-multiline 'insert-line)
  2913. (bind-key #\Return      :and-writable-not-multiline 'finish)
  2914. (bind-key #\C-Y         :and-writable-multiline 'delete-line)
  2915. (bind-key #\C-J         :and-writable-multiline 'combine-lines)
  2916. (bind-key '(#\Backspace #\Delete) :writable  'backspace)
  2917.  
  2918. (bind-key #\C-V         :all       'skip-whitespace-right)
  2919. (bind-key #\C-R         :all       'mark-next-object)
  2920. (bind-key '(#\C-O #\F11) :all      'mark-toplevel-form)
  2921. (bind-key '(#\C-L #\F12) :and-writable-multiline 'eval-toplevel-form)
  2922.  
  2923. (bind-key #\Tab         :writable  'next-indent)
  2924.  
  2925. )
  2926.  
  2927. #+AMIGA
  2928. (progn
  2929.  
  2930. (defun C-H-doc (n)
  2931.   (format nil 
  2932.           #L{
  2933.           DEUTSCH "Fenster Nr. ~D nach oben bringen"
  2934.           ENGLISH "show window ~D"
  2935.           FRANCAIS "montrer la fenêtre ~D"
  2936.           }
  2937.           (1+ n)
  2938. ) )
  2939. (defun M-H-doc (n)
  2940.   (format nil 
  2941.           #L{
  2942.           DEUTSCH "Fenster Nr. ~D unsichtbar machen"
  2943.           ENGLISH "hide window ~D"
  2944.           FRANCAIS "cacher la fenêtre ~D"
  2945.           }
  2946.           (1+ n)
  2947. ) )
  2948.  
  2949. (bind-key :string-char :writable #'insert-char)
  2950.  
  2951. (bind-key #\Left     :all       'cursor-left)
  2952. (bind-key #\Right    :all       'cursor-right)
  2953. (bind-key #\Down     :multiline 'cursor-down)
  2954. (bind-key #\Up       :multiline 'cursor-up)
  2955. (bind-key #\S-Left   :all       'cursor-to-start-of-line)
  2956. (bind-key #\S-Right  :all       'cursor-to-end-of-line)
  2957. (bind-key #\S-Down   :multiline 'page-down)
  2958. (bind-key #\S-Up     :multiline 'page-up)
  2959.  
  2960. (bind-key #\Code0    :all       'skip-whitespace-right) ;Null
  2961. (bind-key #\C-A      :control   '(:SAVE-AS) '
  2962.           #L{
  2963.           DEUTSCH "oberes Fenster als neues File abspeichern"
  2964.           ENGLISH "store to new file"
  2965.           FRANCAIS "placer le contenu dans un nouveau fichier"
  2966.           }
  2967. )
  2968. (bind-key #\C-B       :all       'set-block-start)
  2969. ; #\C-C bleibt c-C
  2970. (bind-key #\C-D       :all       'set-block-end)
  2971. (bind-key #\C-E       :control   '(:ERROR)  '
  2972.           #L{
  2973.           DEUTSCH "Errorfenster nach oben bringen"
  2974.           ENGLISH "show error window"
  2975.           FRANCAIS "montrer la fenêtre des erreurs"
  2976.           }
  2977. )
  2978. (bind-key #\C-F       :multiline 'search-first)
  2979. ; #\C-G leer
  2980. (bind-key #\Backspace :and-writable-multiline 'backspace-1) ; #\C-H
  2981. (bind-key #\Backspace :and-writable-not-multiline 'backspace) ; #\C-H
  2982. (bind-key #\Delete    :and-writable-multiline 'delete-char-1)
  2983. (bind-key #\Delete    :and-writable-not-multiline 'delete-char)
  2984. (bind-key #\Tab       :writable  'next-indent) ; #\C-I
  2985. (bind-key #\C-J       :and-writable-multiline 'combine-lines)
  2986. (bind-key #\C-K       :writable  'clear-end-of-line)
  2987. (bind-key #\C-L       :and-writable-multiline 'eval-toplevel-form)
  2988. (bind-key #\Return    :and-writable-multiline 'insert-line) ; #\C-M
  2989. (bind-key #\Return    :and-writable-not-multiline 'finish) ; #\C-M
  2990. (bind-key #\C-N       :multiline 'search-next)
  2991. (bind-key #\C-O       :all       'mark-toplevel-form)
  2992. ; #\C-P leer
  2993. (bind-key #\C-Q       :control   '(:DELETE) '
  2994.           #L{
  2995.           DEUTSCH "oberes Fenster wegwerfen"
  2996.           ENGLISH "delete current window"
  2997.           FRANCAIS "enlever la fenêtre courante"
  2998.           }
  2999. )
  3000. (bind-key #\C-R       :all       'mark-next-object)
  3001. (bind-key #\C-S       :control   '(:SAVE) '
  3002.           #L{
  3003.           DEUTSCH "oberes Fenster abspeichern"
  3004.           ENGLISH "store to file"
  3005.           FRANCAIS "placer le contenu dans le fichier"
  3006.           }
  3007. )
  3008. (bind-key #\C-T       :control   '(:TRACE) '
  3009.           #L{
  3010.           DEUTSCH "Tracefenster nach oben bringen"
  3011.           ENGLISH "show trace window"
  3012.           FRANCAIS "montrer la fenêtre des traces"
  3013.           }
  3014. )
  3015. (bind-key #\C-U       :all       'hide-block)
  3016. (bind-key #\C-V       :and-writable-multiline 'eval-block)
  3017. (bind-key #\C-W       :writable  'delete-block-buffer)
  3018. (bind-key #\C-X       :control   '(:LOAD)  '
  3019.           #L{
  3020.           DEUTSCH "File laden"
  3021.           ENGLISH "load file"
  3022.           FRANCAIS "charger fichier"
  3023.           }
  3024. )
  3025. (bind-key #\C-Y       :all       'paste-buffer)
  3026. (bind-key #\C-Z       :control   '(:HIDE)  '
  3027.           #L{
  3028.           DEUTSCH "oberes Fenster unsichtbar machen"
  3029.           ENGLISH "hide top window"
  3030.           FRANCAIS "cacher la fenêtre courante"
  3031.           }
  3032. )
  3033. (bind-key '(#\Escape #\Code28) ; c-[, c-\
  3034.           :control '(:LEAVE) '
  3035.           #L{
  3036.           DEUTSCH "Editor verlassen"
  3037.           ENGLISH "quit editor"
  3038.           FRANCAIS "quitter l'éditeur"
  3039.           }
  3040. )
  3041. (bind-key '(#\Code29 #\C-])   :control '(:TOP 0) '(C-H-doc 0)) ; c-]
  3042. ; #\Code30 = c-^ leer
  3043. ; #\Code31 = c-_ leer
  3044.  
  3045. (bind-key #\Help      :control '(:HELP) '
  3046.           #L{
  3047.           DEUTSCH "Hilfefenster (diesen Text) nach oben bringen"
  3048.           ENGLISH "show help window (this text)"
  3049.           FRANCAIS "montrer la fenêtre d'aide (celle-ci)"
  3050.           }
  3051. )
  3052.  
  3053. (bind-key #\F1        :control '(:TOP 0) '(C-H-doc 0))
  3054. (bind-key #\F2        :control '(:TOP 1) '(C-H-doc 1))
  3055. (bind-key #\F3        :control '(:TOP 2) '(C-H-doc 2))
  3056. (bind-key #\F4        :control '(:TOP 3) '(C-H-doc 3))
  3057. (bind-key #\F5        :control '(:TOP 4) '(C-H-doc 4))
  3058. (bind-key #\F6        :all     (cursor-to-mark-fn 0) '(cursor-to-mark-doc 0))
  3059. (bind-key #\F7        :all     (cursor-to-mark-fn 1) '(cursor-to-mark-doc 1))
  3060. (bind-key #\F8        :all     (cursor-to-mark-fn 2) '(cursor-to-mark-doc 2))
  3061. (bind-key #\F9        :all     (cursor-to-mark-fn 3) '(cursor-to-mark-doc 3))
  3062. (bind-key #\F10       :all     (cursor-to-mark-fn 4) '(cursor-to-mark-doc 4))
  3063. (bind-key #\S-F1      :control '(:TOP 5) '(C-H-doc 5))
  3064. (bind-key #\S-F2      :control '(:TOP 6) '(C-H-doc 6))
  3065. (bind-key #\S-F3      :control '(:TOP 7) '(C-H-doc 7))
  3066. (bind-key #\S-F4      :control '(:TOP 8) '(C-H-doc 8))
  3067. (bind-key #\S-F5      :control '(:TOP 9) '(C-H-doc 9))
  3068. (bind-key #\S-F6      :all     (set-mark-fn 0) '(set-mark-doc 0))
  3069. (bind-key #\S-F7      :all     (set-mark-fn 1) '(set-mark-doc 1))
  3070. (bind-key #\S-F8      :all     (set-mark-fn 2) '(set-mark-doc 2))
  3071. (bind-key #\S-F9      :all     (set-mark-fn 3) '(set-mark-doc 3))
  3072. (bind-key #\S-F10     :all     (set-mark-fn 4) '(set-mark-doc 4))
  3073.  
  3074. )
  3075.  
  3076. ;; *undo* behandeln ??
  3077. ;; #\C-R für Repeat ??
  3078.  
  3079. ;###############################################################################
  3080.  
  3081. ;; ob der eingebaute Editor benutzt wird:
  3082. (defparameter *use-ed* t)
  3083.  
  3084. (fmakunbound 'ed)
  3085. ; Erweiterte Version von ED in DEFS1.LSP:
  3086. (defun ed (&optional arg &aux funname sym fun def)
  3087.   (if (null arg)
  3088.     (if *use-ed*
  3089.       (edit)
  3090.       (edit-file "")
  3091.     )
  3092.     (if (or (pathnamep arg) (stringp arg))
  3093.       (if *use-ed*
  3094.         (edit `(:LOAD ,(namestring arg)))
  3095.         (edit-file arg)
  3096.       )
  3097.       (if (and (cond ((sys::function-name-p arg) (setq funname arg) t)
  3098.                      ((functionp arg) (sys::function-name-p (setq funname (sys::%record-ref arg 0))))
  3099.                      (t nil)
  3100.                )
  3101.                (fboundp (setq sym (sys::get-funname-symbol funname)))
  3102.                (or (setq fun (macro-function sym))
  3103.                    (setq fun (symbol-function sym))
  3104.                )
  3105.                (functionp fun)
  3106.                (or (sys::function-name-p arg) (eql fun arg))
  3107.                (setq def (get sym 'sys::definition))
  3108.           )
  3109.         (if *use-ed*
  3110.           (edit `(:FORM ,sym ,*package* ,(cdr def)
  3111.                         ,(write-to-string (car def) :escape t :pretty t)
  3112.           )      )
  3113.           (let ((tempfile (editor-tempfile)))
  3114.             (with-open-file (f tempfile :direction :output)
  3115.               (pprint (car def) f)
  3116.               (terpri f) (terpri f)
  3117.             )
  3118.             (let ((date (file-write-date tempfile)))
  3119.               (edit-file tempfile)
  3120.               (when (> (file-write-date tempfile) date)
  3121.                 (with-open-file (f tempfile :direction :input)
  3122.                   (let ((*package* *package*) ; *PACKAGE* binden
  3123.                         (end-of-file "EOF")) ; einmaliges Objekt
  3124.                     (loop
  3125.                       (let ((obj (read f nil end-of-file)))
  3126.                         (when (eql obj end-of-file) (return))
  3127.                         (print (evalhook obj nil nil (cdr def)))
  3128.                 ) ) ) )
  3129.                 (when (compiled-function-p fun) (compile funname))
  3130.             ) )
  3131.             funname
  3132.         ) )
  3133.         (sys::error-of-type 'error
  3134.           #L{
  3135.           DEUTSCH "~S ist nicht editierbar."
  3136.           ENGLISH "~S cannot be edited."
  3137.           FRANCAIS "~S ne peut pas être édité."
  3138.           }
  3139.           arg
  3140. ) ) ) ) )
  3141.  
  3142.