anchor.diff:                                       :title "Editor"
                                        :close-button-p t
                                        :damage-function (mezzanine.gui.widgets:default-damage-function window)))
  -               (line (make-instance 'line))
                  (*editor* (make-instance 'editor
                                           :fifo fifo
  -                                        :pending-redisplay t
                                           :font font
                                           :window window
                                           :frame frame
  -                                        :first-line line
  -                                        :last-line line
  -                                        :point-line line
  -                                        :point-offset 0
  -                                        :point-column-hint 0
  -                                        :window-top-line nil
  -                                        :window-top 0
  -                                        :current-screen nil
  -                                        :current-point-logical-line nil)))
  +                                        :buffer (make-instance 'buffer))))
             (mezzanine.gui.widgets:draw-frame frame)
             (catch 'quit
               (editor-loop)))))))
  
positive.code: 
  (in-package :mezzanine.editor)
  
  (defclass line ()
    ((%next :initarg :next :accessor next)
     (%prev :initarg :prev :accessor prev)
     (%data :initarg :data :accessor data)
     (%version :initarg :version :accessor version))
    (:default-initargs :next nil
                       :prev nil
                       :data (make-array 50 :element-type 'character :adjustable t :fill-pointer 0)
                       :version 0))
  
  (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)
     (%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))
    (:default-initargs :pending-event nil
                       :pending-redisplay nil
                       :csr-x 0 :csr-y 0 :csr-char #\Space
                       :foreground-colour #xFFDCDCCC
                       :background-colour #xFF3E3E3E))
  
  (defvar *editor*)
  
  
negative.code:     (truncate (- (mezzanine.gui.compositor:height (window *editor*)) top bottom)
                (mezzanine.gui.font:line-height (font *editor*)))))
  
  (defun flush-display-line (mark)
    "Flush the display line containing MARK."
    (setf (display-line-cache *editor*)
          (remove-if (lambda (line)
                       ;; Munch the entire line.
                       (eql (display-line-line line) (mark-line mark)))
                     (display-line-cache *editor*))))
  
  (defun flush-display-lines-in-region (mark-1 mark-2)
    "Flush display lines containing the region specified by MARK-1 and MARK-2."
    (let ((first (min (line-number (mark-line mark-1))
                      (line-number (mark-line mark-2))))
          (last (max (line-number (mark-line mark-1))
                     (line-number (mark-line mark-2)))))
      (setf (display-line-cache *editor*)
            (remove-if (lambda (line)
                         (<= first (line-number (display-line-line line)) last))
                       (display-line-cache *editor*)))))
  
  (defun flush-stale-lines ()
    "Flush any display lines with the wrong version."
    (setf (display-line-cache *editor*)
          (remove-if (lambda (line)
                       (not (eql (display-line-version line)
                                 (line-version (display-line-line line)))))
                     (display-line-cache *editor*))))
  
  (defun editor-width ()
    "Return the width of the display area in pixels."
    (multiple-value-bind (left right top bottom)
        (mezzanine.gui.widgets:frame-size (frame *editor*))
      (- (mezzanine.gui.compositor:width (window *editor*)) left right)))
  
  (defun region-bounds (mark-1 mark-2)
    "Return a bunch of boundary information for the region."
    (cond ((eql (mark-line mark-1) (mark-line mark-2))
           ;; Same line.
           (when (> (mark-charpos mark-1) (mark-charpos mark-2))
             (rotatef mark-1 mark-2))
           (values (mark-line mark-1) (mark-charpos mark-1) nil
                   (mark-line mark-2) (mark-charpos mark-2) nil))
          (t ;; 2 or more lines.
           (when (> (line-number (mark-line mark-1)) (line-number (mark-line mark-2)))
             (rotatef mark-1 mark-2))
           (values (mark-line mark-1) (mark-charpos mark-1) (line-number (mark-line mark-1))
                   (mark-line mark-2) (mark-charpos mark-2) (line-number (mark-line mark-2))))))
  
  (defun render-display-line-2 (line start)
    (multiple-value-bind (line-1 line-1-charpos line-1-number line-2 line-2-charpos line-2-number)
        (region-bounds (buffer-point (current-buffer *editor*)) (buffer-mark (current-buffer *editor*)))
      (loop
         with pen = 0
         with font = (font *editor*)
         with baseline = (mezzanine.gui.font:ascender font)
         with foreground = (foreground-colour *editor*)
         with background = (background-colour *editor*)
         with line-height = (mezzanine.gui.font:line-height font)
         with win-width = (editor-width)
         with point = (buffer-point (current-buffer *editor*))
         with mark-active = (buffer-mark-active (current-buffer *editor*))
         with buffer = (make-array (list line-height win-width)
                                   :element-type '(unsigned-byte 32)
                                   :initial-element background)
         for ch-position from start below (line-length line)
         for glyph = (mezzanine.gui.font:character-to-glyph font (line-character line ch-position))
         for mask = (mezzanine.gui.font:glyph-mask glyph)
         for advance = (mezzanine.gui.font:glyph-advance glyph)
         do
           (when (> (+ pen advance) win-width)
             (return (values buffer ch-position)))
           (let ((at-point (and (eql line (mark-line point))
                                (eql ch-position (mark-charpos point))))
                 (in-region (and mark-active
                                 (or (if line-1-number
                                         (or (< line-1-number (line-number line) line-2-number)
                                             (and (eql line line-1)
                                                  (<= line-1-charpos ch-position))
                                             (and (eql line line-2)
                                                  (< ch-position line-2-charpos)))
                                         (and (eql line line-1)
                                              (<= line-1-charpos ch-position)
                                              (< ch-position line-2-charpos)))))))
             ;; Invert the point.
             (when at-point
               (mezzanine.gui:bitset line-height advance
                                     foreground
                                     buffer 0 pen))
             (mezzanine.gui:bitset-argb-xrgb-mask-8 (array-dimension mask 0) (array-dimension mask 1)
                                                    (if at-point
                                                        background
                                                        foreground)
                                                    mask 0 0
                                                    buffer
                                                    (- baseline (mezzanine.gui.font:glyph-yoff glyph))
                                                    (+ pen (mezzanine.gui.font:glyph-xoff glyph)))
             ;; Underline the region.
             (when in-region
               (mezzanine.gui:bitset-argb-xrgb 1 advance
                                               (if at-point
                                                   background
                                                   foreground)
                                               buffer baseline pen))
             (incf pen advance))
         finally
         ;; Reached end of line, check for the point.
           (when (and (eql line (mark-line point))
                      (eql ch-position (mark-charpos point)))
             ;; Point is here, render it past the last character.
             (let* ((glyph (mezzanine.gui.font:character-to-glyph font #\Space))
                    (advance (mezzanine.gui.font:glyph-advance glyph)))
               (when (<= (+ pen advance) win-width) ; FIXME, how to display point at end of line & display line properly. also fix blit crash bug.
                 (mezzanine.gui:bitset line-height advance
                                       foreground
                                       buffer 0 pen))))
         ;; TODO: Render underline to end of line region spans whole line.
           (return (values buffer ch-position)))))
  
  (defun render-display-line-1 (line start)
    (multiple-value-bind (buffer end)
        (render-display-line-2 line start)
      (let ((display-line (make-instance 'display-line
                                         :line line
                                         :version (line-version line)
                                         :start start
                                         :end end
                                         :representation buffer)))
        (push display-line (display-line-cache *editor*))
        display-line)))
  
  (defun render-display-line (line fn)
    "Render display lines for real line LINE, calling FN with each display line."
    (cond ((zerop (line-length line))
           (funcall fn (or (get-display-line-from-cache line 0)
                           (render-display-line-1 line 0))))
          (t (do ((start 0))
                 ((>= start (line-length line)))
               (let ((display-line (or (get-display-line-from-cache line start)
                                       (render-display-line-1 line start))))
                 (funcall fn display-line)
                 (setf start (display-line-end display-line)))))))
  
  (defun get-display-line-from-cache (line start)
    (dolist (display-line (display-line-cache *editor*))
      (when (and (eql (display-line-line display-line) line)
                 (eql (display-line-start display-line) start))
        ;; MRU cache.
        (setf (display-line-cache *editor*) (remove display-line (display-line-cache *editor*)))
        (push display-line (display-line-cache *editor*))
        (return display-line))))
  
  (defun blit-display-line (line y)
    (multiple-value-bind (left right top bottom)
        (mezzanine.gui.widgets:frame-size (frame *editor*))
      (let* ((fb (mezzanine.gui.compositor:window-buffer (window *editor*)))
             (line-height (mezzanine.gui.font:line-height (font *editor*)))
             (real-y (+ top (* y line-height)))
             (win-width (editor-width)))
        (if line
            ;; Blitting line.
            (mezzanine.gui:bitblt line-height win-width
                                  (display-line-representation line)
                                  0 0
                                  fb
                                  real-y left)
            ;; Line is empty.
            (mezzanine.gui:bitset line-height win-width
                                  (background-colour *editor*)
                                  fb
                                  real-y left))
        (mezzanine.gui.compositor:damage-window (window *editor*)
                                                left real-y
                                                win-width line-height))))
  
  (defun recenter (buffer)
    "Move BUFFER's top line so that the point is displayed."
    (let* ((point (buffer-point buffer))
           (top-line (mark-line point))
           (rendered-lines (make-array (ceiling (window-rows) 2) :fill-pointer 0 :adjustable t))
           (point-display-line nil))
      ;; Move (window-rows)/2 lines up from point.
      (dotimes (i (ceiling (window-rows) 2))
        (when (not (previous-line top-line))
          (return))
        (setf top-line (previous-line top-line)))
      ;; Render display lines until point is reached.
      (do ((line top-line (next-line line)))
          ;; Should always top when the point's line has been reached.
          ()
        (render-display-line line
                             (lambda (display-line)
                               (vector-push-extend display-line rendered-lines)
                               (when (and (eql (mark-line point) (display-line-line display-line))
                                          (<= (display-line-start display-line) (mark-charpos point))
                                          (or (and (eql (display-line-end display-line) (line-length (display-line-line display-line)))
                                                   (eql (display-line-end display-line) (mark-charpos point)))
                                              (< (mark-charpos point) (display-line-end display-line))))
                                 ;; This is point line, stop here.
                                 (setf point-display-line (1- (length rendered-lines)))
                                 (return)))))
      ;; Walk (window-rows)/2 display lines backwards from point. This is the new top-line.
      (let ((new-top-line (aref rendered-lines (max 0 (- point-display-line (truncate (window-rows) 2)))))
            (top-line-mark (buffer-property buffer 'pane-top-line)))
        (setf (mark-line top-line-mark) (display-line-line new-top-line))
              (mark-charpos top-line-mark) (display-line-start new-top-line))))
  
  (defun redisplay ()
    "Perform an incremental redisplay cycle.
  Returns true when the screen is up-to-date, false if the screen is dirty and there is pending input."
    (handler-case
        (progn
          (when (not (eql (length (editor-current-screen *editor*)) (window-rows)))
            (setf (editor-current-screen *editor*) (make-array (window-rows) :initial-element t)))
          (check-pending-input)
          (let* ((buffer (current-buffer *editor*))
                 (current-screen (editor-current-screen *editor*))
                 (new-screen (make-array (window-rows) :fill-pointer 0 :initial-element nil))
                 (point-line nil)
                 (top-line (pane-top-line buffer))
                 (point (buffer-point buffer))
                 (previous-point-position (buffer-property buffer 'pane-previous-point-position))
                 (mark (buffer-mark buffer))
                 (previous-mark-position (buffer-property buffer 'pane-previous-mark-position)))
            (when (not previous-point-position)
              (setf previous-point-position (copy-mark point :right)
                    (buffer-property buffer 'pane-previous-point-position) previous-point-position))
            (when (not previous-mark-position)
              (setf previous-mark-position (copy-mark mark :left)
                    (buffer-property buffer 'pane-previous-mark-position) previous-mark-position))
            ;; If the point has moved, then invalidate the line that contained the point and the line that
            ;; now holds the point.
            #+(or)(format t "Point: ~S  prev point: ~S  equal: ~S~%"
                    point previous-point-position
                    (mark-equal-p point previous-point-position))
            (when (not (mark-equal-p point previous-point-position))
              (flush-display-line previous-point-position)
              (flush-display-line point))
            ;; If the mark changes state, flush lines within the region.
            (when (or (and (not (buffer-mark-active buffer))
                           (buffer-property buffer 'pane-mark-was-active))
                      (and (buffer-mark-active buffer)
                           (not (buffer-property buffer 'pane-mark-was-active))))
              (flush-display-lines-in-region point mark))
            ;; If the mark is active and the point moves, flush lines between the old point position
            ;; and the new position.
            ;; FIXME: This will cause a bunch of lines to be redrawn when the point & mark are exchanged.
            (when (and (buffer-mark-active buffer)
                       (not (mark-equal-p point previous-point-position)))
              (flush-display-lines-in-region point previous-point-position))
            ;; If the mark is or was active and moves, flush lines between the old mark position
            ;; and the new position.
            ;; FIXME: This will cause a bunch of lines to be redrawn when the point & mark are exchanged.
            (when (and (or (buffer-mark-active buffer)
                           (buffer-property buffer 'pane-mark-was-active))
                       (not (mark-equal-p mark previous-mark-position)))
              (format t "Mark moved from ~S to ~S~%" previous-mark-position mark)
              (flush-display-lines-in-region mark previous-mark-position))
            ;; Finally, flush any stale lines.
            (flush-stale-lines)
            ;; Update tracking properties.
            (setf (buffer-property buffer 'pane-mark-was-active) (buffer-mark-active buffer))
            (move-mark-to-mark previous-point-position point)
            (move-mark-to-mark previous-mark-position mark)
            ;; Generate WINDOW-ROWS display lines, starting at TOP-LINE.
            ;; TODO: Don't start from the beginning of the top-line, use the charpos instead.
            (setf (mark-charpos top-line) 0)
            ;(format t "Top line ~S ~S~%" top-line (mark-line top-line))
            (do ((line (mark-line top-line) (next-line line)))
                ;; Stop when there are no more lines or the screen has been filled up.
                ((null line))
              (render-display-line line
                                   (lambda (display-line)
                                     (check-pending-input)
                                     (vector-push display-line new-screen)
                                     (when (and (eql (mark-line point) (display-line-line display-line))
                                                (<= (display-line-start display-line) (mark-charpos point))
                                                (or (and (eql (display-line-end display-line) (line-length (display-line-line display-line)))
                                                         (eql (display-line-end display-line) (mark-charpos point)))
                                                    (< (mark-charpos point) (display-line-end display-line))))
                                       (setf point-line display-line))
                                     (when (eql (fill-pointer new-screen) (window-rows))
                                       (return)))))
            (setf (fill-pointer new-screen) (window-rows))
            ;; If the point is not within the screen bounds, then recenter and retry.
            (when (not point-line)
              (recenter buffer)
              (return-from redisplay nil))
            ;(format t "New screen is ~S~%" new-screen)
            ;; Compare against the current screen, blitting when needed.
            (dotimes (y (window-rows))
              (let ((line (aref new-screen y)))
                (unless (eql (aref current-screen y) line)
                  ;(format t "Update line ~D. Old ~S new ~S.~%" y (aref current-screen y) line)
                  (blit-display-line line y)
                  (setf (aref current-screen y) line)
                  (check-pending-input))))
            ;; Prune the cache.
            (setf (display-line-cache *editor*) (subseq (display-line-cache *editor*) 0 (* (window-rows) 4)))
            #+(or)(format t "Line cache: ~S~%" (display-line-cache *editor*)))
          t)
      (pending-input ()
        nil)))
  
  (defun vomit-buffer (buffer)
    (do ((line (first-line buffer) (next-line line)))
        ((not line))
      (format t "~S ~S~%" line (data line))))
  
  (defun editor-loop ()
    (loop
       (handler-case
           (let ((ch (editor-read-char))
                 (buffer (current-buffer *editor*)))
             (case ch
               ((nil)) ; Happens when there's a redisplay pending.
               (#\Newline (insert-line buffer))
               (#\C-F (forward-char buffer))
               (#\C-B (backward-char buffer))
               (#\C-N (forward-line buffer))
               (#\C-P (backward-line buffer))
               (#\C-A (move-beginning-of-line buffer))
               (#\C-E (move-end-of-line buffer))
               (#\C-K (kill-line buffer))
               (#\C-Q (insert-char buffer (editor-read-char)))
               (#\C-L (recenter buffer))
               (#\M-L (redraw-screen))
               (#\C-Space (set-mark buffer))
               (#\C-X (exchange-point-and-mark buffer))
               (#\Backspace (delete-backward-char buffer))
               (#\C-D (delete-forward-char buffer))
               (#\Delete (delete-forward-char buffer))
               (#\C-V (vomit-buffer buffer))
               (#\C-T (test-fill buffer))
               (t (cond ((find ch "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789!\"£$%^&*()_+-=[]{};'#:@~,./<>?`~|\\"
                               :test #'char=)
                         (insert-char buffer ch)))))
             (format t "Point at ~S  mark at ~S  active:~S~%"
                     (buffer-point buffer) (buffer-mark buffer)
                     (buffer-mark-active buffer))
             (setf (pending-redisplay *editor*) (not (redisplay))))
         (error (c)
           (ignore-errors
  