123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733 |
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Text-Buffer.SL
- %
- % Author: Alan Snyder
- % Hewlett-Packard/CRC
- % Date: 20 August 1982
- % Revised: 23 February 1983
- %
- % A text buffer. Supports the primitive editing functions. The strings in a
- % text buffer are never modified. This allows EQ to be used to minimize
- % redisplay.
- %
- % 23-Feb-83 Alan Snyder
- % Revise stream operations to work with any type of object.
- % 15-Feb-83 Alan Snyder
- % Revise insertion code to reduce unnecessary consing.
- % Remove char-blank? macro (NMODE has a function char-blank?).
- % 19-Jan-83 Jeff Soreff
- % Name made settable in text buffer.
- % 3-Dec-82 Alan Snyder
- % Added cleanup method.
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (BothTimes (load objects))
- (CompileTime (load fast-int fast-vectors fast-strings))
-
- (de create-text-buffer (name) % not for direct use in NMODE
- (let ((buffer (make-instance 'text-buffer 'name name)))
- buffer))
- (defflavor text-buffer (
- (last-line 0) % index of last line in buffer (n >= 0)
- (line-pos 0) % index of "current" line (0 <= n <= last-line)
- (char-pos 0) % index of "current" character in current line
- % (0 <= n <= linelength)
- lines % vector of strings
- name % string name of buffer
- (file-name NIL) % string name of attached file (or NIL)
- (modified? NIL) % T => buffer is different than file
- marks % ring buffer of marks
- (mode NIL) % the buffer's Mode
- (previous-buffer NIL) % (optional) previous buffer
- (p-list NIL) % association list of properties
- )
- ()
- (gettable-instance-variables line-pos char-pos)
- (settable-instance-variables file-name modified? mode previous-buffer name)
- (initable-instance-variables name)
- )
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Private Macros:
- (CompileTime (progn
- (defmacro with-current-line ((var) . forms)
- `(let ((,var (vector-fetch lines line-pos)))
- ,@forms
- ))
- (defmacro with-current-line ((var) . forms) % avoid compiler bug!
- `(let ((**LINES** lines))
- (let ((,var (vector-fetch **LINES** line-pos)))
- ,@forms
- )))
- (defmacro with-current-line-copied ((var) . forms)
- `(let ((**LINES** lines) (**LINE-POS** line-pos))
- (let ((,var (copystring (vector-fetch **LINES** **line-pos**))))
- (vector-store **LINES** **line-pos** ,var)
- ,@forms
- )))
- )) % End of CompileTime
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (defmethod (text-buffer position) ()
- % Return the "current position" in the buffer as a BUFFER-POSITION object.
- (buffer-position-create line-pos char-pos)
- )
- (defmethod (text-buffer set-position) (bp)
- % Set the "current position" in the buffer from the specified
- % BUFFER-POSITION object. Clips the line-position and char-position.
- (=> self goto (buffer-position-line bp) (buffer-position-column bp))
- )
- (defmethod (text-buffer buffer-end-position) ()
- % Return the BUFFER-POSITION object corresponding to the end of the buffer.
- (buffer-position-create
- last-line
- (string-length (vector-fetch lines last-line))
- ))
- (defmethod (text-buffer goto) (lpos cpos)
- % Set the "current position" in the buffer. Clips the line-position and
- % char-position.
- (if (< lpos 0) (setf lpos 0))
- (if (> lpos last-line) (setf lpos last-line))
- (setf line-pos lpos)
- (=> self set-char-pos cpos)
- )
- (defmethod (text-buffer set-line-pos) (lpos)
- % Set the "current line position" in the buffer. Clips the line-position
- % and char-position.
- (when (~= lpos line-pos)
- (if (< lpos 0) (setf lpos 0))
- (if (> lpos last-line) (setf lpos last-line))
- (setf line-pos lpos)
- (with-current-line (l)
- (if (> char-pos (string-length l))
- (setf char-pos (string-length l))
- ))
- ))
- (defmethod (text-buffer set-char-pos) (cpos)
- % Set the "current character position" in the buffer. Clips the specified
- % position to lie in the range 0..line-length.
- (if (< cpos 0) (setf cpos 0))
- (with-current-line (l)
- (if (> cpos (string-length l))
- (setf cpos (string-length l))
- ))
- (setf char-pos cpos)
- )
- (defmethod (text-buffer clip-position) (bp)
- % Return BP if BP is a valid position for this buffer, otherwise return a new
- % buffer-position with clipped values.
- (let ((lpos (buffer-position-line bp))
- (cpos (buffer-position-column bp))
- (clipped NIL)
- )
- (cond ((< lpos 0) (setf lpos 0) (setf clipped T))
- ((> lpos last-line) (setf lpos last-line) (setf clipped T))
- )
- (cond ((< cpos 0) (setf cpos 0) (setf clipped T))
- ((> cpos (string-length (vector-fetch lines lpos)))
- (setf cpos (string-length (vector-fetch lines lpos)))
- (setf clipped T)
- ))
- (if clipped
- (buffer-position-create lpos cpos)
- bp
- )))
- (defmethod (text-buffer size) ()
- % Return the actual size of the buffer (number of lines). This number will
- % include the "fake" empty line at the end of the buffer, should it exist.
- (+ last-line 1)
- )
- (defmethod (text-buffer visible-size) ()
- % Return the apparent size of the buffer (number of lines). This number
- % will NOT include the "fake" empty line at the end of the buffer, should it
- % exist.
- (if (>= (string-upper-bound (vector-fetch lines last-line)) 0)
- (+ last-line 1) % The last line is real!
- last-line % The last line is fake!
- ))
- (defmethod (text-buffer contents) ()
- % Return the text contents of the buffer (a copy thereof) as a vector of
- % strings (the last string is implicitly without a terminating NewLine).
- (sub lines 0 last-line)
- )
- (defmethod (text-buffer current-line) ()
- % Return the current line (as a string).
- (with-current-line (l)
- l))
- (defmethod (text-buffer fetch-line) (n)
- % Fetch the specified line (as a string). Lines are indexed from 0.
- (if (or (< n 0) (> n last-line))
- (ContinuableError
- 0
- (BldMsg "Line index %w out of range." n)
- "")
- (vector-fetch lines n)
- ))
- (defmethod (text-buffer store-line) (n new-line)
- % Replace the specified line with a new string.
- (if (or (< n 0) (> n last-line))
- (ContinuableError
- 0
- (BldMsg "Line index %w out of range." n)
- "")
- % else
- (setf modified? T)
- (vector-store lines n new-line)
- (if (= line-pos n)
- (let ((len (string-length new-line)))
- (if (> char-pos len)
- (setf char-pos len)
- )))
- ))
- (defmethod (text-buffer select) ()
- % Attach the buffer to the current window, making it the current buffer.
- (buffer-select self)
- )
- (defmethod (text-buffer set-mark) (bp)
- % PUSH the specified position onto the ring buffer of marks.
- % The specified position thus becomes the current "mark".
- (ring-buffer-push marks bp)
- )
- (defmethod (text-buffer set-mark-from-point) ()
- % PUSH the current position onto the ring buffer of marks.
- % The current position thus becomes the current "mark".
- (ring-buffer-push marks (buffer-position-create line-pos char-pos))
- )
- (defmethod (text-buffer mark) ()
- % Return the current "mark".
- (ring-buffer-top marks)
- )
- (defmethod (text-buffer previous-mark) ()
- % POP the current mark off the ring buffer of marks.
- % Return the new current mark.
- (ring-buffer-pop marks)
- (ring-buffer-top marks)
- )
- (defmethod (text-buffer get) (property-name)
- % Return the object associated with the specified property name (ID).
- % Returns NIL if named property has not been defined.
- (let ((pair (atsoc property-name p-list)))
- (if (PairP pair) (cdr pair))))
- (defmethod (text-buffer put) (property-name property)
- % Associate the specified object with the specified property name (ID).
- % GET on that property-name will henceforth return the object.
- (let ((pair (atsoc property-name p-list)))
- (if (PairP pair)
- (rplacd pair property)
- (setf p-list (cons (cons property-name property) p-list))
- )))
- (defmethod (text-buffer reset) ()
- % Reset the contents of the buffer to empty and "not modified".
- (setf lines (MkVect 1))
- (vector-store lines 0 "")
- (setf last-line 0)
- (setf line-pos 0)
- (setf char-pos 0)
- (setf modified? NIL)
- )
- (defmethod (text-buffer extract-region) (delete-it bp1 bp2)
- % Delete (if delete-it is non-NIL) or copy (otherwise) the text between
- % position BP1 and position BP2. Return the deleted (or copied) text as a
- % pair (CONS direction-of-deletion vector-of-strings). The returned
- % direction is +1 if BP1 <= BP2, and -1 otherwise. The current position is
- % set to the beginning of the region if deletion is performed.
- (setf bp1 (=> self clip-position bp1))
- (setf bp2 (=> self clip-position bp2))
- (prog (dir text text-last l1 c1 l2 c2 line1 line2)
- (setf dir 1) % the default case
- % ensure that BP1 is not beyond BP2
- (let ((comparison (buffer-position-compare bp1 bp2)))
- (if (> comparison 0)
- (psetq dir -1 bp1 bp2 bp2 bp1))
- (if (and delete-it (~= comparison 0))
- (setf modified? T))
- )
- (setf l1 (buffer-position-line bp1))
- (setf c1 (buffer-position-column bp1))
- (setf l2 (buffer-position-line bp2))
- (setf c2 (buffer-position-column bp2))
- % Ensure the continued validity of the current position.
- (if delete-it (=> self set-position bp1))
- % Create a vector for the extracted text.
- (setf text-last (- l2 l1)) % highest index in TEXT vector
- (setf text (MkVect text-last))
- (setf line1 (vector-fetch lines l1)) % first line (partially) in region
- (cond
- ((= l1 l2) % region lies within a single line (easy!)
- (vector-store text 0 (substring line1 c1 c2))
- (if delete-it
- (vector-store lines l1 (string-concat
- (substring line1 0 c1)
- (string-rest line1 c2)
- )))
- (return (cons dir text))))
- % Here if region spans multiple lines.
- (setf line2 (vector-fetch lines l2)) % last line (partially) in region
- (vector-store text 0 (string-rest line1 c1))
- (vector-store text text-last (substring line2 0 c2))
- % Copy remaining text from region.
- (for (from i 1 (- text-last 1))
- (do (vector-store text i (vector-fetch lines (+ l1 i)))))
- (when delete-it
- (vector-store lines l1 (string-concat
- (substring line1 0 c1)
- (string-rest line2 c2)))
- (=> self &delete-lines (+ l1 1) text-last)
- )
- (return (cons dir text))
- ))
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % The following methods are not really primitive, but are provided as
- % a public service.
- (defmethod (text-buffer current-line-length) ()
- % Return the number of characters in the current line.
- (with-current-line (l)
- (string-length l)))
- (defmethod (text-buffer current-line-empty?) ()
- % Return T if the current line contains no characters.
- (with-current-line (l)
- (string-empty? l)))
- (defmethod (text-buffer current-line-blank?) ()
- % Return T if the current line contains no non-blank characters.
- (with-current-line (l)
- (for (from i 0 (string-upper-bound l))
- (always (char-blank? (string-fetch l i)))
- )))
- (defmethod (text-buffer at-line-start?) ()
- % Return T if we are positioned at the start of the current line.
- (= char-pos 0))
- (defmethod (text-buffer at-line-end?) ()
- % Return T if we are positioned at the end of the current line.
- (with-current-line (l)
- (> char-pos (string-upper-bound l))))
- (defmethod (text-buffer at-buffer-start?) ()
- % Return T if we are positioned at the start of the buffer.
- (and (= line-pos 0) (= char-pos 0)))
- (defmethod (text-buffer at-buffer-end?) ()
- % Return T if we are positioned at the end of the buffer.
- (and
- (>= line-pos last-line)
- (> char-pos (string-upper-bound (vector-fetch lines last-line)))))
- (defmethod (text-buffer current-line-is-first?) ()
- % Return T if the current line is the first line in the buffer.
- (= line-pos 0))
- (defmethod (text-buffer current-line-is-last?) ()
- % Return T if the current line is the last line in the buffer.
- (>= line-pos last-line))
- (defmethod (text-buffer current-line-fetch) (n)
- % Return the character at character position N within the current line.
- % An error is generated if N is out of range.
- (with-current-line (l)
- (if (and (>= n 0) (<= n (string-upper-bound l)))
- (string-fetch l n)
- (ContinuableError
- 0
- (BldMsg "Character index %w out of range." n)
- "")
- )))
- (defmethod (text-buffer current-line-store) (n c)
- % Store the character C at char position N within the current line.
- % An error is generated if N is out of range.
- (with-current-line-copied (l)
- (if (and (>= n 0) (<= n (string-upper-bound l)))
- (progn
- (string-store l n c)
- (vector-store lines line-pos l)
- (setf modified? T)
- )
- (ContinuableError
- 0
- (BldMsg "Character index %w out of range." n)
- "")
- )))
- (defmethod (text-buffer move-to-buffer-start) ()
- % Move to the beginning of the buffer.
- (setf line-pos 0)
- (setf char-pos 0)
- )
- (defmethod (text-buffer move-to-buffer-end) ()
- % Move to the end of the buffer.
- (setf line-pos last-line)
- (with-current-line (l)
- (setf char-pos (string-length l)))
- )
- (defmethod (text-buffer move-to-start-of-line) ()
- % Move to the beginning of the current line.
- (setf char-pos 0))
- (defmethod (text-buffer move-to-end-of-line) ()
- % Move to the end of the current line.
- (with-current-line (l)
- (setf char-pos (string-length l))))
- (defmethod (text-buffer move-to-next-line) ()
- % Move to the beginning of the next line.
- % If already at the last line, move to the end of the line.
- (cond ((< line-pos last-line)
- (setf line-pos (+ line-pos 1))
- (setf char-pos 0))
- (t (=> self move-to-end-of-line))))
- (defmethod (text-buffer move-to-previous-line) ()
- % Move to the beginning of the previous line.
- % If already at the first line, move to the beginning of the line.
- (if (> line-pos 0)
- (setf line-pos (- line-pos 1)))
- (setf char-pos 0))
- (defmethod (text-buffer move-forward) ()
- % Move to the next character in the current buffer.
- % Do nothing if already at the end of the buffer.
- (if (=> self at-line-end?)
- (=> self move-to-next-line)
- (setf char-pos (+ char-pos 1))
- ))
- (defmethod (text-buffer move-backward) ()
- % Move to the previous character in the current buffer.
- % Do nothing if already at the start of the buffer.
- (if (> char-pos 0)
- (setf char-pos (- char-pos 1))
- (when (> line-pos 0)
- (setf line-pos (- line-pos 1))
- (=> self move-to-end-of-line)
- )))
- (defmethod (text-buffer next-character) ()
- % Return the character to the right of the current position.
- % Return NIL if at the end of the buffer.
- (with-current-line (l)
- (if (>= char-pos (string-length l))
- (if (= line-pos last-line)
- NIL
- (char EOL)
- )
- (string-fetch l char-pos)
- )))
- (defmethod (text-buffer previous-character) ()
- % Return the character to the left of the current position.
- % Return NIL if at the beginning of the buffer.
- (if (= char-pos 0)
- (if (= line-pos 0) NIL #\EOL)
- (with-current-line (l)
- (string-fetch l (- char-pos 1)))
- ))
- (defmethod (text-buffer insert-character) (c)
- % Insert character C at the current position in the buffer and advance past
- % that character. Implementation note: some effort is made here to avoid
- % unnecessary consing.
- (if (= c #\EOL)
- (=> self insert-eol)
- % else
- (with-current-line (l)
- (let* ((current-length (string-length l))
- (head-string
- (when (> char-pos 0)
- (if (= char-pos current-length) l (substring l 0 char-pos))))
- (tail-string
- (when (< char-pos current-length)
- (if (= char-pos 0) l (substring l char-pos current-length))))
- (s (string c))
- )
- (when head-string (setf s (string-concat head-string s)))
- (when tail-string (setf s (string-concat s tail-string)))
- (vector-store lines line-pos s)
- (setf char-pos (+ char-pos 1))
- (setf modified? T)
- ))))
- (defmethod (text-buffer insert-eol) ()
- % Insert a line-break at the current position in the buffer and advance to
- % the beginning of the newly-formed line. Implementation note: some effort
- % is made here to avoid unnecessary consing.
- (with-current-line (l)
- (=> self &insert-gap line-pos 1)
- (let* ((current-length (string-length l))
- (head-string
- (when (> char-pos 0)
- (if (= char-pos current-length) l (substring l 0 char-pos))))
- (tail-string
- (when (< char-pos current-length)
- (if (= char-pos 0) l (substring l char-pos current-length))))
- )
- (vector-store lines line-pos (or head-string ""))
- (setf line-pos (+ line-pos 1))
- (vector-store lines line-pos (or tail-string ""))
- (setf char-pos 0)
- (setf modified? T)
- )))
- (defmethod (text-buffer insert-line) (l)
- % Insert the specified string as a new line in front of the current line.
- % Advance past the newly inserted line. Note: L henceforth must never be
- % modified.
- (=> self &insert-gap line-pos 1)
- (vector-store lines line-pos l)
- (setf line-pos (+ line-pos 1))
- (setf modified? T)
- )
- (defmethod (text-buffer insert-string) (s)
- % Insert the string S at the current position. Advance past the
- % newly-inserted string. Note: S must not contain EOL characters! Note: S
- % henceforth must never be modified. Implementation note: some effort is
- % made here to avoid unnecessary consing.
- (let ((insert-length (string-length s)))
- (when (> insert-length 0)
- (with-current-line (l)
- (let* ((current-length (string-length l))
- (head-string
- (when (> char-pos 0)
- (if (= char-pos current-length) l (substring l 0 char-pos))))
- (tail-string
- (when (< char-pos current-length)
- (if (= char-pos 0) l (substring l char-pos current-length))))
- )
- (when head-string (setf s (string-concat head-string s)))
- (when tail-string (setf s (string-concat s tail-string)))
- (vector-store lines line-pos s)
- (setf char-pos (+ char-pos insert-length))
- (setf modified? T)
- )))))
- (defmethod (text-buffer insert-text) (v)
- % V is a vector of strings similar to LINES (e.g., the last string in V is
- % considered to be an unterminated line). Thus, V must have at least one
- % element. Insert this stuff at the current position and advance past it.
- (with-current-line (l)
- (let ((v-last (vector-upper-bound v)))
- (=> self &insert-gap line-pos v-last)
- (let ((vec lines)
- (prefix-text (substring l 0 char-pos))
- (suffix-text (string-rest l char-pos))
- )
- (vector-store vec line-pos
- (string-concat prefix-text (vector-fetch v 0)))
- (for (from i 1 v-last)
- (do (setf line-pos (+ line-pos 1))
- (vector-store vec line-pos (vector-fetch v i))))
- (setf char-pos (string-length (vector-fetch vec line-pos)))
- (vector-store vec line-pos
- (string-concat (vector-fetch vec line-pos) suffix-text))
- (setf modified? T)
- ))))
- (defmethod (text-buffer delete-next-character) ()
- % Delete the next character.
- % Do nothing if at the end of the buffer.
- (with-current-line (l)
- (if (= char-pos (string-length l))
- (if (= line-pos last-line)
- NIL
- % else (at end of line other than last)
- (vector-store lines line-pos
- (string-concat l (vector-fetch lines (+ line-pos 1))))
- (=> self &delete-lines (+ line-pos 1) 1)
- (setf modified? T)
- )
- % else (not at the end of a line)
- (vector-store lines line-pos
- (string-concat
- (substring l 0 char-pos)
- (string-rest l (+ char-pos 1))
- ))
- (setf modified? T)
- )))
- (defmethod (text-buffer delete-previous-character) ()
- % Delete the previous character.
- % Do nothing if at the beginning of the buffer.
- (if (not (=> self at-buffer-start?))
- (progn
- (=> self move-backward)
- (=> self delete-next-character)
- (setf modified? T)
- )))
- % Implementation note: On the 9836, the following implementation of the
- % read-from-stream method using GETC is slightly slower than a much simpler
- % implementation of read-from-stream using GETL (although the GETL method is
- % highly optimized). For a file with 874 lines, using GETC took 7480 ms vs.
- % 7130 ms. when using GETL. The problem with GETL, however, is that it does
- % not report whether the last line of the file is terminated with a Newline or
- % not. This functional difference could conceivably be important. Luckily,
- % the improvement in speed is sufficiently small to be irrelevant.
- (defmethod (text-buffer read-from-stream) (s)
- (=> self reset)
- (let* ((line-buffer (make-string 200 0))
- (buffer-top 200)
- (getc-method (object-get-handler s 'getc))
- line-size
- ch
- )
- (while T
- (setf line-size 0)
- (setf ch (apply getc-method (list s)))
- (while (not (or (null ch) (= ch #\LF)))
- (cond ((>= line-size buffer-top)
- (setf line-buffer (concat line-buffer (make-string 200 0)))
- (setf buffer-top (+ buffer-top 200))
- ))
- (string-store line-buffer line-size ch)
- (setf line-size (+ line-size 1))
- (setf ch (apply getc-method (list s)))
- )
- (if (not (and (null ch) (= line-size 0)))
- (=> self insert-line (sub line-buffer 0 (- line-size 1)))
- )
- (when (null ch)
- (if (> line-size 0) (=> self delete-previous-character))
- (exit)
- ))
- (=> self move-to-buffer-start)
- (=> self set-modified? NIL)
- ))
- (defmethod (text-buffer write-to-stream) (s)
- (let* ((vec lines)
- (putl-method (object-get-handler s 'putl))
- )
- (for (from i 0 (- last-line 1))
- (do (apply putl-method (list s (vector-fetch vec i)))))
- (=> s puts (vector-fetch vec last-line))
- ))
- (defmethod (text-buffer cleanup) ()
- % Discard any unused storage.
- (if (and previous-buffer (not (buffer-is-selectable? previous-buffer)))
- (setf previous-buffer NIL))
- (TruncateVector lines last-line)
- )
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Private methods:
- (defmethod (text-buffer init) (init-plist)
- (setf lines (MkVect 0))
- (vector-store lines 0 "")
- (setf marks (ring-buffer-create 16))
- (ring-buffer-push marks (buffer-position-create 0 0))
- )
- (defmethod (text-buffer &insert-gap) (lpos n-lines)
- % Insert N-LINES lines at position LPOS, moving the remaining lines upward
- % (if any). LPOS may range from 0 (insert at beginning of buffer) to
- % LAST-LINE + 1 (insert at end of buffer). The new lines are not
- % specifically initialized (they retain their old values).
- (when (> n-lines 0)
- (=> self &ensure-room n-lines)
- (let ((vec lines))
- (for (from i last-line lpos -1)
- (do (vector-store vec (+ i n-lines) (vector-fetch vec i)))
- )
- (setf last-line (+ last-line n-lines))
- )))
- (defmethod (text-buffer &ensure-room) (lines-needed)
- % Ensure that the LINES vector is large enough to add the specified number
- % of additional lines.
- (let* ((current-bound (vector-upper-bound lines))
- (lines-available (- current-bound last-line))
- (lines-to-add (- lines-needed lines-available))
- )
- (when (> lines-to-add 0)
- (let ((minimum-incr (>> current-bound 2))) % Increase by at least 25%
- (if (< minimum-incr 64) (setf minimum-incr 64))
- (if (< lines-to-add minimum-incr) (setf lines-to-add minimum-incr))
- )
- (let ((new-lines (make-vector (+ current-bound lines-to-add) NIL)))
- (for (from i 0 current-bound)
- (do (vector-store new-lines i (vector-fetch lines i))))
- (setf lines new-lines)
- ))))
- (defmethod (text-buffer &delete-lines) (lpos n-lines)
- % Remove N-LINES lines starting at position LPOS, moving the remaining lines
- % downward (if any) and NILing out the obsoleted lines at the end of the
- % LINES vector (to allow the strings to be reclaimed). LPOS may range from
- % 0 to LAST-LINE.
- (when (> n-lines 0)
- (let ((vec lines))
- (for (from i (+ lpos n-lines) last-line)
- (do (vector-store vec (- i n-lines) (vector-fetch vec i)))
- )
- (setf last-line (- last-line n-lines))
- (for (from i 1 n-lines)
- (do (vector-store vec (+ last-line i) NIL))
- )
- )))
|