anchor.diff:          (let ((offset (offset mark)))
             (end-of-line mark)
             (delete-region offset mark)))))
  +
  +(defgeneric extract-line (mark &key from-end whole-line as-string)
  +  (:documentation "Destructively remove part of a line and return
  +it. The line `mark' is in indicates which line to perform the
  +extraction on. The line contents from the beginning of the line
  +up to `mark' will be deleted and returned as a vector. If
  +`from-end' is true, the line contents from the end of the line to
  +`mark' will be affected instead. If `whole-line' is true, the
  +entire line, including any single ending newline character, will
  +be deleted and returned."))
  +
  +(defun extract-whole-line (mark)
  +  "Extract the whole line `mark' is in, and remove any single
  +  trailing newline."
  +  (let* ((border-mark (clone-mark mark))
  +         eol-offset)
  +    (end-of-line border-mark)
  +    (setf eol-offset (offset border-mark))
  +    (unless (end-of-buffer-p border-mark)
  +      (incf eol-offset))
  +    (beginning-of-line border-mark)
  +    (let ((sequence (region-to-sequence border-mark eol-offset)))
  +      (delete-region border-mark eol-offset)
  +      sequence)))
  +
  +(defmethod extract-line ((mark mark) &key from-end whole-line)
  +  (if whole-line
  +      (extract-whole-line mark)
  +      (let ((border-mark (clone-mark mark)))
  +        (if from-end
  +            (end-of-line border-mark)
  +            (beginning-of-line border-mark))
  +        (as-region (mark border-mark)
  +          (let ((sequence (region-to-sequence mark border-mark)))
  +            (delete-region mark border-mark)
  +            sequence)))))
  +
  +(defgeneric lines-in-region (mark1 mark2)
  +  (:documentation "Return a list of all the lines (not including
  +  newline characters) in the full region delimited by `mark1' and
  +  `mark2'."))
  +
  +(defmethod lines-in-region (mark1 mark2)
  +  (as-full-region (mark1 mark2)
  +    (let (result)
  +      (do-buffer-region-lines (line-mark mark1 mark2)
  +        (let ((bol-offset (offset line-mark)))
  +          (end-of-line line-mark)
  +          (push (region-to-sequence bol-offset line-mark) result)))
  +      result)))
  +
  +(defgeneric extract-lines-in-region (mark1 mark2)
  +  (:documentation "Delete the lines of the full region delimited
  +by `mark1' and `mark2'"))
  +
  +(defmethod extract-lines-in-region ((mark1 mark) (mark2 mark))
  +  (as-full-region (mark1 mark2)
  +    (let ((lines (lines-in-region mark1 mark2)))
  +      (delete-region mark1 mark2)
  +      lines)))
   
   (defun empty-line-p (mark)
     "Check whether the mark is in an empty line."
  
positive.code: ;;; not, strictly speaking, part of that protocol.
  
  (in-package :drei-base)
  
  (defmacro as-offsets ((&rest marks)
                        &body body)
  
negative.code:     `(progn
         (let* ((,mark-sym (clone-mark ,mark1))
                (,mark2-sym (clone-mark ,mark2)))
           (as-region (,mark-sym ,mark2-sym)
             (loop while (and (mark<= ,mark-sym ,mark2-sym)
                              (not (end-of-buffer-p ,mark-sym)))
                do              
                (let ((,line-var (clone-mark ,mark-sym)))
                  ,@body)
                (end-of-line ,mark-sym)
                (unless (end-of-buffer-p ,mark-sym)
                  (forward-object ,mark-sym))))))))
  
  (defgeneric previous-line (mark &optional column count)
    (:documentation "Move a mark up `count' lines conserving
  