anchor.diff:  
   (in-package :mezzanine.editor)
   
  +;;; Lines.
  +
   (defclass line ()
  -  ((%next :initarg :next :accessor next)
  -   (%prev :initarg :prev :accessor prev)
  +  ((%next :initarg :next :accessor next-line)
  +   (%prev :initarg :prev :accessor previous-line)
      (%data :initarg :data :accessor data)
  -   (%version :initarg :version :accessor version))
  +   (%version :initarg :version :accessor line-version)
  +   (%number :initarg :number :accessor line-number)
  +   (%mark-list :initarg :mark-list :accessor line-mark-list)
  +   (%buffer :initarg :buffer :accessor line-buffer))
     (:default-initargs :next nil
                        :prev nil
                        :data (make-array 50 :element-type 'character :adjustable t :fill-pointer 0)
  -                     :version 0))
  +                     :version 0
  +                     :number 0
  +                     :mark-list '()
  +                     :buffer nil))
  +
  +(defgeneric line-character (line charpos))
  +(defgeneric (setf line-character) (value line charpos))
  +(defgeneric line-length (line))
  +
  +(defmethod line-character ((line line) charpos)
  +  (aref (data line) charpos))
  +
  +(defmethod (setf line-character) (value (line line) charpos)
  +  (setf (aref (data line) charpos) value))
  +
  +(defmethod line-length ((line line))
  +  (length (data line)))
  +
  +(defmethod print-object ((object line) stream)
  +  (print-unreadable-object (object stream :type t :identity t)
  +    (format stream "N:~D V:~D" (line-number object) (line-version object))))
  +
  +;;; Marks.
  +
  +(defclass mark ()
  +  ((%line :initarg :line :reader mark-line)
  +   (%charpos :initarg :charpos :reader mark-charpos)
  +   ;; :left, :right or :temporary.
  +   (%kind :initarg :kind :reader mark-kind)))
  +
  +(defgeneric (setf mark-line) (value mark))
  +(defgeneric (setf mark-charpos) (value mark))
  +(defgeneric (setf mark-kind) (value mark))
  +
  +(defmethod print-object ((object mark) stream)
  +  (print-unreadable-object (object stream :type t :identity t)
  +    (format stream "~S:~D ~S" (mark-line object) (mark-charpos object) (mark-kind object))))
  +
  +;;; Buffers.
  +
  +(defclass buffer ()
  +  ((%first-line :accessor first-line)
  +   (%last-line :accessor last-line)
  +   (%point :reader buffer-point)
  +   (%point-column-hint :initarg :point-column-hint :accessor point-column-hint)
  +   (%mark :reader buffer-mark)
  +   (%mark-active :initarg :mark-active :accessor buffer-mark-active)
  +   (%properties))
  +  (:default-initargs :mark-active nil :point-column-hint 0))
  +
  +(defgeneric buffer-property (buffer property-name &optional default))
  +(defgeneric (setf buffer-property) (value buffer property-name &optional default))
  +
  +(defmethod buffer-property ((buffer buffer) property-name &optional default)
  +  (gethash property-name (slot-value buffer '%properties) default))
  +
  +(defmethod (setf buffer-property) (value (buffer buffer) property-name &optional default)
  +  (setf (gethash property-name (slot-value buffer '%properties) default) value))
  +
  +(defmethod initialize-instance :after ((instance buffer) &key &allow-other-keys)
  +  (let ((line (make-instance 'line :buffer instance)))
  +    (setf (first-line instance) line
  +          (last-line instance) line
  +          (slot-value instance '%properties) (make-hash-table)
  +          (slot-value instance '%point) (make-mark line 0 :right)
  +          (slot-value instance '%mark) (make-mark line 0 :left))))
  +
  +;;; The editor itself.
   
   (defclass editor ()
     ((%fifo :initarg :fifo :reader fifo)
      (%pending-event :initarg :pending-event :accessor pending-event)
      (%pending-redisplay :initarg :pending-redisplay :accessor pending-redisplay)
  -   (%font :initarg :font :reader font)
      (%window :initarg :window :accessor window)
      (%frame :initarg :frame :accessor frame)
  -   (%first-line :initarg :first-line :accessor first-line)
  -   (%last-line :initarg :last-line :accessor last-line)
  -   (%point-line :initarg :point-line :accessor point-line)
  -   (%point-offset :initarg :point-offset :accessor point-offset)
  -   (%point-column-hint :initarg :point-column-hint :accessor point-column-hint)
  +   (%buffer :initarg :buffer :accessor current-buffer)
  +   (%font :initarg :font :reader font)
      (%foreground-colour :initarg :foreground-colour :accessor foreground-colour)
      (%background-colour :initarg :background-colour :accessor background-colour)
      ;; Redisplay state.
  -   (%window-top-line :initarg :window-top-line :accessor window-top-line)
  -   (%window-top :initarg :window-top :accessor window-top)
  -   (%current-screen :initarg :current-screen :accessor current-screen)
  -   (%current-point-logical-line :initarg :current-point-screen-line :accessor current-point-logical-line))
  +   (%current-screen :initarg :screen :accessor editor-current-screen)
  +   (%line-cache :initarg :display-line-cache :accessor display-line-cache)
  +   )
     (:default-initargs :pending-event nil
  -                     :pending-redisplay nil
  -                     :csr-x 0 :csr-y 0 :csr-char #\Space
  +                     :pending-redisplay t
                        :foreground-colour #xFFDCDCCC
  -                     :background-colour #xFF3E3E3E))
  +                     :background-colour #xFF3E3E3E
  +                     :screen nil
  +                     :display-line-cache '()))
   
   (defvar *editor*)
   
  
positive.code:     (truncate (- (mezzanine.gui.compositor:height (window *editor*)) top bottom)
                (mezzanine.gui.font:line-height (font *editor*)))))
  
  (defun put-string (string pen y start end &key bold invert underline)
    (multiple-value-bind (left right top bottom)
        (mezzanine.gui.widgets:frame-size (frame *editor*))
      (loop
         with pen-start = pen
         with font = (font *editor*)
         with y-pos = (* y (mezzanine.gui.font:line-height font))
         with baseline = (+ y-pos (mezzanine.gui.font:ascender font))
         with fb = (mezzanine.gui.compositor:window-buffer (window *editor*))
         with colour = (foreground-colour *editor*)
         with line-height = (mezzanine.gui.font:line-height font)
         with foreground = (if invert
                               (background-colour *editor*)
                               (foreground-colour *editor*))
         with background = (if invert
                               (foreground-colour *editor*)
                               (background-colour *editor*))
         for ch-offset from start below end
         for glyph = (mezzanine.gui.font:character-to-glyph font (aref string ch-offset))
         for mask = (mezzanine.gui.font:glyph-mask glyph)
         for advance = (mezzanine.gui.font:glyph-advance glyph)
         do
           (when invert
             (mezzanine.gui:bitset line-height advance
                                   background
                                   fb (+ top y-pos) (+ left pen)))
           (mezzanine.gui:bitset-argb-xrgb-mask-8 (array-dimension mask 0) (array-dimension mask 1)
                                                  foreground
                                                  mask 0 0
                                                  fb
                                                  (+ top (- baseline (mezzanine.gui.font:glyph-yoff glyph)))
                                                  (+ left pen (mezzanine.gui.font:glyph-xoff glyph)))
           (when bold
             (mezzanine.gui:bitset-argb-xrgb-mask-8 (array-dimension mask 0) (array-dimension mask 1)
                                                    foreground
                                                    mask 0 0
                                                    fb
                                                    (+ top (- baseline (mezzanine.gui.font:glyph-yoff glyph)))
                                                    (+ left pen (mezzanine.gui.font:glyph-xoff glyph))))
           (when underline
             (mezzanine.gui:bitset-argb-xrgb 1 advance
                                             foreground
                                             fb (+ top baseline) (+ left pen)))
           (incf pen advance)
         finally (return pen))))
  
  (defun put-char (character x y &key invert bold underline)
    (multiple-value-bind (left right top bottom)
        (mezzanine.gui.widgets:frame-size (frame *editor*))
      (let* ((glyph (mezzanine.gui.font:character-to-glyph (font *editor*) character))
             (mask (mezzanine.gui.font:glyph-mask glyph))
             (advance (mezzanine.gui.font:glyph-advance glyph))
             (fb (mezzanine.gui.compositor:window-buffer (window *editor*)))
             (win-width (- (mezzanine.gui.compositor:width (window *editor*)) left right))
             (line-height (mezzanine.gui.font:line-height (font *editor*)))
             (y (* y line-height)))
        (when (<= (+ x advance) win-width)
          (when invert
            (mezzanine.gui:bitset line-height advance
                                  (foreground-colour *editor*)
                                  fb (+ top y) (+ left x)))
          (mezzanine.gui:bitset-argb-xrgb-mask-8 (array-dimension mask 0) (array-dimension mask 1)
                                                 (if invert
                                                     (background-colour *editor*)
                                                     (foreground-colour *editor*))
                                                 mask 0 0
                                                 fb
                                                 (+ top (- (+ y (mezzanine.gui.font:ascender (font *editor*))) (mezzanine.gui.font:glyph-yoff glyph)))
                                                 (+ left x (mezzanine.gui.font:glyph-xoff glyph)))
          (when bold
            (mezzanine.gui:bitset-argb-xrgb-mask-8 (array-dimension mask 0) (array-dimension mask 1)
                                                   (if invert
                                                       (background-colour *editor*)
                                                       (foreground-colour *editor*))
                                                   mask 0 0
                                                   fb
                                                   (+ top (- (+ y (mezzanine.gui.font:ascender (font *editor*))) (mezzanine.gui.font:glyph-yoff glyph)))
                                                   (+ left x (mezzanine.gui.font:glyph-xoff glyph))))
          (when underline
            (mezzanine.gui:bitset-argb-xrgb 1 advance
                                            (if invert
                                                (background-colour *editor*)
                                                (foreground-colour *editor*))
                                            fb
                                            (+ top y (mezzanine.gui.font:ascender (font *editor*)))
                                            (+ left x))))
        (+ x advance))))
  
  (defclass logical-line-segment ()
    ((%logical-line :initarg :logical-line :accessor logical-line)
     (%start :initarg :start :accessor line-start)
     (%end :initarg :start :accessor line-end)))
  
  (defclass logical-line ()
    ((%physical-line :initarg :physical-line :accessor physical-line)
     (%version :initarg :version :accessor version)
     (%segments :initarg :segments :accessor segments))
    (:default-initargs :segments (make-array 1 :adjustable t :fill-pointer 0)))
  
  (defmethod physical-line ((line logical-line-segment))
    (physical-line (logical-line line)))
  
  (defun physical-line-to-logical-line-1 (line win-width)
    (let* ((font (font *editor*))
           (pen-offset 0)
           (logical-line (make-instance 'logical-line
                                        :physical-line line
                                        :version (version line)))
           (segs (segments logical-line))
           (current-segment (make-instance 'logical-line-segment
                                           :logical-line logical-line
                                           :start 0)))
      (flet ((finish-segment (end)
               (check-pending-input)
               (setf (line-end current-segment) end)
               (vector-push-extend current-segment segs)
               (setf pen-offset 0)
                     current-segment (make-instance 'logical-line-segment
                                                    :logical-line logical-line
                                                    :start end)))
        (dotimes (i (line-length line))
          (let* ((glyph (mezzanine.gui.font:character-to-glyph (font *editor*) (aref (data line) i)))
                 (advance (mezzanine.gui.font:glyph-advance glyph)))
            ;;(format t "Pen-offset: ~S  Advance ~S  Width ~S~%" pen-offset advance win-width)
            (incf pen-offset advance)
            (when (>= pen-offset win-width)
              ;;(format t "Wrap line. ~S ~S~%" pen-offset win-width)
              (finish-segment i))))
        (finish-segment (line-length line)))
      logical-line))
  
  (defun physical-line-to-logical-line (current-screen line win-width)
    ;; Convert a physical line to a logical line, possibly reusing previously displayed logical lines.
    (cond
      (current-screen
       (loop for seg across current-screen do
            (when (and (zerop (line-start seg))
                       (eql (physical-line seg) line)
                       (eql (version (logical-line seg)) (version (physical-line seg))))
              #+(or)(format t "Reused logical line ~S for physical line ~S.~%" (logical-line seg) line)
              (return (logical-line seg)))
          finally (return (physical-line-to-logical-line-1 line win-width))))
      (t (physical-line-to-logical-line-1 line win-width))))
  
  (defun build-screen-line-list (current-screen top-line win-width)
    (do ((screen (make-array (length current-screen) :adjustable t :fill-pointer 0))
         (point-screen-line nil)
         (lines-since-point 0)
         (line top-line (next line)))
        ((or (null line)
             (> lines-since-point (window-rows)))
         (values screen point-screen-line))
      (let ((logical-line (physical-line-to-logical-line current-screen line win-width)))
        (loop for seg across (segments logical-line) do
             (when point-screen-line
               (incf lines-since-point))
             #+(or)(format t "Line ~S ~S  ~S ~S ~S~%"
                     (point-line *editor*) line
                     (line-start seg) (point-offset *editor*) (line-end seg))
             (when (and (eql (point-line *editor*) line)
                        (<= (line-start seg) (point-offset *editor*) (line-end seg)))
               ;; This screen line contains the point.
               (setf point-screen-line (length screen)))
             (vector-push-extend seg screen)))))
  
  (defun put-line (seg y window-top point-screen-line)
    (let* ((data (data (physical-line seg)))
           (point-at-endp (eql (point-offset *editor*) (line-length (point-line *editor*)))))
      (cond
        ((not (eql (+ window-top y) point-screen-line))
         (put-string data 0 y (line-start seg) (line-end seg)))
        ;; Point is on this line. Highlight it.
        ;; This does't work too well if the point is at the end of both a physical & a virtual line.
        ;; Adding a right margin with wrap indicator would provide a place for the point to sit.
        (point-at-endp
         (let ((pen 0))
           (setf pen (put-string data pen y (line-start seg) (line-end seg)))
           (setf pen (put-char #\Space pen y :invert t))))
        (t
         (let ((pen 0))
           (setf pen (put-string data pen y (line-start seg) (point-offset *editor*)))
           (setf pen (put-char (aref data (point-offset *editor*)) pen y :invert t))
           (setf pen (put-string data pen y (1+ (point-offset *editor*)) (line-end seg))))))))
  
  (defun incremental-redisplay ()
    (multiple-value-bind (left right top bottom)
        (mezzanine.gui.widgets:frame-size (frame *editor*))
      (let* ((top-line (point-line *editor*))
             (current-screen (current-screen *editor*))
             (full-redisplayp (not current-screen))
             (win-width (- (mezzanine.gui.compositor:width (window *editor*)) left right))
             (line-height (mezzanine.gui.font:line-height (font *editor*))))
        ;; Starting from point, count back a bunch of physical lines.
        (dotimes (i (window-rows))
          (when (not (prev top-line))
            (return))
          (setf top-line (prev top-line)))
        ;; Rebuild the screen array.
        (multiple-value-bind (screen point-screen-line)
            (build-screen-line-list current-screen top-line win-width)
          #+(or)(format t "Incr Screen layout: ~S~%" screen)
          #+(or)(format t "Incr Point is ~S ~S~%" (point-line *editor*) (point-offset *editor*))
          #+(or)(format t "Incr Point screen line is ~S ~S~%" point-screen-line (aref screen point-screen-line))
          #+(or)(format t "Incr Previous top of window is ~S~%" (window-top-line *editor*))
          ;; Find the new top screen line, based on the current top screen line.
          (let ((window-top (when (window-top-line *editor*)
                              (position-if (lambda (x) (or (eql x (window-top-line *editor*))
                                                           (and (eql (physical-line x) (physical-line (window-top-line *editor*)))
                                                                (eql (line-start x) (line-start (window-top-line *editor*)))
                                                                (eql (line-end x) (line-end (window-top-line *editor*))))))
                                           screen))))
            ;; If the point is above (lt) the old window top, or below (gte) the window bottom, then recenter.
            (when (or (not window-top)
                      (< point-screen-line window-top)
                      (>= point-screen-line (+ window-top (window-rows))))
              (setf window-top (max 0 (- point-screen-line (truncate (window-rows) 2)))))
            #+(or)(format t "Incr Window top is ~S~%" window-top)
            (when full-redisplayp
              ;; Actually a full redisplay, clear the whole screen.
              (mezzanine.gui:bitset (- (mezzanine.gui.compositor:height (window *editor*)) top bottom)
                                    win-width
                                    (background-colour *editor*)
                                    (mezzanine.gui.compositor:window-buffer (window *editor*))
                                    top left))
            ;; Walk the screen line array, copying lines when possible or redrawing them when not.
            (dotimes (y (window-rows))
              (check-pending-input)
              (when (>= (+ window-top y) (length screen))
                (return))
              (let* ((seg (aref screen (+ window-top y)))
                     (position (when (not full-redisplayp)
                                 (position seg
                                           current-screen
                                           :start (window-top *editor*)
                                           :end (min (+ (window-top *editor*) (window-rows))
                                                     (length current-screen))))))
                (cond ((or full-redisplayp
                           (eql y (- point-screen-line window-top))
                           (eql y (current-point-logical-line *editor*))
                           (not position))
                       (when (not full-redisplayp)
                         (mezzanine.gui:bitset line-height win-width
                                               (background-colour *editor*)
                                               (mezzanine.gui.compositor:window-buffer (window *editor*))
                                               (+ top (* y line-height)) left))
                       (put-line seg y window-top point-screen-line)
                       (when (not full-redisplayp)
                         (mezzanine.gui.compositor:damage-window (window *editor*)
                                                                 left (+ top (* y line-height))
                                                                 win-width line-height)
                         (when (< (+ (window-top *editor*) y) (length current-screen))
                           (setf (aref current-screen (+ (window-top *editor*) y)) seg))))
                      ((not (eql y (- position (window-top *editor*))))
                       #+(or)(format t "Copy old line ~S ~S to new line ~S ~S.~%" position (* (- position (window-top *editor*)) line-height) y (* y line-height))
                       (mezzanine.gui:bitblt line-height win-width
                                             (mezzanine.gui.compositor:window-buffer (window *editor*))
                                             (+ top (* (- position (window-top *editor*)) line-height)) left
                                             (mezzanine.gui.compositor:window-buffer (window *editor*))
                                             (+ top (* y line-height)) left)
                       (mezzanine.gui.compositor:damage-window (window *editor*)
                                                               left (+ top (* y line-height))
                                                               win-width line-height)
                       (when (< (+ (window-top *editor*) y) (length current-screen))
                         (setf (aref current-screen (+ (window-top *editor*) y)) seg)))
                      (t #+(or)(format t "Keep old line ~S ~S~%" position y)))))
            ;; If the new screen is shorter than the old screen, then fill
            ;; any newly nonexistent screen lines.
            (when (and (not full-redisplayp)
                       (> (- (length current-screen) (window-top *editor*))
                          (- (length screen) window-top)))
              (mezzanine.gui:bitset (* (- (- (length current-screen) (window-top *editor*))
                                          (- (length screen) window-top))
                                       line-height)
                                    win-width
                                    (background-colour *editor*)
                                    (mezzanine.gui.compositor:window-buffer (window *editor*))
                                    (+ top (* (- (length screen) window-top) line-height)) left)
              (mezzanine.gui.compositor:damage-window (window *editor*)
                                                      left
                                                      (+ top (* (- (length screen) window-top) line-height))
                                                      win-width
                                                      (* (- (- (length current-screen) (window-top *editor*))
                                                            (- (length screen) window-top))
                                                         line-height)))
            (when full-redisplayp
              (mezzanine.gui.compositor:damage-window (window *editor*)
                                                      left top
                                                      win-width
                                                      (- (mezzanine.gui.compositor:height (window *editor*)) top bottom)))
            (setf (current-screen *editor*) screen
                  (window-top-line *editor*) (aref screen window-top)
                  (window-top *editor*) window-top
                  (current-point-logical-line *editor*) (- point-screen-line window-top)))))))
  
  (defun redraw-screen ()
    (setf (current-screen *editor*) nil
          (window-top-line *editor*) nil))
  
  (defun redisplay ()
    (handler-case
        (progn
          (check-pending-input)
          (incremental-redisplay)
          t)
      (pending-input ()
        nil)))
  
  (defun editor-loop ()
    (loop
       (handler-case
           (let ((ch (editor-read-char)))
             (case ch
               ((nil)) ; Happens when there's a redisplay pending.
               (#\Newline
                (insert-line))
               (#\C-F (forward-char))
               (#\C-B (backward-char))
               (#\C-N (next-line))
               (#\C-P (previous-line))
               (#\C-A (move-beginning-of-line))
               (#\C-E (move-end-of-line))
               (#\C-K (kill-line))
               (#\C-Q (insert-char (editor-read-char)))
               (#\C-L (redraw-screen))
               (#\Backspace (delete-backward-char))
               (#\Delete (delete-forward-char))
               (t (cond ((find ch "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789!\"£$%^&*()_+-=[]{};'#:@~,./<>?`~|\\"
                               :test #'char=)
                         (insert-char ch)))))
             (setf (pending-redisplay *editor*) (not (redisplay))))
         (error (c)
           (ignore-errors
  
negative.code:   (when (not (mezzanine.gui.compositor:key-releasep event))
      (throw 'next-character
        (if (mezzanine.gui.compositor:key-modifier-state event)
            ;; Force character to uppercase when a modifier key is active, gets
            ;; around weirdness in how character names are processed.
            ;; #\C-a and #\C-A both parse as the same character (C-LATIN_CAPITAL_LETTER_A).
            (sys.int::make-character (char-code (char-upcase (mezzanine.gui.compositor:key-key event)))
                                     :control (find :control (mezzanine.gui.compositor:key-modifier-state event))
                                     :meta (find :meta (mezzanine.gui.compositor:key-modifier-state event))
  