| 1 | ;;; -*- Log: hemlock.log; Package: Hemlock-Internals -*-
|
|---|
| 2 | ;;;
|
|---|
| 3 | ;;; **********************************************************************
|
|---|
| 4 | ;;; This code was written as part of the CMU Common Lisp project at
|
|---|
| 5 | ;;; Carnegie Mellon University, and has been placed in the public domain.
|
|---|
| 6 | ;;;
|
|---|
| 7 | #+CMU (ext:file-comment
|
|---|
| 8 | "$Header$")
|
|---|
| 9 | ;;;
|
|---|
| 10 | ;;; **********************************************************************
|
|---|
| 11 | ;;;
|
|---|
| 12 | ;;; More Hemlock Text-Manipulation functions.
|
|---|
| 13 | ;;; Written by Skef Wholey.
|
|---|
| 14 | ;;;
|
|---|
| 15 | ;;; The code in this file implements the non-insert/delete functions in the
|
|---|
| 16 | ;;; "Doing Stuff and Going Places" chapter of the Hemlock Design document.
|
|---|
| 17 | ;;;
|
|---|
| 18 |
|
|---|
| 19 | (in-package :hemlock-internals)
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 | |
|---|
| 25 |
|
|---|
| 26 | (defun region-to-string (region &optional output-string)
|
|---|
| 27 | "Returns a string containing the characters in the given Region."
|
|---|
| 28 | (close-line)
|
|---|
| 29 | (let* ((dst-length (count-characters region))
|
|---|
| 30 | (string (if (and output-string
|
|---|
| 31 | (<= dst-length (length output-string)))
|
|---|
| 32 | output-string
|
|---|
| 33 | (make-string dst-length)))
|
|---|
| 34 | (start-mark (region-start region))
|
|---|
| 35 | (end-mark (region-end region))
|
|---|
| 36 | (start-line (mark-line start-mark))
|
|---|
| 37 | (end-line (mark-line end-mark))
|
|---|
| 38 | (start-charpos (mark-charpos start-mark)))
|
|---|
| 39 | (declare (simple-string string))
|
|---|
| 40 | (if (eq start-line end-line)
|
|---|
| 41 | (%sp-byte-blt (line-chars start-line) start-charpos string 0
|
|---|
| 42 | dst-length)
|
|---|
| 43 | (let ((index ()))
|
|---|
| 44 | (let* ((line-chars (line-chars start-line))
|
|---|
| 45 | (dst-end (- (length line-chars) start-charpos)))
|
|---|
| 46 | (declare (simple-string line-chars))
|
|---|
| 47 | (%sp-byte-blt line-chars start-charpos string 0 dst-end)
|
|---|
| 48 | (setf (char string dst-end) #\newline)
|
|---|
| 49 | (setq index (1+ dst-end)))
|
|---|
| 50 | (do* ((line (line-next start-line) (line-next line))
|
|---|
| 51 | (chars (line-chars line) (line-chars line)))
|
|---|
| 52 | ((eq line end-line)
|
|---|
| 53 | (%sp-byte-blt (line-chars line) 0 string index dst-length))
|
|---|
| 54 | (declare (simple-string chars))
|
|---|
| 55 | (%sp-byte-blt (line-chars line) 0 string index
|
|---|
| 56 | (incf index (length chars)))
|
|---|
| 57 | (setf (char string index) #\newline)
|
|---|
| 58 | (setq index (1+ index)))))
|
|---|
| 59 | (values string dst-length)))
|
|---|
| 60 | |
|---|
| 61 |
|
|---|
| 62 | (defun string-to-region (string)
|
|---|
| 63 | "Returns a region containing the characters in the given String."
|
|---|
| 64 | (let* ((string (if (simple-string-p string)
|
|---|
| 65 | string (coerce string 'simple-string)))
|
|---|
| 66 | (end (length string)))
|
|---|
| 67 | (declare (simple-string string))
|
|---|
| 68 | (do* ((index 0)
|
|---|
| 69 | (buffer (next-disembodied-buffer-counter))
|
|---|
| 70 | (previous-line)
|
|---|
| 71 | (line (make-line :%buffer buffer))
|
|---|
| 72 | (first-line line))
|
|---|
| 73 | (())
|
|---|
| 74 | (let ((right-index (%sp-find-character string index end #\newline)))
|
|---|
| 75 | (cond (right-index
|
|---|
| 76 | (let* ((length (- right-index index))
|
|---|
| 77 | (chars (make-string length)))
|
|---|
| 78 | (%sp-byte-blt string index chars 0 length)
|
|---|
| 79 | (setf (line-chars line) chars))
|
|---|
| 80 | (setq index (1+ right-index))
|
|---|
| 81 | (setq previous-line line)
|
|---|
| 82 | (setq line (make-line :%buffer buffer))
|
|---|
| 83 | (setf (line-next previous-line) line)
|
|---|
| 84 | (setf (line-previous line) previous-line))
|
|---|
| 85 | (t
|
|---|
| 86 | (let* ((length (- end index))
|
|---|
| 87 | (chars (make-string length)))
|
|---|
| 88 | (%sp-byte-blt string index chars 0 length)
|
|---|
| 89 | (setf (line-chars line) chars))
|
|---|
| 90 | (return (renumber-region
|
|---|
| 91 | (internal-make-region
|
|---|
| 92 | (mark first-line 0 :right-inserting)
|
|---|
| 93 | (mark line (length (line-chars line))
|
|---|
| 94 | :left-inserting))))))))))
|
|---|
| 95 |
|
|---|
| 96 | (defun line-to-region (line)
|
|---|
| 97 | "Returns a region containing the specified line."
|
|---|
| 98 | (internal-make-region (mark line 0 :right-inserting)
|
|---|
| 99 | (mark line (line-length* line) :left-inserting)))
|
|---|
| 100 | |
|---|
| 101 |
|
|---|
| 102 | (defun previous-character (mark)
|
|---|
| 103 | "Returns the character immediately before the given Mark."
|
|---|
| 104 | (let ((line (mark-line mark))
|
|---|
| 105 | (charpos (mark-charpos mark)))
|
|---|
| 106 | (if (= charpos 0)
|
|---|
| 107 | (if (line-previous line)
|
|---|
| 108 | #\newline
|
|---|
| 109 | nil)
|
|---|
| 110 | (if (current-open-line-p line)
|
|---|
| 111 | (char (the simple-string (current-open-chars))
|
|---|
| 112 | (if (<= charpos (current-left-open-pos))
|
|---|
| 113 | (1- charpos)
|
|---|
| 114 | (1- (+ (current-right-open-pos) (- charpos (current-left-open-pos))))))
|
|---|
| 115 | (schar (line-chars line) (1- charpos))))))
|
|---|
| 116 |
|
|---|
| 117 | (defun next-character (mark)
|
|---|
| 118 | "Returns the character immediately after the given Mark."
|
|---|
| 119 | (let ((line (mark-line mark))
|
|---|
| 120 | (charpos (mark-charpos mark)))
|
|---|
| 121 | (if (current-open-line-p line)
|
|---|
| 122 | (if (= charpos (- (current-line-cache-length) (- (current-right-open-pos) (current-left-open-pos))))
|
|---|
| 123 | (if (line-next line)
|
|---|
| 124 | #\newline
|
|---|
| 125 | nil)
|
|---|
| 126 | (schar (current-open-chars)
|
|---|
| 127 | (if (< charpos (current-left-open-pos))
|
|---|
| 128 | charpos
|
|---|
| 129 | (+ (current-right-open-pos) (- charpos (current-left-open-pos))))))
|
|---|
| 130 | (let ((chars (line-chars line)))
|
|---|
| 131 | (if (= charpos (strlen chars))
|
|---|
| 132 | (if (line-next line)
|
|---|
| 133 | #\newline
|
|---|
| 134 | nil)
|
|---|
| 135 | (schar chars charpos))))))
|
|---|
| 136 | |
|---|
| 137 |
|
|---|
| 138 | ;;; %Set-Next-Character -- Internal
|
|---|
| 139 | ;;;
|
|---|
| 140 | ;;; This is the setf form for Next-Character. Since we may change a
|
|---|
| 141 | ;;; character to or from a newline, we must be prepared to split and
|
|---|
| 142 | ;;; join lines. We cannot just delete a character and insert the new one
|
|---|
| 143 | ;;; because the marks would not be right.
|
|---|
| 144 | ;;;
|
|---|
| 145 | (defun %set-next-character (mark character)
|
|---|
| 146 | (let* ((line (mark-line mark))
|
|---|
| 147 | (next (line-next line))
|
|---|
| 148 | (buffer (line-%buffer line)))
|
|---|
| 149 | (check-buffer-modification buffer mark)
|
|---|
| 150 | (modifying-buffer buffer
|
|---|
| 151 | (modifying-line line mark)
|
|---|
| 152 | (cond ((= (mark-charpos mark)
|
|---|
| 153 | (- (current-line-cache-length) (- (current-right-open-pos) (current-left-open-pos))))
|
|---|
| 154 | ;; The mark is at the end of the line.
|
|---|
| 155 | (unless next
|
|---|
| 156 | (error "~S has no next character, so it cannot be set." mark))
|
|---|
| 157 | (unless (char= character #\newline)
|
|---|
| 158 | ;; If the character is no longer a newline then mash two
|
|---|
| 159 | ;; lines together.
|
|---|
| 160 | (let ((chars (line-chars next)))
|
|---|
| 161 | (declare (simple-string chars))
|
|---|
| 162 | (setf (current-right-open-pos) (- (current-line-cache-length) (length chars)))
|
|---|
| 163 | (when (<= (current-right-open-pos) (current-left-open-pos))
|
|---|
| 164 | (grow-open-chars (* (+ (length chars) (current-left-open-pos) 1) 2)))
|
|---|
| 165 | (%sp-byte-blt chars 0 (current-open-chars) (current-right-open-pos)
|
|---|
| 166 | (current-line-cache-length))
|
|---|
| 167 | (setf (schar (current-open-chars) (current-left-open-pos)) character)
|
|---|
| 168 | (incf (current-left-open-pos)))
|
|---|
| 169 | (move-some-marks (charpos next line)
|
|---|
| 170 | (+ charpos (current-left-open-pos)))
|
|---|
| 171 | (setq next (line-next next))
|
|---|
| 172 | (setf (line-next line) next)
|
|---|
| 173 | (when next (setf (line-previous next) line))))
|
|---|
| 174 | ((char= character #\newline)
|
|---|
| 175 | ;; The char is being changed to a newline, so we must split lines.
|
|---|
| 176 | (incf (current-right-open-pos))
|
|---|
| 177 | (let* ((len (- (current-line-cache-length) (current-right-open-pos)))
|
|---|
| 178 | (chars (make-string len))
|
|---|
| 179 | (new (make-line :chars chars :previous line
|
|---|
| 180 | :next next :%buffer buffer)))
|
|---|
| 181 | (%sp-byte-blt (current-open-chars) (current-right-open-pos) chars 0 len)
|
|---|
| 182 | (maybe-move-some-marks* (charpos line new) (current-left-open-pos)
|
|---|
| 183 | (- charpos (current-left-open-pos) 1))
|
|---|
| 184 | (setf (line-next line) new)
|
|---|
| 185 | (when next (setf (line-previous next) new))
|
|---|
| 186 | (setf (current-right-open-pos) (current-line-cache-length))
|
|---|
| 187 | (number-line new)))
|
|---|
| 188 | (t
|
|---|
| 189 | (setf (char (the simple-string (current-open-chars)) (current-right-open-pos))
|
|---|
| 190 | character)
|
|---|
| 191 | (hi::buffer-note-modification buffer mark 1)))))
|
|---|
| 192 | character)
|
|---|
| 193 |
|
|---|
| 194 | ;;; %Set-Previous-Character -- Internal
|
|---|
| 195 | ;;;
|
|---|
| 196 | ;;; The setf form for Previous-Character. We just Temporarily move the
|
|---|
| 197 | ;;; mark back one and call %Set-Next-Character.
|
|---|
| 198 | ;;;
|
|---|
| 199 | (defun %set-previous-character (mark character)
|
|---|
| 200 | (unless (mark-before mark)
|
|---|
| 201 | (error "~S has no previous character, so it cannot be set." mark))
|
|---|
| 202 | (%set-next-character mark character)
|
|---|
| 203 | (mark-after mark)
|
|---|
| 204 | character)
|
|---|
| 205 | |
|---|
| 206 |
|
|---|
| 207 | (defun count-lines (region)
|
|---|
| 208 | "Returns the number of lines in the region, first and last lines inclusive."
|
|---|
| 209 | (do ((line (mark-line (region-start region)) (line-next line))
|
|---|
| 210 | (count 1 (1+ count))
|
|---|
| 211 | (last-line (mark-line (region-end region))))
|
|---|
| 212 | ((eq line last-line) count)))
|
|---|
| 213 |
|
|---|
| 214 | (defun count-characters (region)
|
|---|
| 215 | "Returns the number of characters in the region."
|
|---|
| 216 | (let* ((start (region-start region))
|
|---|
| 217 | (end (region-end region))
|
|---|
| 218 | (first-line (mark-line start))
|
|---|
| 219 | (last-line (mark-line end)))
|
|---|
| 220 | (if (eq first-line last-line)
|
|---|
| 221 | (- (mark-charpos end) (mark-charpos start))
|
|---|
| 222 | (do ((line (line-next first-line) (line-next line))
|
|---|
| 223 | (count (1+ (- (line-length* first-line) (mark-charpos start)))))
|
|---|
| 224 | ((eq line last-line)
|
|---|
| 225 | (+ count (mark-charpos end)))
|
|---|
| 226 | (setq count (+ 1 count (line-length* line)))))))
|
|---|
| 227 |
|
|---|
| 228 | (defun line-start (mark &optional line)
|
|---|
| 229 | "Changes the Mark to point to the beginning of the Line and returns it.
|
|---|
| 230 | Line defaults to the line Mark is on."
|
|---|
| 231 | (when line
|
|---|
| 232 | (change-line mark line))
|
|---|
| 233 | (setf (mark-charpos mark) 0)
|
|---|
| 234 | mark)
|
|---|
| 235 |
|
|---|
| 236 | (defun line-end (mark &optional line)
|
|---|
| 237 | "Changes the Mark to point to the end of the line and returns it.
|
|---|
| 238 | Line defaults to the line Mark is on."
|
|---|
| 239 | (if line
|
|---|
| 240 | (change-line mark line)
|
|---|
| 241 | (setq line (mark-line mark)))
|
|---|
| 242 | (setf (mark-charpos mark) (line-length* line))
|
|---|
| 243 | mark)
|
|---|
| 244 |
|
|---|
| 245 | (defun buffer-start (mark &optional (buffer (mark-buffer mark)))
|
|---|
| 246 | "Change Mark to point to the beginning of Buffer, which defaults to
|
|---|
| 247 | the buffer Mark is currently in."
|
|---|
| 248 | (unless buffer (error "Mark ~S does not point into a buffer." mark))
|
|---|
| 249 | (move-mark mark (buffer-start-mark buffer)))
|
|---|
| 250 |
|
|---|
| 251 | (defun buffer-end (mark &optional (buffer (mark-buffer mark)))
|
|---|
| 252 | "Change Mark to point to the end of Buffer, which defaults to
|
|---|
| 253 | the buffer Mark is currently in."
|
|---|
| 254 | (unless buffer (error "Mark ~S does not point into a buffer." mark))
|
|---|
| 255 | (move-mark mark (buffer-end-mark buffer)))
|
|---|
| 256 |
|
|---|
| 257 | (defun move-mark (mark new-position)
|
|---|
| 258 | "Changes the Mark to point to the same position as New-Position."
|
|---|
| 259 | (let* ((line (mark-line new-position)))
|
|---|
| 260 | (change-line mark line))
|
|---|
| 261 | (setf (mark-charpos mark) (mark-charpos new-position))
|
|---|
| 262 | mark)
|
|---|
| 263 |
|
|---|
| 264 | |
|---|
| 265 |
|
|---|
| 266 | (defun mark-before (mark)
|
|---|
| 267 | "Changes the Mark to point one character before where it currently points.
|
|---|
| 268 | NIL is returned if there is no previous character."
|
|---|
| 269 | (let ((charpos (mark-charpos mark)))
|
|---|
| 270 | (cond ((zerop charpos)
|
|---|
| 271 | (let ((prev (line-previous (mark-line mark))))
|
|---|
| 272 | (when prev
|
|---|
| 273 | (always-change-line mark prev)
|
|---|
| 274 | (setf (mark-charpos mark) (line-length* prev))
|
|---|
| 275 | mark)))
|
|---|
| 276 | (t
|
|---|
| 277 | (setf (mark-charpos mark) (1- charpos))
|
|---|
| 278 | mark))))
|
|---|
| 279 |
|
|---|
| 280 | (defun mark-after (mark)
|
|---|
| 281 | "Changes the Mark to point one character after where it currently points.
|
|---|
| 282 | NIL is returned if there is no previous character."
|
|---|
| 283 | (let ((line (mark-line mark))
|
|---|
| 284 | (charpos (mark-charpos mark)))
|
|---|
| 285 | (cond ((= charpos (line-length* line))
|
|---|
| 286 | (let ((next (line-next line)))
|
|---|
| 287 | (when next
|
|---|
| 288 | (always-change-line mark next)
|
|---|
| 289 | (setf (mark-charpos mark) 0)
|
|---|
| 290 | mark)))
|
|---|
| 291 | (t
|
|---|
| 292 | (setf (mark-charpos mark) (1+ charpos))
|
|---|
| 293 | mark))))
|
|---|
| 294 | |
|---|
| 295 |
|
|---|
| 296 | (defun character-offset (mark n)
|
|---|
| 297 | "Changes the Mark to point N characters after (or -N before if N is negative)
|
|---|
| 298 | where it currently points. If there aren't N characters before (or after)
|
|---|
| 299 | the mark, Nil is returned."
|
|---|
| 300 | (let* ((charpos (mark-charpos mark)))
|
|---|
| 301 | (if (< n 0)
|
|---|
| 302 | (let ((n (- n)))
|
|---|
| 303 | (if (< charpos n)
|
|---|
| 304 | (do ((line (line-previous (mark-line mark)) (line-previous line))
|
|---|
| 305 | (n (- n charpos 1)))
|
|---|
| 306 | ((null line) nil)
|
|---|
| 307 | (let ((length (line-length* line)))
|
|---|
| 308 | (cond ((<= n length)
|
|---|
| 309 | (always-change-line mark line)
|
|---|
| 310 | (setf (mark-charpos mark) (- length n))
|
|---|
| 311 | (return mark))
|
|---|
| 312 | (t
|
|---|
| 313 | (setq n (- n (1+ length)))))))
|
|---|
| 314 | (progn (setf (mark-charpos mark) (- charpos n))
|
|---|
| 315 | mark)))
|
|---|
| 316 | (let* ((line (mark-line mark))
|
|---|
| 317 | (length (line-length* line)))
|
|---|
| 318 | (if (> (+ charpos n) length)
|
|---|
| 319 | (do ((line (line-next line) (line-next line))
|
|---|
| 320 | (n (- n (1+ (- length charpos)))))
|
|---|
| 321 | ((null line) nil)
|
|---|
| 322 | (let ((length (line-length* line)))
|
|---|
| 323 | (cond ((<= n length)
|
|---|
| 324 | (always-change-line mark line)
|
|---|
| 325 | (setf (mark-charpos mark) n)
|
|---|
| 326 | (return mark))
|
|---|
| 327 | (t
|
|---|
| 328 | (setq n (- n (1+ length)))))))
|
|---|
| 329 | (progn (setf (mark-charpos mark) (+ charpos n))
|
|---|
| 330 | mark))))))
|
|---|
| 331 | |
|---|
| 332 |
|
|---|
| 333 | (defun line-offset (mark n &optional charpos)
|
|---|
| 334 | "Changes to Mark to point N lines after (-N before if N is negative) where
|
|---|
| 335 | it currently points. If there aren't N lines after (or before) the Mark,
|
|---|
| 336 | Nil is returned."
|
|---|
| 337 | (if (< n 0)
|
|---|
| 338 | (do ((line (mark-line mark) (line-previous line))
|
|---|
| 339 | (n n (1+ n)))
|
|---|
| 340 | ((null line) nil)
|
|---|
| 341 | (when (= n 0)
|
|---|
| 342 | (always-change-line mark line)
|
|---|
| 343 | (setf (mark-charpos mark)
|
|---|
| 344 | (if charpos
|
|---|
| 345 | (min (line-length line) charpos)
|
|---|
| 346 | (min (line-length line) (mark-charpos mark))))
|
|---|
| 347 | (return mark)))
|
|---|
| 348 | (do ((line (mark-line mark) (line-next line))
|
|---|
| 349 | (n n (1- n)))
|
|---|
| 350 | ((null line) nil)
|
|---|
| 351 | (when (= n 0)
|
|---|
| 352 | (change-line mark line)
|
|---|
| 353 | (setf (mark-charpos mark)
|
|---|
| 354 | (if charpos
|
|---|
| 355 | (min (line-length line) charpos)
|
|---|
| 356 | (min (line-length line) (mark-charpos mark))))
|
|---|
| 357 | (return mark)))))
|
|---|
| 358 |
|
|---|
| 359 | ;;; region-bounds -- Public
|
|---|
| 360 | ;;;
|
|---|
| 361 | (defun region-bounds (region)
|
|---|
| 362 | "Return as multiple-value the start and end of Region."
|
|---|
| 363 | (values (region-start region) (region-end region)))
|
|---|
| 364 |
|
|---|
| 365 | (defun set-region-bounds (region start end)
|
|---|
| 366 | "Set the start and end of Region to the marks Start and End."
|
|---|
| 367 | (let ((sl (mark-line start))
|
|---|
| 368 | (el (mark-line end)))
|
|---|
| 369 | (when (or (neq (line-%buffer sl) (line-%buffer el))
|
|---|
| 370 | (> (line-number sl) (line-number el))
|
|---|
| 371 | (and (eq sl el) (> (mark-charpos start) (mark-charpos end))))
|
|---|
| 372 | (error "Marks ~S and ~S cannot be made into a region." start end))
|
|---|
| 373 | (setf (region-start region) start (region-end region) end))
|
|---|
| 374 | region)
|
|---|
| 375 |
|
|---|
| 376 | |
|---|
| 377 |
|
|---|
| 378 | ;;;; Debugging stuff.
|
|---|
| 379 |
|
|---|
| 380 | (defun slf (string)
|
|---|
| 381 | "For a good time, figure out what this function does, and why it was written."
|
|---|
| 382 | (delete #\linefeed (the simple-string string)))
|
|---|
| 383 |
|
|---|
| 384 | (defun %print-whole-line (structure stream)
|
|---|
| 385 | (let* ((hi::*current-buffer* (line-buffer structure)))
|
|---|
| 386 | (cond ((current-open-line-p structure)
|
|---|
| 387 | (write-string (current-open-chars) stream :end (current-left-open-pos))
|
|---|
| 388 | (write-string (current-open-chars) stream :start (current-right-open-pos)
|
|---|
| 389 | :end (current-line-cache-length)))
|
|---|
| 390 | (t
|
|---|
| 391 | (write-string (line-chars structure) stream)))))
|
|---|
| 392 |
|
|---|
| 393 | (defun %print-before-mark (mark stream)
|
|---|
| 394 | (let* ((hi::*current-buffer* (mark-buffer mark)))
|
|---|
| 395 | (if (mark-line mark)
|
|---|
| 396 | (let* ((line (mark-line mark))
|
|---|
| 397 | (chars (line-chars line))
|
|---|
| 398 | (charpos (mark-charpos mark))
|
|---|
| 399 | (length (line-length line)))
|
|---|
| 400 | (declare (simple-string chars))
|
|---|
| 401 | (cond ((or (> charpos length) (< charpos 0))
|
|---|
| 402 | (write-string "{bad mark}" stream))
|
|---|
| 403 | ((current-open-line-p line)
|
|---|
| 404 | (cond ((< charpos (current-left-open-pos))
|
|---|
| 405 | (write-string (current-open-chars) stream :end charpos))
|
|---|
| 406 | (t
|
|---|
| 407 | (write-string (current-open-chars) stream :end (current-left-open-pos))
|
|---|
| 408 | (let ((p (+ charpos (- (current-right-open-pos) (current-left-open-pos)))))
|
|---|
| 409 | (write-string (current-open-chars) stream :start (current-right-open-pos)
|
|---|
| 410 | :end p)))))
|
|---|
| 411 | (t
|
|---|
| 412 | (write-string chars stream :end charpos))))
|
|---|
| 413 | (write-string "{deleted mark}" stream))))
|
|---|
| 414 |
|
|---|
| 415 |
|
|---|
| 416 | (defun %print-after-mark (mark stream)
|
|---|
| 417 | (let* ((hi::*current-buffer* (mark-buffer mark)))
|
|---|
| 418 | (if (mark-line mark)
|
|---|
| 419 | (let* ((line (mark-line mark))
|
|---|
| 420 | (chars (line-chars line))
|
|---|
| 421 | (charpos (mark-charpos mark))
|
|---|
| 422 | (length (line-length line)))
|
|---|
| 423 | (declare (simple-string chars))
|
|---|
| 424 | (cond ((or (> charpos length) (< charpos 0))
|
|---|
| 425 | (write-string "{bad mark}" stream))
|
|---|
| 426 | ((current-open-line-p line)
|
|---|
| 427 | (cond ((< charpos (current-left-open-pos))
|
|---|
| 428 | (write-string (current-open-chars) stream :start charpos
|
|---|
| 429 | :end (current-left-open-pos))
|
|---|
| 430 | (write-string (current-open-chars) stream :start (current-right-open-pos)
|
|---|
| 431 | :end (current-line-cache-length)))
|
|---|
| 432 | (t
|
|---|
| 433 | (let ((p (+ charpos (- (current-right-open-pos) (current-left-open-pos)))))
|
|---|
| 434 | (write-string (current-open-chars) stream :start p
|
|---|
| 435 | :end (current-line-cache-length))))))
|
|---|
| 436 | (t
|
|---|
| 437 | (write-string chars stream :start charpos :end length))))
|
|---|
| 438 | (write-string "{deleted mark}" stream))))
|
|---|
| 439 |
|
|---|
| 440 | (defun %print-hline (structure stream d)
|
|---|
| 441 | (declare (ignore d))
|
|---|
| 442 | (write-string "#<Hemlock Line \"" stream)
|
|---|
| 443 | (%print-whole-line structure stream)
|
|---|
| 444 | (write-string "\">" stream))
|
|---|
| 445 |
|
|---|
| 446 | (defun %print-hmark (structure stream d)
|
|---|
| 447 | (declare (ignore d))
|
|---|
| 448 | (let ((hi::*current-buffer* (mark-buffer structure)))
|
|---|
| 449 | (write-string "#<Hemlock Mark \"" stream)
|
|---|
| 450 | (%print-before-mark structure stream)
|
|---|
| 451 | (write-string "^" stream)
|
|---|
| 452 | (%print-after-mark structure stream)
|
|---|
| 453 | (write-string "\">" stream)))
|
|---|
| 454 |
|
|---|
| 455 | (defvar *print-region* 10
|
|---|
| 456 | "The number of lines to print out of a region, or NIL if none.")
|
|---|
| 457 |
|
|---|
| 458 | (defun %print-hregion (region stream d)
|
|---|
| 459 | (declare (ignore d))
|
|---|
| 460 | (write-string "#<Hemlock Region \"" stream)
|
|---|
| 461 | (let* ((start (region-start region))
|
|---|
| 462 | (end (region-end region))
|
|---|
| 463 | (hi::*current-buffer* (mark-buffer start))
|
|---|
| 464 | (first-line (mark-line start))
|
|---|
| 465 | (last-line (mark-line end)))
|
|---|
| 466 | (cond
|
|---|
| 467 | ((not (and (linep first-line) (linep last-line)
|
|---|
| 468 | (eq (line-%buffer first-line) (line-%buffer last-line))
|
|---|
| 469 | (mark<= start end)))
|
|---|
| 470 | (write-string "{bad region}" stream))
|
|---|
| 471 | (*print-region*
|
|---|
| 472 | (cond ((eq first-line last-line)
|
|---|
| 473 | (let ((cs (mark-charpos start))
|
|---|
| 474 | (ce (mark-charpos end))
|
|---|
| 475 | (len (line-length first-line)))
|
|---|
| 476 | (cond
|
|---|
| 477 | ((or (< cs 0) (> ce len))
|
|---|
| 478 | (write-string "{bad region}" stream))
|
|---|
| 479 | ((current-open-line-p first-line)
|
|---|
| 480 | (let ((gap (- (current-right-open-pos) (current-left-open-pos))))
|
|---|
| 481 | (cond
|
|---|
| 482 | ((<= ce (current-left-open-pos))
|
|---|
| 483 | (write-string (current-open-chars) stream :start cs :end ce))
|
|---|
| 484 | ((>= cs (current-left-open-pos))
|
|---|
| 485 | (write-string (current-open-chars) stream :start (+ cs gap)
|
|---|
| 486 | :end (+ ce gap)))
|
|---|
| 487 | (t
|
|---|
| 488 | (write-string (current-open-chars) stream :start cs
|
|---|
| 489 | :end (current-left-open-pos))
|
|---|
| 490 | (write-string (current-open-chars) stream :start (current-right-open-pos)
|
|---|
| 491 | :end (+ gap ce))))))
|
|---|
| 492 | (t
|
|---|
| 493 | (write-string (line-chars first-line) stream :start cs
|
|---|
| 494 | :end ce)))))
|
|---|
| 495 | (t
|
|---|
| 496 | (%print-after-mark start stream)
|
|---|
| 497 | (write-char #\/ stream)
|
|---|
| 498 | (do ((line (line-next first-line) (line-next line))
|
|---|
| 499 | (last-line (mark-line end))
|
|---|
| 500 | (cnt *print-region* (1- cnt)))
|
|---|
| 501 | ((or (eq line last-line)
|
|---|
| 502 | (when (zerop cnt) (write-string "..." stream) t))
|
|---|
| 503 | (%print-before-mark end stream))
|
|---|
| 504 | (%print-whole-line line stream)
|
|---|
| 505 | (write-char #\/ stream)))))
|
|---|
| 506 | (t
|
|---|
| 507 | (write-string "{mumble}" stream))))
|
|---|
| 508 | (write-string "\">" stream))
|
|---|
| 509 |
|
|---|
| 510 | (defun %print-hbuffer (structure stream d)
|
|---|
| 511 | (declare (ignore d))
|
|---|
| 512 | (write-string "#<Hemlock Buffer \"" stream)
|
|---|
| 513 | (write-string (buffer-name structure) stream)
|
|---|
| 514 | (write-string "\">" stream))
|
|---|
| 515 |
|
|---|
| 516 | (defun check-buffer-modification (buffer mark)
|
|---|
| 517 | (when (typep buffer 'buffer)
|
|---|
| 518 | (let* ((protected-region (buffer-protected-region buffer)))
|
|---|
| 519 | (when protected-region
|
|---|
| 520 | (let* ((prot-start (region-start protected-region))
|
|---|
| 521 | (prot-end (region-end protected-region)))
|
|---|
| 522 |
|
|---|
| 523 | (when (and (mark>= mark prot-start)
|
|---|
| 524 | (mark< mark prot-end))
|
|---|
| 525 | (editor-error "Can't modify protected buffer region.")))))))
|
|---|