Update of /project/mcclim/cvsroot/mcclim/Drei In directory clnet:/tmp/cvs-serv23671
Modified Files: base.lisp Log Message: Add more convenience features: `as-region', `as-full-region', `extract-line', `lines-in-region', `extract-lines-in-region'.
--- /project/mcclim/cvsroot/mcclim/Drei/base.lisp 2006/11/08 01:15:33 1.1 +++ /project/mcclim/cvsroot/mcclim/Drei/base.lisp 2006/11/14 07:58:37 1.2 @@ -32,6 +32,45 @@
(in-package :drei-base)
+(defgeneric invoke-as-region (mark1 mark2 continuation) + (:documentation "Invoke `continuation' with two arguments +ordering a proper region.")) + +(defmethod invoke-as-region ((mark1 integer) (mark2 integer) + (continuation function)) + (if (>= mark2 mark1) + (funcall continuation mark1 mark2) + (funcall continuation mark2 mark1))) + +(defmethod invoke-as-region ((mark1 mark) (mark2 mark) + (continuation function)) + (if (mark>= mark2 mark1) + (funcall continuation mark1 mark2) + (funcall continuation mark2 mark1))) + +(defmacro as-region ((mark1 mark2) &body body) + "Rebind `mark1' and `mark2' to be a proper region. That +is, `(mark>= mark2 mark1)' will hold. `Mark1' and `mark2' must be +symbols bound to marks or integers (but they must be of the same +type). It is a good idea to use this macro when dealing with +regions." + `(invoke-as-region ,mark1 ,mark2 + #'(lambda (,mark1 ,mark2) + ,@body))) + +(defmacro as-full-region ((mark1 mark2) &body body) + "Bind `mark1' and `mark2' to marks that delimit a full + region (a region where the beginning and end are at the + beginning and end of their lines, respectively). The new marks + will be copies of the marks `mark1' and `mark2' are already + bound to. `Mark1' and `mark2' must be symbols bound to marks." + `(as-region (,mark1 ,mark2) + (let ((,mark1 (clone-mark ,mark1)) + (,mark2 (clone-mark ,mark2))) + (beginning-of-line ,mark1) + (end-of-line ,mark2) + ,@body))) + (defmacro as-offsets ((&rest marks) &body body) "Bind the symbols in `marks' to the numeric offsets of the mark @@ -75,16 +114,15 @@ `(progn (let* ((,mark-sym (clone-mark ,mark1)) (,mark2-sym (clone-mark ,mark2))) - (when (mark< ,mark2-sym ,mark-sym) - (rotatef ,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))))))) + (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 @@ -161,6 +199,66 @@ (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." (and (beginning-of-line-p mark) (end-of-line-p mark))) @@ -212,21 +310,18 @@ (assert (eq (buffer mark1) (buffer mark2))) (let ((offset1 (offset mark1)) (offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (buffer-number-of-lines-in-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (buffer-number-of-lines-in-region (buffer mark1) offset1 offset2))))
(defmethod number-of-lines-in-region ((offset1 integer) (mark2 mark)) (let ((offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (buffer-number-of-lines-in-region (buffer mark2) offset1 offset2))) + (as-region (offset1 offset2) + (buffer-number-of-lines-in-region (buffer mark2) offset1 offset2))))
(defmethod number-of-lines-in-region ((mark1 mark) (offset2 integer)) (let ((offset1 (offset mark1))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (buffer-number-of-lines-in-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (buffer-number-of-lines-in-region (buffer mark1) offset1 offset2))))
(defun constituentp (obj) "A predicate to ensure that an object is a constituent character." @@ -506,21 +601,18 @@ (assert (eq (buffer mark1) (buffer mark2))) (let ((offset1 (offset mark1)) (offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (downcase-buffer-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (downcase-buffer-region (buffer mark1) offset1 offset2))))
(defmethod downcase-region ((offset1 integer) (mark2 mark)) (let ((offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (downcase-buffer-region (buffer mark2) offset1 offset2))) + (as-region (offset1 offset2) + (downcase-buffer-region (buffer mark2) offset1 offset2))))
(defmethod downcase-region ((mark1 mark) (offset2 integer)) (let ((offset1 (offset mark1))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (downcase-buffer-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (downcase-buffer-region (buffer mark1) offset1 offset2))))
(defun upcase-buffer-region (buffer offset1 offset2) (do-buffer-region (object offset buffer offset1 offset2) @@ -536,21 +628,18 @@ (assert (eq (buffer mark1) (buffer mark2))) (let ((offset1 (offset mark1)) (offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (upcase-buffer-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (upcase-buffer-region (buffer mark1) offset1 offset2))))
(defmethod upcase-region ((offset1 integer) (mark2 mark)) (let ((offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (upcase-buffer-region (buffer mark2) offset1 offset2))) + (as-region (offset1 offset2) + (upcase-buffer-region (buffer mark2) offset1 offset2))))
(defmethod upcase-region ((mark1 mark) (offset2 integer)) (let ((offset1 (offset mark1))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (upcase-buffer-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (upcase-buffer-region (buffer mark1) offset1 offset2))))
(defun capitalize-buffer-region (buffer offset1 offset2) (let ((previous-char-constituent-p nil)) @@ -572,21 +661,18 @@ (assert (eq (buffer mark1) (buffer mark2))) (let ((offset1 (offset mark1)) (offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (capitalize-buffer-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (capitalize-buffer-region (buffer mark1) offset1 offset2))))
(defmethod capitalize-region ((offset1 integer) (mark2 mark)) (let ((offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (capitalize-buffer-region (buffer mark2) offset1 offset2))) + (as-region (offset1 offset2) + (capitalize-buffer-region (buffer mark2) offset1 offset2))))
(defmethod capitalize-region ((mark1 mark) (offset2 integer)) (let ((offset1 (offset mark1))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (capitalize-buffer-region (buffer mark1) offset1 offset2))) + (as-region (offset1 offset2) + (capitalize-buffer-region (buffer mark1) offset1 offset2))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; @@ -618,21 +704,18 @@ (assert (eq (buffer mark1) (buffer mark2))) (let ((offset1 (offset mark1)) (offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (tabify-buffer-region (buffer mark1) offset1 offset2 tab-width))) + (as-region (offset1 offset2) + (tabify-buffer-region (buffer mark1) offset1 offset2 tab-width))))
(defmethod tabify-region ((offset1 integer) (mark2 mark) tab-width) (let ((offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (tabify-buffer-region (buffer mark2) offset1 offset2 tab-width))) + (as-region (offset1 offset2) + (tabify-buffer-region (buffer mark2) offset1 offset2 tab-width))))
(defmethod tabify-region ((mark1 mark) (offset2 integer) tab-width) (let ((offset1 (offset mark1))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (tabify-buffer-region (buffer mark1) offset1 offset2 tab-width))) + (as-region (offset1 offset2) + (tabify-buffer-region (buffer mark1) offset1 offset2 tab-width))))
(defun untabify-buffer-region (buffer offset1 offset2 tab-width) (loop for offset = offset1 then (1+ offset) @@ -656,21 +739,18 @@ (assert (eq (buffer mark1) (buffer mark2))) (let ((offset1 (offset mark1)) (offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (untabify-buffer-region (buffer mark1) offset1 offset2 tab-width))) + (as-region (offset1 offset2) + (untabify-buffer-region (buffer mark1) offset1 offset2 tab-width))))
(defmethod untabify-region ((offset1 integer) (mark2 mark) tab-width) (let ((offset2 (offset mark2))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (untabify-buffer-region (buffer mark2) offset1 offset2 tab-width))) + (as-region (offset1 offset2) + (untabify-buffer-region (buffer mark2) offset1 offset2 tab-width))))
(defmethod untabify-region ((mark1 mark) (offset2 integer) tab-width) (let ((offset1 (offset mark1))) - (when (> offset1 offset2) - (rotatef offset1 offset2)) - (untabify-buffer-region (buffer mark1) offset1 offset2 tab-width))) + (as-region (offset1 offset2) + (untabify-buffer-region (buffer mark1) offset1 offset2 tab-width))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;