1 (declaim (optimize (debug 3)))
7 (defvar *buffer-list
* nil
8 "All buffers managed by lice. buffers are sorted from most recently
9 accessed to least. the CAR is the most recent buffer.")
11 (defvar *current-buffer
* nil
12 "When this buffer is non-nil, it contains the current buffer. Calls
13 to `current-buffer' return this buffer. Otherwise, `current-buffer'
14 returns the current frames's current window's buffer.
16 This variable should never be set using `setq' or `setf'. Bind it with
17 `let' for as long as it needs to be set.")
20 ((data :type string
:initarg
:data
:accessor pstring-data
)
21 (intervals :type
(or null interval
) :initform nil
:initarg
:intervals
:accessor intervals
))
22 (:documentation
"The lice string implementation."))
24 (defmethod print-object ((obj pstring
) stream
)
25 (print-unreadable-object (obj stream
:type t
:identity t
)
26 (format stream
"~s" (pstring-data obj
))))
28 (defun pstring-length (ps)
29 "Return the length of the string in PS"
30 (declare (type pstring ps
))
31 (length (pstring-data ps
)))
33 (defclass base-buffer
()
34 ((file :type
(or null pathname
) :initarg
:file
:accessor buffer-file
)
35 (name :type string
:initarg
:name
:accessor buffer-name
)
37 (mode-line :type list
:initarg
:mode-line
:initform nil
:accessor buffer-mode-line
)
38 (mode-line-string :type string
:initform
"" :accessor buffer-mode-line-string
)
39 (modified :type boolean
:initform nil
:accessor buffer-modified
)
40 (read-only :type boolean
:initform nil
:accessor buffer-read-only
)
41 (tick :type integer
:initform
0 :accessor buffer-modified-tick
:documentation
42 "The buffer's tick counter. It is incremented for each change
44 (display-count :type integer
:initform
0 :accessor buffer-display-count
:documentation
45 "The buffer's display counter. It is incremented each time it
46 is displayed in a window.")
47 (display-time :type integer
:initform
0 :accessor buffer-display-time
:documentation
48 "The last time the buffer was switched to in a window.")
49 (major-mode :type major-mode
:initarg
:major-mode
:accessor buffer-major-mode
)
50 (locals-variables :type hash-table
:initform
(make-hash-table) :accessor buffer-local-variables
)
51 (locals :type hash-table
:initform
(make-hash-table) :accessor buffer-locals
))
52 (:documentation
"A Buffer."))
54 (defclass buffer
(base-buffer)
55 ((point :type marker
:initarg
:point
:accessor buffer-point
)
56 (mark :type marker
:initarg
:mark
:accessor buffer-mark-marker
)
57 ;; A string containing the raw buffer
58 (data :type
(array character
1) :initarg
:data
:accessor buffer-data
)
59 (intervals :type
(or null interval
) :initform nil
:initarg
:intervals
:accessor intervals
)
60 (gap-start :type integer
:initarg
:gap-start
:accessor buffer-gap-start
)
61 (gap-size :type integer
:initarg
:gap-size
:accessor buffer-gap-size
)
62 (markers :type list
:initform
'() :accessor buffer-markers
)
63 (syntax-table :initform
*standard-syntax-table
* :accessor buffer-syntax-table
))
64 (:documentation
"A text Buffer."))
66 (defmethod print-object ((obj buffer
) stream
)
67 (print-unreadable-object (obj stream
:type t
:identity t
)
68 (format stream
"~a" (buffer-name obj
))))
70 (define-condition args-out-of-range
(lice-condition)
71 () (:documentation
"Raised when some arguments (usually relating to a
72 buffer) are out of range."))
74 (define-condition beginning-of-buffer
(lice-condition)
75 () (:documentation
"Raised when it is an error that the point is at
76 the beginning of the buffer."))
78 (define-condition end-of-buffer
(lice-condition)
79 () (:documentation
"Raised when it is an error that the point is at
80 the end of the buffer."))
82 (define-condition buffer-read-only
(lice-condition)
83 () (:documentation
"Raised when there is an attempt to insert into a read-only buffer."))
85 (defun mark-marker (&optional
(buffer (current-buffer)))
86 "Return this buffer's mark, as a marker object.
87 Watch out! Moving this marker changes the mark position.
88 If you set the marker not to point anywhere, the buffer will have no mark."
89 ;; FIXME: marks can't be inactive ATM
90 (buffer-mark-marker buffer
))
95 (defstruct buffer-local-binding
96 symbol value doc-string
)
98 (defvar *global-buffer-locals
* (make-hash-table)
99 "The default values of buffer locals and a hash table containing all possible buffer locals")
101 (defun buffer-local-exists-p (symbol)
102 (multiple-value-bind (v b
) (gethash symbol
*global-buffer-locals
*)
106 (defun make-buffer-local (symbol default-value
&optional doc-string
)
107 (unless (buffer-local-exists-p symbol
)
108 (setf (gethash symbol
*global-buffer-locals
*)
109 (make-buffer-local-binding :symbol symbol
111 :doc-string doc-string
))))
113 (defmacro define-buffer-local
(symbol default-value
&optional doc-string
)
114 "buffer locals are data hooks you can use to store values per
115 buffer. Use them when building minor and major modes. You
116 generally want to define them with this so you can create a
117 docstring for them. there is also `make-buffer-local'."
118 `(make-buffer-local ,symbol
,default-value
,doc-string
))
120 (defun (setf buffer-local
) (symbol value
)
121 "Set the value of the buffer local in the current buffer."
122 (setf (gethash symbol
(buffer-locals *current-buffer
*)) value
)
123 ;; create a global buffer local entry if needed.
124 (make-buffer-local symbol nil
))
126 (defun buffer-local (symbol)
127 "Return the value of the buffer local symbol. If none exists
128 for the current buffer then use the global one. If that doesn't
130 (multiple-value-bind (v b
) (gethash symbol
(buffer-locals *current-buffer
*))
133 (multiple-value-bind (v b
) (gethash symbol
*global-buffer-locals
*)
135 (buffer-local-binding-value v
))))))
137 (define-buffer-local :buffer-invisibility-spec nil
138 "Invisibility spec of this buffer.
139 The default is t, which means that text is invisible
140 if it has a non-nil `invisible' property.
141 If the value is a list, a text character is invisible if its `invisible'
142 property is an element in that list.
143 If an element is a cons cell of the form (PROP . ELLIPSIS),
144 then characters with property value PROP are invisible,
145 and they have an ellipsis as well if ELLIPSIS is non-nil.")
147 (define-buffer-local :selective-display nil
148 "Non-nil enables selective display.
149 An Integer N as value means display only lines
150 that start with less than n columns of space.
151 A value of t means that the character ^M makes itself and
152 all the rest of the line invisible; also, when saving the buffer
153 in a file, save the ^M as a newline.")
157 ;;; buffer related conditions
159 ;;(define-condition end-of-buffer)
165 ((position :type integer
:initform
0 :accessor marker-position
)
166 (buffer :type
(or buffer null
) :initform nil
:accessor marker-buffer
))
167 (:documentation
"A Marker"))
169 (defmethod print-object ((obj marker
) stream
)
170 (print-unreadable-object (obj stream
:type t
:identity t
)
171 (format stream
"~a" (marker-position obj
))))
173 (defgeneric ensure-number
(thing)
174 (:documentation
"Call this function when THING could be a number or a marker or...?"))
176 (defmethod ensure-number ((thing number
))
179 (defmethod ensure-number ((thing marker
))
180 (marker-position thing
))
182 (defun copy-marker (marker &optional type
)
183 "Return a new marker pointing at the same place as MARKER.
184 If argument is a number, makes a new marker pointing
185 at that position in the current buffer.
186 **The optional argument TYPE specifies the insertion type of the new marker;
187 **see `marker-insertion-type'."
188 (declare (ignore type
))
189 (make-marker (if (numberp marker
)
191 (marker-position marker
))
192 (if (typep marker
'marker
)
193 (marker-buffer marker
)
196 (defun make-marker (&optional position buffer
)
197 "Return a newly allocated marker which does not point anywhere."
198 (let ((m (make-instance 'marker
)))
199 (when (and position buffer
)
200 (set-marker m position buffer
))
203 (defun unchain-marker (marker)
204 (when (marker-buffer marker
)
205 (setf (buffer-markers (marker-buffer marker
))
206 (delete marker
(buffer-markers (marker-buffer marker
)) :key
#'weak-pointer-value
))))
208 (defun chain-marker (marker buffer
)
209 (push (make-weak-pointer marker
) (buffer-markers buffer
)))
211 (defun set-marker (marker position
&optional
(buffer (current-buffer)))
212 ;; remove the marker from its buffer, when appropriate
213 (when (null position
)
214 (unchain-marker marker
)
215 (return-from set-marker marker
))
216 ;; XXX handle dead buffers
219 (setf (marker-position marker
) (min (max position
(begv buffer
)) (zv buffer
)))
221 ;; update buffer stuff
222 (unless (eq (marker-buffer marker
) buffer
)
223 (unchain-marker marker
)
224 (setf (marker-buffer marker
) buffer
)
225 (chain-marker marker buffer
))
228 (defun update-markers-del (buffer start size
)
229 ;; First get rid of stale markers
230 (purge-markers buffer
)
231 (dolist (wp (buffer-markers buffer
))
232 (let ((m (weak-pointer-value wp
)))
233 ;; paranoia, maybe the GC freed some stuff after the marker
236 ;; markers are before the marker-position.
237 (cond ((>= (marker-position m
) (+ start size
))
238 (decf (marker-position m
) size
))
239 ((> (marker-position m
) start
)
240 (setf (marker-position m
) start
)))))))
242 (defun update-markers-ins (buffer start size
)
243 ;; First get rid of stale markers
244 (purge-markers buffer
)
245 (dolist (wp (buffer-markers buffer
))
246 (let ((m (weak-pointer-value wp
)))
247 ;; markers are before the marker-position.
248 (when (and m
(> (marker-position m
) start
)
249 (incf (marker-position m
) size
))))))
251 (defun purge-markers (buffer)
252 "Remove GC'd markers."
253 (setf (buffer-markers buffer
)
254 (delete-if (lambda (m)
255 (multiple-value-bind (v c
) (weak-pointer-value m
)
258 (buffer-markers buffer
))))
263 (defun inc-buffer-tick (buffer)
264 "Increment the buffer's ticker."
265 (incf (buffer-modified-tick buffer
)))
267 ;;; Some wrappers around replace
269 (defun move-subseq-left (seq from end to
)
270 "Move the subseq between from and end to before TO, which is assumed to be
272 (replace seq seq
:start1
(+ to
(- end from
) 1) :start2 to
:end2 from
)
275 (defun move-subseq-right (seq from end to
)
276 "Move the subseq between from and end to before TO, which is assumed to be
278 (replace seq seq
:start1 from
:start2
(1+ end
) :end2 to
)
279 (+ from
(- to end
1)))
281 (defun move-subseq (seq from end to
)
282 "Destructively move the gap subseq starting at from and ending at
283 end, inclusive, to before TO."
285 (move-subseq-left seq from end to
)
286 (move-subseq-right seq from end to
)))
288 (defun fill-gap (buf)
289 "For debugging purposes. fill the gap with _'s."
290 (fill (buffer-data buf
) #\_
:start
(buffer-gap-start buf
) :end
(gap-end buf
)))
292 (defun gap-move-to (buf to
)
293 "A basic function to move the gap. TO is in aref coordinates and the
294 gap is positioned before TO.
297 (gap-move-to buffer 6)
299 (setf (buffer-gap-start buf
)
300 (move-subseq (buffer-data buf
) (buffer-gap-start buf
) (1- (gap-end buf
)) to
))
301 ;; for debugging purposes, we set the gap to _'s
304 (defun gap-move-to-point (buf)
305 "Move the gap to the point position in aref space.
312 (gap-move-to buf
(buffer-char-to-aref buf
(marker-position (buffer-point buf
)))))
314 ;; ;; Move the gap to the end of the vector
315 ;; (replace data data :start1 gap-start :start2 gap-end)
316 ;; ;; open a space for the gap
317 ;; (replace data data :start1 (+ to (buffer-gap-size buf)) :start2 to)
318 ;; (setf (buffer-gap-start buf) to)))
321 "The end of the gap. in aref space. gap-end is the first valid
323 (declare (type buffer buf
))
324 (+ (buffer-gap-start buf
) (buffer-gap-size buf
)))
326 (defmacro inc-aref
(var buffer
)
327 "increment VAR one character forward in BUFFER, avoiding the gap."
330 (if (= (buffer-gap-start ,buffer
) ,var
)
331 (setf ,var
(gap-end ,buffer
)))))
333 (defmacro inc-both
(char-var aref-var buffer
)
335 (inc-aref ,aref-var
,buffer
)
338 (defun aref-minus-1 (aref buffer
)
339 (if (= (gap-end buffer
) aref
)
340 (1- (buffer-gap-start buffer
))
343 (defmacro dec-aref
(var buffer
)
344 "increment VAR one character forward in BUFFER, avoiding the gap."
345 `(setf ,var
(aref-minus-1 ,var
,buffer
)))
347 (defmacro dec-both
(char-var aref-var buffer
)
349 (dec-aref ,aref-var
,buffer
)
352 ;; (defun gap-close (buf)
353 ;; "Move the gap to the end of the buffer."
354 ;; (let ((gap-start (buffer-gap-start buf))
355 ;; (gap-end (gap-end buf)))
356 ;; (setf (buffer-gap-start buf) (- (length (buffer-data buf)) (buffer-gap-size buf)))
357 ;; (replace (buffer-data buf) (buffer-data buf) :start1 gap-start :start2 gap-end)))
359 (defun grow-buffer-data (buf size
)
360 "Grow the buffer data array to be SIZE. SIZE must be larger than before."
361 ;; MOVITZ doesn't have adjust-array
362 ;; ;; #\_ is used for debugging to represent the gap
363 ;; (adjust-array (buffer-data buf) size :initial-element #\_ :fill-pointer t)
364 (let ((newbuf (make-array size
:initial-element
#\_
;; :fill-pointer t
365 :element-type
'character
)))
366 (replace newbuf
(buffer-data buf
))
367 (setf (buffer-data buf
) newbuf
)))
369 (defun gap-extend (buf size
)
370 "Extend the gap by SIZE characters."
371 (let ((new-size (+ (length (buffer-data buf
)) size
))
372 (old-end (gap-end buf
))
373 (old-size (buffer-size buf
))
374 (data (buffer-data buf
)))
375 (setf data
(grow-buffer-data buf new-size
))
376 (incf (buffer-gap-size buf
) size
)
377 (unless (= (buffer-gap-start buf
) old-size
)
379 :start1
(gap-end buf
)
381 ;; for debugging, mark the gap
384 (defun buffer-size (buf)
385 "Return the length of the buffer not including the gap."
386 (declare (type buffer buf
))
387 (- (length (buffer-data buf
))
388 (buffer-gap-size buf
)))
390 (defun buffer-min (buf)
391 "The beginning of the buffer in char space."
392 (declare (type buffer buf
)
396 (defun buffer-max (buf)
397 "The end of the buffer in char space."
398 (declare (type buffer buf
))
401 (defun begv (&optional
(buf (current-buffer)))
402 "Position of beginning of accessible range of buffer."
403 ;; TODO: handle buffer narrowing
406 (defun begv-aref (&optional
(buf (current-buffer)))
407 "aref Position of beginning of accessible range of buffer."
408 ;; TODO: handle buffer narrowing
409 (buffer-char-to-aref buf
(buffer-min buf
)))
411 (defun zv (&optional
(buf (current-buffer)))
412 "Position of end of accessible range of buffer."
413 ;; TODO: handle buffer narrowing
416 (defun zv-aref (&optional
(buf (current-buffer)))
417 "aref Position of end of accessible range of buffer."
418 ;; TODO: handle buffer narrowing
419 (buffer-char-to-aref buf
(buffer-max buf
)))
421 (defun point (&optional
(buffer (current-buffer)))
422 "Return the point in the current buffer."
423 (marker-position (buffer-point buffer
)))
425 (defun point-marker (&optional
(buffer (current-buffer)))
426 "Return value of point, as a marker object."
427 (buffer-point buffer
))
429 (defun point-min (&optional
(buffer (current-buffer)))
430 "Return the minimum permissible value of point in the current buffer."
431 (declare (ignore buffer
))
434 (defun point-max (&optional
(buffer (current-buffer)))
435 "Return the maximum permissible value of point in the current buffer."
436 (buffer-size buffer
))
438 (defun set-point-both (buffer char-pos aref-pos
)
439 "Set point in BUFFER to CHARPOS, which corresponds to byte
440 position BYTEPOS. If the target position is
441 before an intangible character, move to an ok place."
442 (declare (ignore aref-pos
))
444 (setf (marker-position (buffer-point buffer
)) char-pos
))
446 (defun set-point (char-pos &optional
(buffer (current-buffer)))
447 (set-point-both buffer char-pos nil
))
449 (defun goto-char (position &optional
(buffer (current-buffer)))
450 "Set point to POSITION, a number."
451 (check-number-coerce-marker position
)
452 (when (and (>= position
(point-min buffer
))
453 (<= position
(point-max buffer
)))
454 (set-point position buffer
)))
456 ;; (defun buffer-char-before-point (buf p)
457 ;; "The character at the point P in buffer BUF. P is in char space."
458 ;; (declare (type buffer buf)
460 ;; (let ((aref (buffer-char-to-aref buf p)))
461 ;; (when (< aref (length (buffer-data buf)))
462 ;; (aref (buffer-data buf) aref))))
464 (defun buffer-char-after (buf p
)
465 "The character at the point P in buffer BUF. P is in char space."
466 (declare (type buffer buf
)
468 (let ((aref (buffer-char-to-aref buf p
)))
469 (when (and (>= aref
0)
470 (< aref
(length (buffer-data buf
))))
471 (aref (buffer-data buf
) aref
))))
473 (defun buffer-char-before (buf p
)
474 (buffer-char-after buf
(1- p
)))
476 (defun char-after (&optional
(pos (point)))
477 "Return character in current buffer at position POS.
478 ***POS is an integer or a marker.
479 ***If POS is out of range, the value is nil."
480 (buffer-char-after (current-buffer) pos
))
482 (defun char-before (&optional
(pos (point)))
483 "Return character in current buffer preceding position POS.
484 ***POS is an integer or a marker.
485 ***If POS is out of range, the value is nil."
486 (char-after (1- pos
)))
488 (defun buffer-aref-to-char (buf idx
)
489 "Translate the index into the buffer data to the index excluding the gap."
490 (declare (type buffer buf
)
492 (if (>= idx
(gap-end buf
))
493 (- idx
(buffer-gap-size buf
))
496 (defun buffer-char-to-aref (buf p
)
498 (declare (type buffer buf
)
500 (if (>= p
(buffer-gap-start buf
))
501 (+ p
(buffer-gap-size buf
))
504 (defun buffer-point-aref (buf)
505 "Return the buffer point in aref coordinates."
506 (buffer-char-to-aref buf
(point buf
)))
508 (defun buffer-fetch-char (aref buf
)
509 (aref (buffer-data buf
) aref
))
511 (defun string-to-vector (s)
512 "Return a resizable vector containing the elements of the string s."
514 (make-array (length s
)
516 :element-type
'character
520 (defgeneric buffer-insert
(buffer object
)
521 (:documentation
"Insert OBJECT into BUFFER at the current point."))
523 (defmethod buffer-insert :after
((buf buffer
) object
)
524 "Any object insertion modifies the buffer."
525 (declare (ignore object
))
526 (setf (buffer-modified buf
) t
))
528 (defmethod buffer-insert ((buf buffer
) (char character
))
529 "Insert a single character into buffer before point."
530 ;; Resize the gap if needed
531 (if (<= (buffer-gap-size buf
) 1)
532 (gap-extend buf
100))
533 ;; Move the gap to the point
534 (unless (= (point buf
) (buffer-gap-start buf
))
535 (gap-move-to buf
(buffer-point-aref buf
)))
536 (update-markers-ins buf
(point buf
) 1)
538 (setf (aref (buffer-data buf
) (buffer-gap-start buf
)) char
)
539 ;; move the gap forward
540 (incf (buffer-gap-start buf
))
541 (decf (buffer-gap-size buf
))
542 ;; expand the buffer intervals
543 (offset-intervals buf
(point buf
) 1))
545 (defmethod buffer-insert ((buf buffer
) (string string
))
547 (when (<= (buffer-gap-size buf
) (length string
))
548 (gap-extend buf
(+ (length string
) 100)))
549 ;; move the gap to the point
550 (unless (= (point buf
) (buffer-gap-start buf
))
551 (gap-move-to buf
(buffer-point-aref buf
)))
552 (update-markers-ins buf
(point buf
) (length string
))
554 (replace (buffer-data buf
) string
:start1
(buffer-gap-start buf
))
555 (incf (buffer-gap-start buf
) (length string
))
556 (decf (buffer-gap-size buf
) (length string
))
557 ;; expand the buffer intervals
558 (offset-intervals buf
(point buf
) (length string
)))
560 (defmethod buffer-insert ((buf buffer
) (string pstring
))
562 (buffer-insert buf
(pstring-data string
))
564 (graft-intervals-into-buffer (intervals string
)
566 (pstring-length string
)
570 (defgeneric insert-move-point
(buffer object
)
571 (:documentation
"Insert OBJECT into BUFFER at the current point. Move the point
572 forward by its length."))
574 (defmethod insert-move-point ((buffer buffer
) (object character
))
575 (buffer-insert buffer object
)
576 (incf (marker-position (buffer-point buffer
))))
578 (defmethod insert-move-point ((buffer buffer
) (object string
))
579 (buffer-insert buffer object
)
580 (incf (marker-position (buffer-point buffer
)) (length object
)))
582 (defmethod insert-move-point ((buffer buffer
) (object pstring
))
583 (buffer-insert buffer object
)
584 (incf (marker-position (buffer-point buffer
)) (pstring-length object
)))
586 (defun insert (&rest objects
)
587 "Insert the arguments, either strings or characters, at point.
588 Point and before-insertion markers move forward to end up after the
589 inserted text. Any other markers at the point of insertion remain
592 (insert-move-point (current-buffer) o
)))
594 (defun buffer-delete (buf p length
)
595 "Deletes chars from point to point + n. If N is negative, deletes backwards."
597 (gap-move-to buf
(buffer-char-to-aref buf p
))
598 (let* ((new (max 0 (+ (buffer-gap-start buf
) length
)))
599 (capped-size (- (buffer-gap-start buf
) new
)))
600 (update-markers-del buf new capped-size
)
601 (adjust-intervals-for-deletion buf new capped-size
)
602 (incf (buffer-gap-size buf
) capped-size
)
603 (setf (buffer-gap-start buf
) new
)))
605 (unless (>= p
(zv buf
))
606 ;; can't delete forward if we're at the end of the buffer.
607 (gap-move-to buf
(buffer-char-to-aref buf p
))
608 ;; Make sure the gap size doesn't grow beyond the buffer size.
609 (let ((capped-size (- (min (+ (gap-end buf
) length
)
610 (length (buffer-data buf
)))
612 (incf (buffer-gap-size buf
) capped-size
)
613 (update-markers-del buf p capped-size
)
614 (adjust-intervals-for-deletion buf p capped-size
)))))
615 (setf (buffer-modified buf
) t
)
619 (defun buffer-erase (&optional
(buf (current-buffer)))
621 (adjust-intervals-for-deletion buf
0 (buffer-size buf
))
622 (update-markers-del buf
0 (buffer-size buf
))
623 ;; expand the gap to take up the whole buffer
624 (setf (buffer-gap-start buf
) 0
625 (buffer-gap-size buf
) (length (buffer-data buf
))
626 (marker-position (buffer-point buf
)) 0
627 (buffer-modified buf
) t
)
631 (defun buffer-scan-newline (buf start limit count
)
632 "Search BUF for COUNT newlines with a limiting point at LIMIT,
633 starting at START. Returns the point of the last newline or limit and
634 number of newlines found. START and LIMIT are inclusive."
635 (declare (type buffer buf
)
636 (type integer start limit count
))
637 (labels ((buffer-scan-bk (buf start limit count
)
638 "count is always >=0. start >= limit."
639 (let* ((start-aref (buffer-char-to-aref buf start
))
640 (limit-aref (buffer-char-to-aref buf limit
))
641 (ceiling (if (>= start-aref
(gap-end buf
))
642 (max limit-aref
(gap-end buf
))
645 ;; :END is not inclusive but START is.
646 (start (1+ start-aref
))
649 ;; Always search at least once
650 (setf p
(position #\Newline
(buffer-data buf
)
651 :start ceiling
:end start
:from-end t
))
654 ;; Move start. Note that start isn't set to (1+ p)
655 ;; because we don't want to search p again.
659 ;; Have we found enough newlines?
661 (return-from buffer-scan-bk
(values (buffer-aref-to-char buf p
)
663 ;; Check if we've searched up to the limit
664 (if (= ceiling limit-aref
)
665 (return-from buffer-scan-bk
(values limit i
))
666 ;; if not, skip past the gap
668 (setf ceiling limit-aref
)
669 (setf start
(buffer-gap-start buf
))))))))
670 (buffer-scan-fw (buf start limit count
)
671 "count is always >=0. start >= limit."
672 (let* ((start-aref (buffer-char-to-aref buf start
))
673 (limit-aref (1+ (buffer-char-to-aref buf limit
)))
674 (ceiling (if (< start
(buffer-gap-start buf
))
675 (min limit-aref
(buffer-gap-start buf
))
681 ;; Always search at least once
682 (setf p
(position #\Newline
(buffer-data buf
) :start start
:end ceiling
))
685 ;; Move start. We don't want to search p again, thus the 1+.
689 ;; Have we found enough newlines?
691 (return-from buffer-scan-fw
(values (buffer-aref-to-char buf p
)
693 ;; Check if we've searched up to the limit
694 (if (= ceiling limit-aref
)
695 (return-from buffer-scan-fw
(values limit i
))
696 ;; if not, skip past the gap
698 (setf ceiling limit-aref
)
699 (setf start
(gap-end buf
)))))))))
700 ;; make sure start and limit are within the bounds
701 (setf start
(max 0 (min start
(1- (buffer-size buf
))))
702 limit
(max 0 (min limit
(1- (buffer-size buf
)))))
703 ;; the search always fails on an empty buffer
704 (when (= (buffer-size buf
) 0)
705 (return-from buffer-scan-newline
(values limit
0)))
707 (dformat +debug-vv
+ "scan-fw ~a ~a ~a~%" start limit count
)
708 (buffer-scan-fw buf start limit count
))
710 (dformat +debug-vv
+ "scan-bk ~a ~a ~a~%" start limit count
)
711 (buffer-scan-bk buf start limit
(abs count
)))
712 ;; 0 means the newline before the beginning of the current
713 ;; line. We need to handle the case where we are on a newline.
715 (dformat +debug-vv
+ "scan-0 ~a ~a ~a~%" start limit count
)
716 (if (char= (buffer-char-after buf start
) #\Newline
)
717 (buffer-scan-bk buf start limit
2)
718 (buffer-scan-bk buf start limit
1))))))
722 ;; (defparameter +scratch-buffer+ ";; This buffer is for notes you don't want to save, and for Lisp evaluation.
723 ;; ;; If you want to create a file, visit that file with C-x C-f,
724 ;; ;; then enter the text in that file's own buffer.")
726 ;; (defparameter +other-buf+
727 ;; "678901234567890 abcdefghijklmnopqrstuvwxyz
728 ;; 1 abcdefghijklmnopqrstuvwxyz
729 ;; 2 abcdefghijklmnopqrstuvwxyz
730 ;; 3 abcdefghijklmnopqrstuvwxyz
731 ;; 4 abcdefghijklmnopqrstuvwxyz
732 ;; 5 abcdefghijklmnopqrstuvwxyz
733 ;; 6 abcdefghijklmnopqrstuvwxyz
734 ;; 7 abcdefghijklmnopqrstuvwxyz
735 ;; 8 abcdefghijklmnopqrstuvwxyz")
737 ;; (defun buffer-read-from-stream (buffer stream)
738 ;; "Read the contents of stream until EOF, putting it in buffer-data"
739 ;; (loop for c = (read-char stream nil nil)
741 ;; do (vector-push-extend c (buffer-data buffer))))
743 ;; (defun buffer-read-from-file (buffer file)
744 ;; (with-open-file (s file :direction :input)
745 ;; (buffer-read-from-stream buffer s)))
749 ;; FIXME: this is a parameter for debugging
750 ;; FIXME: be more emacs-like or make it better so we don't just have
751 ;; lambda functions that process data and return a string.
752 (defparameter *mode-line-format
* (list "--:" ;; fake it for hype
755 ;; FIXME: add read-only stuff
756 (if (buffer-modified buffer
)
758 (if (buffer-modified buffer
)
762 (format nil
"~12,,,a" (buffer-name buffer
)))
766 (major-mode-name (buffer-major-mode buffer
)))))
767 "The default mode line format.")
769 (defgeneric mode-line-format-elem
(buffer elem
)
770 (:documentation
"Given the element found in the buffer mode-line,
771 return a string that will be printed in the mode-line."))
773 (defmethod mode-line-format-elem ((b buffer
) (elem string
))
774 "just return the string."
778 (defmethod mode-line-format-elem ((b buffer
) (elem function
))
779 "Call the function. It is expected to return a string."
782 (defmethod mode-line-format-elem ((b buffer
) (elem symbol
))
783 "elem is a symbol, so print its value."
786 (defun update-mode-line (buffer)
787 "Given the buffer, refresh its mode-line string."
788 (setf (buffer-mode-line-string buffer
)
789 (format nil
"~{~a~}" (mapcar (lambda (elem)
790 (mode-line-format-elem buffer elem
))
791 (buffer-mode-line buffer
)))))
793 (defun truncate-mode-line (buffer len
)
794 "return the buffers mode-line trunctated to len. If the mode-line is
795 shorter than len, it will be padded with -'s."
796 (let ((s (make-array len
:element-type
'character
:initial-element
#\-
)))
797 (replace s
(buffer-mode-line-string buffer
))))
799 ;;; Buffer query/creation
801 (defgeneric get-buffer
(name)
802 (:documentation
"Return the buffer named NAME. If there is no live
803 buffer named NAME, return NIL."))
805 (defmethod get-buffer ((name string
))
806 (find name
*buffer-list
* :key
#'buffer-name
:test
#'string
=))
808 (defmethod get-buffer ((buffer buffer
))
809 (find buffer
*buffer-list
*))
811 (defgeneric get-buffer-create
(name)
812 (:documentation
"Return the buffer named NAME, or create such a buffer and return it.
813 A new buffer is created if there is no live buffer named NAME.
814 If NAME starts with a space, the new buffer does not keep undo information.
815 If NAME is a buffer instead of a string, then it is the value returned.
816 The value is never nil."))
818 (defmethod get-buffer-create ((name string
))
822 (when (zerop (length name
))
823 (error "Empty string for buffer name is not allowed"))
824 (let ((b (make-instance 'buffer
828 ;; Currently a buffer has to have a gap
829 ;; of at least size 1.
830 :data
(string-to-vector "_")
833 :mode-line
*mode-line-format
*
835 :major-mode fundamental-mode
)))
836 (set-marker (buffer-point b
) 0 b
)
837 (set-marker (mark-marker b
) 0 b
)
838 (push b
*buffer-list
*)
841 (defmethod get-buffer-create ((buffer buffer
))
846 (defun make-default-buffers ()
847 "Called on startup. Create the default buffers, putting them in
849 ;; for the side effect
850 (get-buffer-create "*messages*")
851 (let ((scratch (get-buffer-create "*scratch*")))
852 (buffer-insert scratch
";; This buffer is for notes you don't want to save, and for Lisp evaluation.
853 ;; If you want to create a file, visit that file with C-x C-f,
854 ;; then enter the text in that file's own buffer.")
855 ;; FIXME: is this a hack?
856 (setf (buffer-modified scratch
) nil
)
857 (goto-char (point-min scratch
) scratch
)))
861 (defun generate-new-buffer-name (name &optional ignore
)
862 "Return a string that is the name of no existing buffer based on NAME.
863 If there is no live buffer named NAME, then return NAME.
864 Otherwise modify name by appending `<NUMBER>', incrementing NUMBER
865 until an unused name is found, and then return that name.
866 Optional second argument IGNORE specifies a name that is okay to use
867 (if it is in the sequence to be tried)
868 even if a buffer with that name exists."
869 (declare (type string name
)
870 (type (or string null
) ignore
))
871 (or (unless (get-buffer name
)
873 (loop for count from
1
874 ;; FIXME: there's gotta be a way to do this where s isn't
877 do
(setf s
(format nil
"~a<~d>" name count
))
881 unless
(get-buffer s
)
884 (defmacro with-current-buffer
(buffer &body body
)
885 "Execute the forms in BODY with BUFFER as the current buffer.
886 The value returned is the value of the last form in BODY.
887 See also `with-temp-buffer'."
888 (let ((bk (gensym "BK")))
890 (let ((,bk
*current-buffer
*))
894 (set-buffer ,bk
))))))
896 (defmacro with-temp-buffer
(&body body
)
897 "Create a temporary buffer, and evaluate BODY there like `progn'.
898 See also `with-temp-file'."
899 (let ((temp-buffer (gensym "TEMP-BUFFER")))
900 `(let ((,temp-buffer
(get-buffer-create (generate-new-buffer-name "*temp*"))))
902 (with-current-buffer ,temp-buffer
904 (and (get-buffer ,temp-buffer
)
905 (kill-buffer ,temp-buffer
))))))
907 (defun bring-buffer-to-front (buf)
908 "Put buf at the front of *buffer-list*. Assumes BUF is in
910 (setf *buffer-list
* (delete buf
*buffer-list
*))
911 (push buf
*buffer-list
*))
913 (defun other-buffer (&optional
(buffer (current-buffer)) visible-ok frame
)
914 "Return most recently selected buffer other than BUFFER.
915 Buffers not visible in windows are preferred to visible buffers,
916 unless optional second argument VISIBLE-OK is non-nil.
917 If the optional third argument FRAME is non-nil, use that frame's
918 buffer list instead of the selected frame's buffer list.
919 If no other buffer exists, the buffer `*scratch*' is returned.
920 If BUFFER is omitted or nil, some interesting buffer is returned."
921 (declare (ignore frame
))
922 ;; TODO: honour FRAME argument
924 (match (loop for b in
*buffer-list
*
925 unless
(or (eq b buffer
)
926 (char= (char (buffer-name b
) 0) #\Space
))
927 if
(and (not visible-ok
)
928 (get-buffer-window b
))
933 (get-buffer-create "*scratch*"))))
935 (defun mark (&optional force
(buffer (current-buffer)))
936 "Return BUFFER's mark value as integer; error if mark inactive.
937 If optional argument FORCE is non-nil, access the mark value
938 even if the mark is not currently active, and return nil
939 if there is no mark at all."
940 (declare (ignore force
))
941 ;; FIXME: marks can't be inactive ATM
942 (marker-position (mark-marker buffer
)))
944 (defun validate-region (start end
&optional
(buffer (current-buffer)))
945 "Return a value pair of start and end for buffer. the 1st value
946 returned will always be <= the second. May raise an args out of range
949 If START or END are marks, their positions will be used."
950 (when (typep start
'marker
)
951 (setf start
(marker-position start
)))
952 (when (typep end
'marker
)
953 (setf end
(marker-position end
)))
955 ;; MOVITZ doesn't have psetf
962 (when (or (< start
(buffer-min buffer
))
963 (> end
(buffer-max buffer
)))
964 (signal 'args-out-of-range
))
967 (defun eobp (&optional
(buffer (current-buffer)))
968 "Return T when the point is at the end of the buffer."
969 (= (buffer-max buffer
) (point)))
971 (defun bobp (&optional
(buffer (current-buffer)))
972 "Return T when the point is at the beginning of the buffer."
973 (= (buffer-min buffer
) (point)))
975 (defun set-buffer (buffer)
976 "Make the buffer BUFFER current for editing operations.
977 BUFFER may be a buffer or the name of an existing buffer.
978 See also `save-excursion' when you want to make a buffer current temporarily.
979 This function does not display the buffer, so its effect ends
980 when the current command terminates.
981 Use `switch-to-buffer' or `pop-to-buffer' to switch buffers permanently."
982 (setf buffer
(get-buffer buffer
))
985 (when *current-buffer
*
986 (record-local-variables *current-buffer
*))
987 (set-local-variables buffer
)
988 (setf *current-buffer
* buffer
))
989 (error "No buffer named ~s" buffer
)))
991 (defun record-buffer (buffer)
992 "**Move the assoc for buffer BUF to the front of buffer-alist.
993 Since we do this each time BUF is selected visibly, the more recently
994 selected buffers are always closer to the front of the list. This
995 means that other_buffer is more likely to choose a relevant buffer."
996 (setf *buffer-list
* (delete buffer
*buffer-list
* :test
#'eq
))
997 (push buffer
*buffer-list
*))
999 (defun barf-if-buffer-read-only ()
1000 "Signal a `buffer-read-only' error if the current buffer is read-only."
1001 (when (buffer-read-only (current-buffer))
1002 (signal 'buffer-read-only
)))
1004 (defun bufferp (object)
1005 "Return t if object is an editor buffer."
1006 (typep object
'buffer
))
1008 (define-buffer-local :default-directory
(truename "")
1009 "Name of default directory of current buffer.
1010 To interactively change the default directory, use command `cd'.")
1012 (defstruct local-variable-binding
1015 (defun make-local-variable (symbol)
1016 "Make variable have a separate value in the current buffer.
1017 Other buffers will continue to share a common default value.
1018 (The buffer-local value of variable starts out as the same value
1019 variable previously had.)
1021 (setf (gethash symbol
(buffer-local-variables (current-buffer)))
1022 (make-local-variable-binding :value
(symbol-value symbol
)))
1025 (defun record-local-variables (buffer)
1026 "Update the values BUFFER's local variables."
1027 (labels ((update (k v
)
1029 (setf (local-variable-binding-value v
) (symbol-value k
)
1030 (symbol-value k
) (local-variable-binding-backup v
))
1031 (remhash k
(buffer-local-variables buffer
)))))
1032 (maphash #'update
(buffer-local-variables buffer
))))
1034 (defun set-local-variables (buffer)
1035 "Set all variables to the buffer local value."
1036 (labels ((set-it (k v
)
1038 (setf (local-variable-binding-backup v
) (symbol-value k
)
1039 (symbol-value k
) (local-variable-binding-value v
))
1040 (remhash k
(buffer-local-variables buffer
)))))
1041 (maphash #'set-it
(buffer-local-variables buffer
))))
1043 ;;; reading from the buffer
1045 (defun read-from-buffer (&aux
(buffer (current-buffer)))
1046 "Read 1 sexp from the buffer at the current point, moving the point to the end of what was read"
1047 (when (< (buffer-char-to-aref buffer
(point buffer
))
1048 (buffer-gap-start buffer
))
1049 (gap-move-to-point buffer
))
1050 (multiple-value-bind (obj pos
)
1051 (read-from-string (buffer-data buffer
) t nil
1052 :start
(buffer-char-to-aref buffer
(point buffer
)))
1053 (set-point (buffer-aref-to-char buffer pos
))
1056 (provide :lice-0.1
/buffer
)