[lice @ massive rearrangement to get rid of compiler warnings and mimic the file...
[lice.git] / simple.lisp
blob158a8f086e5f25ca5cc41800a25241b795aa2a16
1 (in-package "LICE")
3 (defvar *kill-ring* nil
4 "The kill ring.")
6 (defvar *kill-ring-max* 60
7 "Maximum length of kill ring before oldest elements are thrown away.")
9 (defvar *kill-ring-yank-pointer* nil
10 "The tail of the kill ring whose car is the last thing yanked.")
12 (defcustom *eval-expression-print-level* 4
13 "Value for `print-level' while printing value in `eval-expression'.
14 A value of nil means no limit."
15 :group 'lisp
16 :type '(choice (const :tag "No Limit" nil) integer)
17 :version "21.1")
19 (defcustom *eval-expression-print-length* 12
20 "Value for `print-length' while printing value in `eval-expression'.
21 A value of nil means no limit."
22 :group 'lisp
23 :type '(choice (const :tag "No Limit" nil) integer)
24 :version "21.1")
26 (defcustom *eval-expression-debug-on-error* t
27 "If non-nil set `debug-on-error' to t in `eval-expression'.
28 If nil, don't change the value of `debug-on-error'."
29 :group 'lisp
30 :type 'boolean
31 :version "21.1")
33 (define-condition kill-ring-empty (lice-condition)
34 () (:documentation "Raised when a yank is attempted but the kill ring is empty"))
36 ;; (when (or (and (< n 0)
37 ;; (< (point (current-buffer)) 0))
38 ;; (> (point (current-buffer))
39 ;; (point-max)))
40 ;; (decf (marker-position (buffer-point (current-buffer))) n))
44 (defun buffer-beginning-of-line ()
45 "Return the point in the buffer that is the beginning of the line that P is on."
46 (if (or (not (char-before))
47 (char= (char-before) #\Newline))
48 (point)
49 (let ((bol (buffer-scan-newline (current-buffer) (point) 0 0)))
50 (if (and (char= (char-after bol) #\Newline)
51 (< bol (1- (buffer-size (current-buffer)))))
52 (1+ bol)
53 bol))))
55 (defun buffer-end-of-line ()
56 "Return the point in the buffer that is the end of the line that P is on."
57 (if (or (not (char-after))
58 (char= (char-after) #\Newline))
59 (point)
60 (let ((eol (buffer-scan-newline (current-buffer) (point) (1- (buffer-size (current-buffer))) 1)))
61 ;; XXX: a bit of a kludge. if the eol char isn't a newline then it
62 ;; has to be the end of the buffer, so advance the point by one,
63 ;; which is the actual end of the line.
64 (if (char= (char-after eol) #\Newline)
65 eol
66 (1+ eol)))))
68 (defcommand newline ((&optional n)
69 :prefix)
70 "Insert N new lines."
71 (insert-move-point (current-buffer) (make-string (or n 1) :initial-element #\Newline)))
73 (defcommand open-line ((n) :prefix)
74 "Insert a newline and leave point before it.
75 **If there is a fill prefix and/or a left-margin, insert them on the new line
76 **if the line would have been blank.
77 With arg N, insert N newlines."
78 (let ((loc (point)))
79 (dotimes (i n) (newline 1))
80 (goto-char loc)))
82 (defcommand next-line ((&optional (arg 1))
83 :prefix)
84 "Move cursor vertically down N lines."
85 (let ((col (current-column)))
86 (forward-line arg)
87 (if (<= col (- (buffer-end-of-line) (point)))
88 (goto-char (+ (point) col))
89 (goto-char (buffer-end-of-line)))))
91 (defcommand previous-line ((&optional (arg 1))
92 :prefix)
93 "Move cursor vertically up N lines."
94 (let ((col (current-column)))
95 ;; FIXME: this is all fucked
96 (forward-line (- arg))
97 ;;(forward-line 0)
98 ;;(backward-char 1)
99 ;;(forward-line 0)
100 (if (<= col (- (buffer-end-of-line) (point)))
101 (goto-char (+ (point) col))
102 (goto-char (buffer-end-of-line)))))
104 (defun line-move-invisible-p (pos)
105 "Return non-nil if the character after POS is currently invisible."
106 (let ((prop
107 (get-char-property pos 'invisible)))
108 (if (eq *buffer-invisibility-spec* t)
109 prop
110 (or (find prop *buffer-invisibility-spec*)
111 (assoc prop (remove-if 'listp *buffer-invisibility-spec*))))))
113 (defcustom track-eol nil
114 "*Non-nil means vertical motion starting at end of line keeps to ends of lines.
115 This means moving to the end of each line moved onto.
116 The beginning of a blank line does not count as the end of a line."
117 :type 'boolean
118 :group 'editing-basics)
120 (defcustom *line-move-ignore-invisible* t
121 "*Non-nil means \\[next-line] and \\[previous-line] ignore invisible lines.
122 Outline mode sets this."
123 :type 'boolean
124 :group 'editing-basics)
126 (defcustom-buffer-local *goal-column* nil
127 "*Semipermanent goal column for vertical motion, as set by \\[set-goal-column], or nil."
128 :type '(choice integer
129 (const :tag "None" nil))
130 :group 'editing-basics)
132 (defvar *temporary-goal-column* 0
133 "Current goal column for vertical motion.
134 It is the column where point was
135 at the start of current run of vertical motion commands.
136 When the `track-eol' feature is doing its job, the value is 9999.")
138 (defun line-move (arg &optional noerror to-end try-vscroll)
139 "This is like line-move-1 except that it also performs
140 vertical scrolling of tall images if appropriate.
141 That is not really a clean thing to do, since it mixes
142 scrolling with cursor motion. But so far we don't have
143 a cleaner solution to the problem of making C-n do something
144 useful given a tall image."
145 (declare (ignore try-vscroll))
146 ;; XXX: Fuckit the vertical scrolling for now
147 ;; (if (and auto-window-vscroll try-vscroll
148 ;; ;; But don't vscroll in a keyboard macro.
149 ;; ;; FIXME: kbd macros
150 ;; ;; (not defining-kbd-macro)
151 ;; ;; (not executing-kbd-macro)
152 ;; )
153 ;; (let ((forward (> arg 0))
154 ;; (part (nth 2 (pos-visible-in-window-p (point) nil t))))
155 ;; (if (and (consp part)
156 ;; (> (if forward (cdr part) (car part)) 0))
157 ;; (set-window-vscroll nil
158 ;; (if forward
159 ;; (+ (window-vscroll nil t)
160 ;; (min (cdr part)
161 ;; (* (frame-char-height) arg)))
162 ;; (max 0
163 ;; (- (window-vscroll nil t)
164 ;; (min (car part)
165 ;; (* (frame-char-height) (- arg))))))
166 ;; t)
167 ;; (set-window-vscroll nil 0)
168 ;; (when (line-move-1 arg noerror to-end)
169 ;; (when (not forward)
170 ;; ;; Update display before calling pos-visible-in-window-p,
171 ;; ;; because it depends on window-start being up-to-date.
172 ;; (sit-for 0)
173 ;; ;; If the current line is partly hidden at the bottom,
174 ;; ;; scroll it partially up so as to unhide the bottom.
175 ;; (if (and (setq part (nth 2 (pos-visible-in-window-p
176 ;; (line-beginning-position) nil t)))
177 ;; (> (cdr part) 0))
178 ;; (set-window-vscroll nil (cdr part) t)))
179 ;; t)))
180 (line-move-1 arg noerror to-end))
181 ;; ))
183 (defun line-move-1 (arg &optional noerror to-end)
184 "This is the guts of next-line and previous-line.
185 Arg says how many lines to move.
186 The value is t if we can move the specified number of lines."
187 ;; Don't run any point-motion hooks, and disregard intangibility,
188 ;; for intermediate positions.
189 (declare (ignore to-end))
190 (let ((*inhibit-point-motion-hooks* t)
191 (opoint (point))
192 (forward (> arg 0)))
193 (unwind-protect
194 (progn
195 (if (not (find *last-command* '(next-line previous-line)))
196 (setq *temporary-goal-column*
197 (if (and track-eol (eolp)
198 ;; Don't count beg of empty line as end of line
199 ;; unless we just did explicit end-of-line.
200 (or (not (bolp)) (eq *last-command* 'move-end-of-line)))
201 9999
202 (current-column))))
204 (if (and (not (integerp *selective-display*))
205 (not *line-move-ignore-invisible*))
206 ;; Use just newline characters.
207 ;; Set ARG to 0 if we move as many lines as requested.
208 (or (if (> arg 0)
209 (progn (if (> arg 1) (forward-line (1- arg)))
210 ;; This way of moving forward ARG lines
211 ;; verifies that we have a newline after the last one.
212 ;; It doesn't get confused by intangible text.
213 (end-of-line)
214 (if (zerop (forward-line 1))
215 (setq arg 0)))
216 (and (zerop (forward-line arg))
217 (bolp)
218 (setq arg 0)))
219 (unless noerror
220 (signal (if (< arg 0)
221 'beginning-of-buffer
222 'end-of-buffer)
223 nil)))
224 ;; Move by arg lines, but ignore invisible ones.
225 (let (done)
226 (while (and (> arg 0) (not done))
227 ;; If the following character is currently invisible,
228 ;; skip all characters with that same `invisible' property value.
229 (while (and (not (eobp)) (line-move-invisible-p (point)))
230 (goto-char (next-char-property-change (point))))
231 ;; Now move a line.
232 (end-of-line)
233 ;; If there's no invisibility here, move over the newline.
234 (cond
235 ((eobp)
236 (if (not noerror)
237 (signal 'end-of-buffer)
238 (setq done t)))
239 ((and (> arg 1) ;; Use vertical-motion for last move
240 (not (integerp *selective-display*))
241 (not (line-move-invisible-p (point))))
242 ;; We avoid vertical-motion when possible
243 ;; because that has to fontify.
244 (forward-line 1))
245 ;; Otherwise move a more sophisticated way.
246 ((zerop (vertical-motion 1))
247 (if (not noerror)
248 (signal 'end-of-buffer)
249 (setq done t))))
250 (unless done
251 (setq arg (1- arg))))
252 ;; The logic of this is the same as the loop above,
253 ;; it just goes in the other direction.
254 (while (and (< arg 0) (not done))
255 (beginning-of-line)
256 (cond
257 ((bobp)
258 (if (not noerror)
259 (signal 'beginning-of-buffer nil)
260 (setq done t)))
261 ((and (< arg -1) ;; Use vertical-motion for last move
262 (not (integerp *selective-display*))
263 (not (line-move-invisible-p (1- (point)))))
264 (forward-line -1))
265 ((zerop (vertical-motion -1))
266 (if (not noerror)
267 (signal 'beginning-of-buffer nil)
268 (setq done t))))
269 (unless done
270 (setq arg (1+ arg))
271 (while (and ;; Don't move over previous invis lines
272 ;; if our target is the middle of this line.
273 (or (zerop (or *goal-column* *temporary-goal-column*))
274 (< arg 0))
275 (not (bobp)) (line-move-invisible-p (1- (point))))
276 (goto-char (previous-char-property-change (point))))))))
277 ;; This is the value the function returns.
278 (= arg 0))
280 (cond ((> arg 0)
281 ;; If we did not move down as far as desired,
282 ;; at least go to end of line.
283 (end-of-line))
284 ((< arg 0)
285 ;; If we did not move up as far as desired,
286 ;; at least go to beginning of line.
287 (beginning-of-line))
289 (line-move-finish (or *goal-column* *temporary-goal-column*)
290 opoint forward))))))
292 (defun line-move-finish (column opoint forward)
293 (let ((repeat t))
294 (while repeat
295 ;; Set REPEAT to t to repeat the whole thing.
296 (setq repeat nil)
298 (let (new
299 (line-beg (save-excursion (beginning-of-line) (point)))
300 (line-end
301 ;; Compute the end of the line
302 ;; ignoring effectively invisible newlines.
303 (save-excursion
304 ;; Like end-of-line but ignores fields.
305 (skip-chars-forward "^\n")
306 (while (and (not (eobp)) (line-move-invisible-p (point)))
307 (goto-char (next-char-property-change (point)))
308 (skip-chars-forward "^\n"))
309 (point))))
311 ;; Move to the desired column.
312 (line-move-to-column column)
313 (setq new (point))
315 ;; Process intangibility within a line.
316 ;; With inhibit-point-motion-hooks bound to nil, a call to
317 ;; goto-char moves point past intangible text.
319 ;; However, inhibit-point-motion-hooks controls both the
320 ;; intangibility and the point-entered/point-left hooks. The
321 ;; following hack avoids calling the point-* hooks
322 ;; unnecessarily. Note that we move *forward* past intangible
323 ;; text when the initial and final points are the same.
324 (goto-char new)
325 (let ((*inhibit-point-motion-hooks* nil))
326 (goto-char new)
328 ;; If intangibility moves us to a different (later) place
329 ;; in the same line, use that as the destination.
330 (if (<= (point) line-end)
331 (setq new (point))
332 ;; If that position is "too late",
333 ;; try the previous allowable position.
334 ;; See if it is ok.
335 (progn
336 (backward-char)
337 (if (if forward
338 ;; If going forward, don't accept the previous
339 ;; allowable position if it is before the target line.
340 (< line-beg (point))
341 ;; If going backward, don't accept the previous
342 ;; allowable position if it is still after the target line.
343 (<= (point) line-end))
344 (setq new (point))
345 ;; As a last resort, use the end of the line.
346 (setq new line-end)))))
348 ;; Now move to the updated destination, processing fields
349 ;; as well as intangibility.
350 (goto-char opoint)
351 (let ((*inhibit-point-motion-hooks* nil))
352 (goto-char
353 (constrain-to-field new opoint nil t
354 'inhibit-line-move-field-capture)))
356 ;; If all this moved us to a different line,
357 ;; retry everything within that new line.
358 (when (or (< (point) line-beg) (> (point) line-end))
359 ;; Repeat the intangibility and field processing.
360 (setq repeat t))))))
362 (defun line-move-to-column (col)
363 "Try to find column COL, considering invisibility.
364 This function works only in certain cases,
365 because what we really need is for `move-to-column'
366 and `current-column' to be able to ignore invisible text."
367 (if (zerop col)
368 (beginning-of-line)
369 (let ((opoint (point)))
370 (move-to-column col)
371 ;; move-to-column doesn't respect field boundaries.
372 (goto-char (constrain-to-field (point) opoint))))
374 (when (and *line-move-ignore-invisible*
375 (not (bolp)) (line-move-invisible-p (1- (point))))
376 (let ((normal-location (point))
377 (normal-column (current-column)))
378 ;; If the following character is currently invisible,
379 ;; skip all characters with that same `invisible' property value.
380 (while (and (not (eobp))
381 (line-move-invisible-p (point)))
382 (goto-char (next-char-property-change (point))))
383 ;; Have we advanced to a larger column position?
384 (if (> (current-column) normal-column)
385 ;; We have made some progress towards the desired column.
386 ;; See if we can make any further progress.
387 (line-move-to-column (+ (current-column) (- col normal-column)))
388 ;; Otherwise, go to the place we originally found
389 ;; and move back over invisible text.
390 ;; that will get us to the same place on the screen
391 ;; but with a more reasonable buffer position.
392 (progn
393 (goto-char normal-location)
394 (let ((line-beg (save-excursion (beginning-of-line) (point))))
395 (while (and (not (bolp)) (line-move-invisible-p (1- (point))))
396 (goto-char (previous-char-property-change (point) line-beg)))))))))
398 (defcommand beginning-of-line ((&optional (n 1))
399 :prefix)
400 "Move the point to the beginning of the line in the current buffer."
401 (check-type n number)
402 (set-point (line-beginning-position n)))
404 (defcommand move-beginning-of-line ((arg)
405 :prefix)
406 "Move point to beginning of current line as displayed.
407 \(If there's an image in the line, this disregards newlines
408 which are part of the text that the image rests on.)
410 With argument ARG not nil or 1, move forward ARG - 1 lines first.
411 If point reaches the beginning or end of buffer, it stops there.
412 To ignore intangibility, bind `inhibit-point-motion-hooks' to t."
413 (or arg (setq arg 1))
415 (let ((orig (point))
416 start first-vis first-vis-field-value)
418 ;; Move by lines, if ARG is not 1 (the default).
419 (if (/= arg 1)
420 (line-move (1- arg) t))
422 ;; Move to beginning-of-line, ignoring fields and invisibles.
423 (skip-chars-backward "\\n\\n") ;; FIXME: was "^\n"
424 (while (and (not (bobp)) (line-move-invisible-p (1- (point))))
425 (goto-char (previous-char-property-change (point)))
426 (skip-chars-backward "\\n\\n")) ;; FIXME: was "^\n"
427 (setq start (point))
429 ;; Now find first visible char in the line
430 (while (and (not (eobp)) (line-move-invisible-p (point)))
431 (goto-char (next-char-property-change (point))))
432 (setq first-vis (point))
434 ;; See if fields would stop us from reaching FIRST-VIS.
435 (setq first-vis-field-value
436 (constrain-to-field first-vis orig (/= arg 1) t nil))
438 (goto-char (if (/= first-vis-field-value first-vis)
439 ;; If yes, obey them.
440 first-vis-field-value
441 ;; Otherwise, move to START with attention to fields.
442 ;; (It is possible that fields never matter in this case.)
443 (constrain-to-field (point) orig
444 (/= arg 1) t nil)))))
447 (defcommand end-of-line ((&optional (n 1))
448 :prefix)
449 "Move point to end of current line.
450 With argument N not nil or 1, move forward N - 1 lines first.
451 If point reaches the beginning or end of buffer, it stops there.
452 To ignore intangibility, bind `inhibit-point-motion-hooks' to t.
454 This function constrains point to the current field unless this moves
455 point to a different line than the original, unconstrained result. If
456 N is nil or 1, and a rear-sticky field ends at point, the point does
457 not move. To ignore field boundaries bind `inhibit-field-text-motion'
458 to t."
459 (let (newpos)
460 (loop
461 (setf newpos (line-end-position n))
462 (set-point newpos)
463 (cond
464 ((and (> (point) newpos)
465 (char= (buffer-fetch-char (1- (point)) (current-buffer))
466 #\Newline))
467 ;; If we skipped over a newline that follows an invisible
468 ;; intangible run, move back to the last tangible position
469 ;; within the line.
470 (set-point (1- (point)))
471 (return))
472 ((and (> (point) newpos)
473 (< (point) (zv))
474 (char/= (buffer-fetch-char (point) (current-buffer))
475 #\Newline))
476 ;; If we skipped something intangible and now we're not
477 ;; really at eol, keep going.
478 (setf n 1))
479 (t (return))))
480 nil))
482 (defcommand execute-extended-command ((prefix)
483 :raw-prefix)
484 "Read a user command from the minibuffer."
485 (let* ((name (read-command (case (prefix-numeric-value prefix)
486 (1 "M-x ")
487 (4 "C-u M-x ")
488 (t (format nil "~a M-x " prefix)))))
489 (cmd (lookup-command name)))
490 (if cmd
491 (progn
492 (dispatch-command name)
493 (setf *this-command* (command-name cmd)))
494 (message "No Match"))))
496 (defcommand switch-to-buffer ((buffer &optional norecord)
497 (:buffer "Switch To Buffer: " (buffer-name (other-buffer (current-buffer)))))
498 "Select buffer buffer in the current window.
499 If buffer does not identify an existing buffer,
500 then this function creates a buffer with that name.
502 When called from Lisp, buffer may be a buffer, a string (a buffer name),
503 or nil. If buffer is nil, then this function chooses a buffer
504 using `other-buffer'.
505 Optional second arg norecord non-nil means
506 do not put this buffer at the front of the list of recently selected ones.
507 This function returns the buffer it switched to.
509 WARNING: This is NOT the way to work on another buffer temporarily
510 within a Lisp program! Use `set-buffer' instead. That avoids messing with
511 the window-buffer correspondences."
512 (unless buffer
513 (setf buffer (other-buffer (current-buffer))))
514 (let ((w (frame-selected-window (selected-frame))))
515 (when (typep w 'minibuffer-window)
516 (error "its a minibuffer"))
517 (setf buffer (get-buffer-create buffer))
518 (set-buffer buffer)
519 (unless norecord
520 (record-buffer buffer))
521 (set-window-buffer w buffer)))
523 (defcommand save-buffers-kill-emacs ()
524 ;; TODO: save-some-buffers
525 (throw 'lice-quit t))
527 (defun eval-echo (string)
528 ;; FIXME: don't just abandon the output
529 (let* ((stream (make-string-output-stream))
530 (*standard-output* stream)
531 (*error-output* stream)
532 (*debug-io* stream))
533 (multiple-value-bind (sexpr pos) (read-from-string string)
534 (if (= pos (length string))
535 (message "~s" (eval sexpr))
536 (error "Trailing garbage is ~a" string)))))
538 (defun eval-print (string)
539 (multiple-value-bind (sexpr pos) (read-from-string string)
540 (if (= pos (length string))
541 (insert (format nil "~%~s~%" (eval sexpr)))
542 (error "Trailing garbage is ~a" string))))
544 (defcommand eval-expression ((s)
545 (:string "Eval: "))
546 ;;(handler-case
547 (eval-echo s))
548 ;;(error (c) (message "Eval error: ~s" c))))
550 (defcommand exchange-point-and-mark ()
551 (let ((p (point)))
552 (goto-char (marker-position (mark-marker)))
553 (set-marker (mark-marker) p)))
555 ;; FIXME: this variable is here just so code compiles. we still need
556 ;; to implement it.
557 (defvar transient-mark-mode nil)
559 (defcommand set-mark-command ()
560 (set-marker (mark-marker) (point))
561 (message "Mark set"))
563 (defun push-mark (&optional location nomsg activate)
564 "Set mark at LOCATION (point, by default) and push old mark on mark ring.
565 If the last global mark pushed was not in the current buffer,
566 also push LOCATION on the global mark ring.
567 Display `Mark set' unless the optional second arg NOMSG is non-nil.
568 In Transient Mark mode, activate mark if optional third arg ACTIVATE non-nil.
570 Novice Emacs Lisp programmers often try to use the mark for the wrong
571 purposes. See the documentation of `set-mark' for more information.
573 In Transient Mark mode, this does not activate the mark."
574 (declare (ignore location activate))
575 ;; TODO implement
576 (set-marker (mark-marker) (point))
577 (unless nomsg
578 (message "Mark set")))
580 ;; (defun kill-ring-save (beg end)
581 ;; "Save the region to the kill ring."
583 (defcommand scroll-up ((&optional arg)
584 :raw-prefix)
585 (let ((win (selected-window)))
586 (window-scroll-up win (max 1 (or (and arg (prefix-numeric-value arg))
587 (- (window-height win)
588 *next-screen-context-lines*))))))
590 (defcommand scroll-down ((&optional arg)
591 :raw-prefix)
592 (let ((win (selected-window)))
593 (window-scroll-down win (max 1 (or (and arg (prefix-numeric-value arg))
594 (- (window-height win)
595 *next-screen-context-lines*))))))
597 (defcommand end-of-buffer ()
598 "Move point to the end of the buffer; leave mark at previous position.
599 With arg N, put point N/10 of the way from the end.
601 If the buffer is narrowed, this command uses the beginning and size
602 of the accessible part of the buffer."
603 (set-mark-command)
604 (goto-char (point-max)))
606 (defcommand just-one-space ((&optional (n 1))
607 :prefix)
608 "Delete all spaces and tabs around point, leaving one space (or N spaces)."
609 (let ((orig-pos (point)))
610 (skip-chars-backward (coerce '(#\Space #\Tab) 'string))
611 (constrain-to-field nil orig-pos)
612 (dotimes (i n)
613 (if (char= (following-char) #\Space)
614 (forward-char 1)
615 (insert #\Space)))
616 (delete-region
617 (point)
618 (progn
619 (skip-whitespace-forward)
620 (constrain-to-field nil orig-pos t)))))
622 (defcommand beginning-of-buffer ()
623 "Move point to the beginning of the buffer; leave mark at previous position.
624 With arg N, put point N/10 of the way from the beginning.
626 If the buffer is narrowed, this command uses the beginning and size
627 of the accessible part of the buffer."
628 (set-mark-command)
629 (goto-char (point-min)))
631 (defcommand split-window-vertically ()
632 (split-window (selected-window)))
634 (defcommand split-window-horizontally ()
635 (split-window (selected-window) nil t))
637 (defcommand switch-to-buffer-other-window ((buffer)
638 (:buffer "Switch to buffer in other window: " (buffer-name (other-buffer (current-buffer)))))
639 (let* ((cw (selected-window))
640 (w (or (next-window cw)
641 (split-window cw))))
642 (select-window w)
643 (switch-to-buffer buffer)))
645 (defcommand keyboard-quit ()
646 (signal 'quit))
648 ;;; kill ring
650 (defun kill-new (string &optional replace)
651 "Make STRING the latest kill in the kill ring.
652 Set the kill-ring-yank pointer to point to it.
653 Optional second argument REPLACE non-nil means that STRING will replace
654 the front of the kill ring, rather than being added to the list."
655 (if (and replace
656 *kill-ring*)
657 (setf (car *kill-ring*) string)
658 (push string *kill-ring*))
659 (when (> (length *kill-ring*) *kill-ring-max*)
660 (setf (cdr (nthcdr (1- *kill-ring-max*) *kill-ring*)) nil))
661 (setf *kill-ring-yank-pointer* *kill-ring*))
663 (defun copy-region-as-kill (start end &optional (buffer (current-buffer)))
664 (multiple-value-setq (start end) (validate-region start end buffer))
665 (kill-new (buffer-substring start end buffer)))
667 (defcommand kill-ring-save ()
668 (copy-region-as-kill (mark) (point)))
670 (defcommand kill-region ((beg end)
671 :region-beginning
672 :region-end)
673 "Kill between point and mark.
674 The text is deleted but saved in the kill ring.
675 The command C-y can retrieve it from there.
676 (If you want to kill and then yank immediately, use M-w.)"
677 (copy-region-as-kill beg end)
678 (delete-region beg end))
681 (defcommand kill-line ()
682 (kill-region (point)
683 (progn
684 (when (eobp)
685 (signal 'end-of-buffer))
686 (if (char= (buffer-char-after (current-buffer) (point)) #\Newline)
687 (forward-line 1)
688 (goto-char (buffer-end-of-line)))
689 (point))))
691 (defun current-kill (n &optional do-not-move)
692 "Rotate the yanking point by N places, and then return that kill.
693 If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
694 yanking point; just return the Nth kill forward."
695 (unless *kill-ring*
696 (signal 'kill-ring-empty))
697 (let ((argth-kill-element
698 (nthcdr (mod (- n (length *kill-ring-yank-pointer*))
699 (length *kill-ring*))
700 *kill-ring*)))
701 (unless do-not-move
702 (setf *kill-ring-yank-pointer* argth-kill-element))
703 (car argth-kill-element)))
705 (defcommand yank ()
706 (set-mark-command)
707 (insert (current-kill 0)))
709 (defcommand yank-pop ()
710 (unless (eq *last-command* 'yank)
711 (error "Previous command was not a yank: ~a" *last-command*))
712 (setf *this-command* 'yank)
713 (delete-region (mark) (point))
714 (insert (current-kill 1)))
716 ;;; universal argument
718 (defun prefix-numeric-value (prefix)
719 "Return numeric meaning of raw prefix argument RAW.
720 A raw prefix argument is what you get from :raw-prefix.
721 Its numeric meaning is what you would get from :prefix."
722 ;; TODO
723 (cond ((null prefix)
725 ((eq prefix '-)
727 ((and (consp prefix)
728 (integerp (car prefix)))
729 (car prefix))
730 ((integerp prefix)
731 prefix)
732 (t 1)))
734 (defun prefix-arg ()
735 "Return numeric meaning of *prefix-arg*"
736 (prefix-numeric-value *prefix-arg*))
738 (defun raw-prefix-arg ()
739 "Return the current prefix arg in raw form."
740 *prefix-arg*)
742 (defvar *overriding-map-is-bound* nil)
743 (defvar *saved-overriding-map* nil)
744 (defvar *universal-argument-num-events* nil)
746 (defvar *universal-argument-map*
747 (let ((map (make-sparse-keymap)))
748 ;;(define-key map (kbd "t") 'universal-argument-other-key)
749 (define-key map t 'universal-argument-other-key)
750 ;;(define-key map [switch-frame] nil)
751 (define-key map (kbd "C-u") 'universal-argument-more)
752 (define-key map (kbd "-") 'universal-argument-minus)
753 (define-key map (kbd "0") 'digit-argument)
754 (define-key map (kbd "1") 'digit-argument)
755 (define-key map (kbd "2") 'digit-argument)
756 (define-key map (kbd "3") 'digit-argument)
757 (define-key map (kbd "4") 'digit-argument)
758 (define-key map (kbd "5") 'digit-argument)
759 (define-key map (kbd "6") 'digit-argument)
760 (define-key map (kbd "7") 'digit-argument)
761 (define-key map (kbd "8") 'digit-argument)
762 (define-key map (kbd "9") 'digit-argument)
763 ;; (define-key map [kp-0] 'digit-argument)
764 ;; (define-key map [kp-1] 'digit-argument)
765 ;; (define-key map [kp-2] 'digit-argument)
766 ;; (define-key map [kp-3] 'digit-argument)
767 ;; (define-key map [kp-4] 'digit-argument)
768 ;; (define-key map [kp-5] 'digit-argument)
769 ;; (define-key map [kp-6] 'digit-argument)
770 ;; (define-key map [kp-7] 'digit-argument)
771 ;; (define-key map [kp-8] 'digit-argument)
772 ;; (define-key map [kp-9] 'digit-argument)
773 ;; (define-key map [kp-subtract] 'universal-argument-minus)
774 map)
775 "Keymap used while processing \\[universal-argument].")
777 (defun ensure-overriding-map-is-bound ()
778 "Check `*overriding-terminal-local-map*' is `*universal-argument-map*'."
779 (unless *overriding-map-is-bound*
780 (setf *saved-overriding-map* *overriding-terminal-local-map*
781 *overriding-terminal-local-map* *universal-argument-map*
782 *overriding-map-is-bound* t)))
784 (defun restore-overriding-map ()
785 "Restore `*overriding-terminal-local-map*' to its saved value."
786 (setf *overriding-terminal-local-map* *saved-overriding-map*
787 *overriding-map-is-bound* nil))
789 (defcommand universal-argument ()
790 (setf *prefix-arg* (list 4)
791 *universal-argument-num-events* (length (this-command-keys)))
792 (ensure-overriding-map-is-bound))
794 (defcommand universal-argument-more ((arg)
795 :raw-prefix)
796 (if (consp arg)
797 (setf *prefix-arg* (list (* 4 (car arg))))
798 (if (eq arg '-)
799 (setf *prefix-arg* (list -4))
800 (progn
801 (setf *prefix-arg* arg)
802 (restore-overriding-map))))
803 (setf *universal-argument-num-events* (length (this-command-keys))))
805 (defcommand negative-argument ((arg)
806 :raw-prefix)
807 "Begin a negative numeric argument for the next command.
808 \\[universal-argument] following digits or minus sign ends the argument."
809 (cond ((integerp arg)
810 (setf *prefix-arg* (- arg)))
811 ((eq arg '-)
812 (setf *prefix-arg* nil))
814 (setf *prefix-arg* '-)))
815 (setf *universal-argument-num-events* (length (this-command-keys)))
816 (ensure-overriding-map-is-bound))
818 (defcommand digit-argument ((arg)
819 :raw-prefix)
820 "Part of the numeric argument for the next command.
821 \\[universal-argument] following digits or minus sign ends the argument."
822 (let* ((char (last-command-char))
823 (digit (- (logand (char-code char) #o177) (char-code #\0))))
824 (cond ((integerp arg)
825 (setf *prefix-arg* (+ (* arg 10)
826 (if (< arg 0) (- digit) digit))))
827 ((eq arg '-)
828 ;; Treat -0 as just -, so that -01 will work.
829 (setf *prefix-arg* (if (zerop digit) '- (- digit))))
831 (setf *prefix-arg* digit))))
832 (setf *universal-argument-num-events* (length (this-command-keys)))
833 (ensure-overriding-map-is-bound))
835 ;; For backward compatibility, minus with no modifiers is an ordinary
836 ;; command if digits have already been entered.
837 (defcommand universal-argument-minus ((arg)
838 :raw-prefix)
839 (if (integerp arg)
840 (universal-argument-other-key arg)
841 (negative-argument arg)))
843 ;; Anything else terminates the argument and is left in the queue to be
844 ;; executed as a command.
845 (defcommand universal-argument-other-key ((arg)
846 :raw-prefix)
847 (setf *prefix-arg* arg)
848 (let* ((keylist (this-command-keys)))
849 (setf *unread-command-events* keylist))
850 ;; (append (nthcdr *universal-argument-num-events* keylist)
851 ;; *unread-command-events*)))
852 ;;FIXME: (reset-this-command-lengths)
853 (restore-overriding-map))
856 ;; (defcommand append-to-buffer ((buffer :buffer "Append to buffer: " (buffer-name (other-buffer (current-buffer))))
857 ;; (start :region-beginning)
858 ;; (end :region-end))
859 ;; "Append to specified buffer the text of the region.
860 ;; It is inserted into that buffer before its point.
862 ;; When calling from a program, give three arguments:
863 ;; buffer (or buffer name), start and end.
864 ;; start and end specify the portion of the current buffer to be copied."
865 ;; (let ((oldbuf (current-buffer)))
866 ;; (save-excursion
867 ;; (let* ((append-to (get-buffer-create buffer))
868 ;; (windows (get-buffer-window-list append-to t t))
869 ;; point)
870 ;; (set-buffer append-to)
871 ;; (setf point (point))
872 ;; (barf-if-buffer-read-only)
873 ;; (insert-buffer-substring oldbuf start end)
874 ;; (dolist (window windows)
875 ;; (when (= (window-point window) point)
876 ;; (set-window-point window (point))))))))
878 (defcommand transpose-chars ((arg)
879 :prefix)
880 "Interchange characters around point, moving forward one character.
881 With prefix arg ARG, effect is to take character before point
882 and drag it forward past ARG other characters (backward if ARG negative).
883 If no argument and at end of line, the previous two chars are exchanged."
884 (and (null arg) (eolp) (forward-char -1))
885 (transpose-subr 'forward-char (prefix-numeric-value arg)))
887 (defcommand transpose-words ((arg)
888 :prefix)
889 "Interchange words around point, leaving point at end of them.
890 With prefix arg ARG, effect is to take word before or around point
891 and drag it forward past ARG other words (backward if ARG negative).
892 If ARG is zero, the words around or after point and around or after mark
893 are interchanged."
894 ;; FIXME: `foo a!nd bar' should transpose into `bar and foo'.
895 (transpose-subr 'forward-word arg))
897 ;; (defun transpose-sexps ((arg)
898 ;; :prefix)
899 ;; "Like \\[transpose-words] but applies to sexps.
900 ;; Does not work on a sexp that point is in the middle of
901 ;; if it is a list or string."
902 ;; (transpose-subr
903 ;; (lambda (arg)
904 ;; ;; Here we should try to simulate the behavior of
905 ;; ;; (cons (progn (forward-sexp x) (point))
906 ;; ;; (progn (forward-sexp (- x)) (point)))
907 ;; ;; Except that we don't want to rely on the second forward-sexp
908 ;; ;; putting us back to where we want to be, since forward-sexp-function
909 ;; ;; might do funny things like infix-precedence.
910 ;; (if (if (> arg 0)
911 ;; ;;(looking-at "\\sw\\|\\s_")
912 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
913 ;; (or (alpha-char-p (char-after (point)))
914 ;; (find (char-after (point)) "*/+-%$!@&"))
915 ;; (and (not (bobp))
916 ;; (save-excursion (forward-char -1)
917 ;; ;; (looking-at "\\sw\\|\\s_")
918 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
919 ;; (or (alpha-char-p (char-after (point)))
920 ;; (find (char-after (point)) "*/+-%$!@&"))
921 ;; )))
922 ;; ;; Jumping over a symbol. We might be inside it, mind you.
923 ;; (progn (funcall (if (> arg 0)
924 ;; 'skip-syntax-backward 'skip-syntax-forward)
925 ;; "w_")
926 ;; (cons (save-excursion (forward-sexp arg) (point)) (point)))
927 ;; ;; Otherwise, we're between sexps. Take a step back before jumping
928 ;; ;; to make sure we'll obey the same precedence no matter which direction
929 ;; ;; we're going.
930 ;; (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) " .")
931 ;; (cons (save-excursion (forward-sexp arg) (point))
932 ;; (progn (while (or (forward-comment (if (> arg 0) 1 -1))
933 ;; (not (zerop (funcall (if (> arg 0)
934 ;; 'skip-syntax-forward
935 ;; 'skip-syntax-backward)
936 ;; ".")))))
937 ;; (point)))))
938 ;; arg 'special))
940 (defcommand transpose-lines ((arg)
941 :prefix)
942 "Exchange current line and previous line, leaving point after both.
943 With argument ARG, takes previous line and moves it past ARG lines.
944 With argument 0, interchanges line point is in with line mark is in."
945 (transpose-subr (function
946 (lambda (arg)
947 (if (> arg 0)
948 (progn
949 ;; Move forward over ARG lines,
950 ;; but create newlines if necessary.
951 (setq arg (forward-line arg))
952 (if (char/= (preceding-char) #\Newline)
953 (setq arg (1+ arg)))
954 (if (> arg 0)
955 (newline arg)))
956 (forward-line arg))))
957 arg))
959 (defun transpose-subr (mover arg &optional special)
960 (let ((aux (if special mover
961 (lambda (x)
962 (cons (progn (funcall mover x) (point))
963 (progn (funcall mover (- x)) (point))))))
964 pos1 pos2)
965 (cond
966 ((= arg 0)
967 (save-excursion
968 (setq pos1 (funcall aux 1))
969 (goto-char (mark))
970 (setq pos2 (funcall aux 1))
971 (transpose-subr-1 pos1 pos2))
972 (exchange-point-and-mark))
973 ((> arg 0)
974 (setq pos1 (funcall aux -1))
975 (setq pos2 (funcall aux arg))
976 (transpose-subr-1 pos1 pos2)
977 (goto-char (car pos2)))
979 (setq pos1 (funcall aux -1))
980 (goto-char (car pos1))
981 (setq pos2 (funcall aux arg))
982 (transpose-subr-1 pos1 pos2)))))
984 (defun transpose-subr-1 (pos1 pos2)
985 (when (> (car pos1) (cdr pos1)) (setq pos1 (cons (cdr pos1) (car pos1))))
986 (when (> (car pos2) (cdr pos2)) (setq pos2 (cons (cdr pos2) (car pos2))))
987 (when (> (car pos1) (car pos2))
988 (let ((swap pos1))
989 (setq pos1 pos2 pos2 swap)))
990 (if (> (cdr pos1) (car pos2)) (error "Don't have two things to transpose"))
991 ;; (atomic-change-group
992 (let (word2)
993 ;; FIXME: We first delete the two pieces of text, so markers that
994 ;; used to point to after the text end up pointing to before it :-(
995 (setq word2 (delete-and-extract-region (car pos2) (cdr pos2)))
996 (goto-char (car pos2))
997 (insert (delete-and-extract-region (car pos1) (cdr pos1)))
998 (goto-char (car pos1))
999 (insert word2)))
1001 ;;;
1003 (defcustom-buffer-local *fill-prefix* nil
1004 "*String for filling to insert at front of new line, or nil for none."
1005 :type '(choice (const :tag "None" nil)
1006 string)
1007 :group 'fill)
1009 (defvar *fundamental-mode*
1010 (make-instance 'major-mode
1011 :name "Fundamental")
1012 "Major mode not specialized for anything in particular.
1013 Other major modes are defined by comparison with this one.")
1015 (defun fundamental-mode ()
1016 (set-major-mode '*fundamental-mode*))
1018 (defun turn-on-auto-fill ()
1019 "Unconditionally turn on Auto Fill mode."
1020 ;; FIXME: implement
1024 ;; FIXME: put this info in the following condition
1025 ;; (put 'mark-inactive 'error-conditions '(mark-inactive error))
1026 ;; (put 'mark-inactive 'error-message "The mark is not active now")
1028 (define-condition mark-inactive (lice-condition)
1031 (defvar activate-mark-hook nil
1032 "Hook run when the mark becomes active.
1033 It is also run at the end of a command, if the mark is active and
1034 it is possible that the region may have changed")
1036 (defvar deactivate-mark-hook nil
1037 "Hook run when the mark becomes inactive.")
1039 (defun mark (&optional force)
1040 "Return this buffer's mark value as integer, or nil if never set.
1042 In Transient Mark mode, this function signals an error if
1043 the mark is not active. However, if `mark-even-if-inactive' is non-nil,
1044 or the argument FORCE is non-nil, it disregards whether the mark
1045 is active, and returns an integer or nil in the usual way.
1047 If you are using this in an editing command, you are most likely making
1048 a mistake; see the documentation of `set-mark'."
1049 (if (or force (not transient-mark-mode) mark-active mark-even-if-inactive)
1050 (marker-position (mark-marker))
1051 (signal 'mark-inactive nil)))
1053 ;; ;; Many places set mark-active directly, and several of them failed to also
1054 ;; ;; run deactivate-mark-hook. This shorthand should simplify.
1055 ;; (defsubst deactivate-mark ()
1056 ;; "Deactivate the mark by setting `mark-active' to nil.
1057 ;; \(That makes a difference only in Transient Mark mode.)
1058 ;; Also runs the hook `deactivate-mark-hook'."
1059 ;; (cond
1060 ;; ((eq transient-mark-mode 'lambda)
1061 ;; (setq transient-mark-mode nil))
1062 ;; (transient-mark-mode
1063 ;; (setq mark-active nil)
1064 ;; (run-hooks 'deactivate-mark-hook))))
1066 (defun set-mark (pos)
1067 "Set this buffer's mark to POS. Don't use this function!
1068 That is to say, don't use this function unless you want
1069 the user to see that the mark has moved, and you want the previous
1070 mark position to be lost.
1072 Normally, when a new mark is set, the old one should go on the stack.
1073 This is why most applications should use `push-mark', not `set-mark'.
1075 Novice Emacs Lisp programmers often try to use the mark for the wrong
1076 purposes. The mark saves a location for the user's convenience.
1077 Most editing commands should not alter the mark.
1078 To remember a location for internal use in the Lisp program,
1079 store it in a Lisp variable. Example:
1081 (let ((beg (point))) (forward-line 1) (delete-region beg (point)))."
1083 (if pos
1084 (progn
1085 (setq mark-active t)
1086 (run-hooks 'activate-mark-hook)
1087 (set-marker (mark-marker) pos (current-buffer)))
1088 ;; Normally we never clear mark-active except in Transient Mark mode.
1089 ;; But when we actually clear out the mark value too,
1090 ;; we must clear mark-active in any mode.
1091 (progn
1092 (setq mark-active nil)
1093 (run-hooks 'deactivate-mark-hook)
1094 (set-marker (mark-marker) nil))))
1096 (define-buffer-local mark-ring nil
1097 "The list of former marks of the current buffer, most recent first.")
1098 (make-variable-buffer-local 'mark-ring)
1099 (setf (get 'mark-ring 'permanent-local) t)
1101 (defcustom mark-ring-max 16
1102 "*Maximum size of mark ring. Start discarding off end if gets this big."
1103 :type 'integer
1104 :group 'editing-basics)
1106 (defvar global-mark-ring nil
1107 "The list of saved global marks, most recent first.")
1109 (defcustom global-mark-ring-max 16
1110 "*Maximum size of global mark ring. \
1111 Start discarding off end if gets this big."
1112 :type 'integer
1113 :group 'editing-basics)
1115 (defcommand pop-to-mark-command ()
1116 "Jump to mark, and pop a new position for mark off the ring
1117 \(does not affect global mark ring\)."
1118 (if (null (mark t))
1119 (error "No mark set in this buffer")
1120 (progn
1121 (goto-char (mark t))
1122 (pop-mark))))
1124 ;; (defun push-mark-command (arg &optional nomsg)
1125 ;; "Set mark at where point is.
1126 ;; If no prefix arg and mark is already set there, just activate it.
1127 ;; Display `Mark set' unless the optional second arg NOMSG is non-nil."
1128 ;; (interactive "P")
1129 ;; (let ((mark (marker-position (mark-marker))))
1130 ;; (if (or arg (null mark) (/= mark (point)))
1131 ;; (push-mark nil nomsg t)
1132 ;; (setq mark-active t)
1133 ;; (run-hooks 'activate-mark-hook)
1134 ;; (unless nomsg
1135 ;; (message "Mark activated")))))
1137 (defcustom set-mark-command-repeat-pop nil
1138 "*Non-nil means that repeating \\[set-mark-command] after popping will pop.
1139 This means that if you type C-u \\[set-mark-command] \\[set-mark-command]
1140 will pop twice."
1141 :type 'boolean
1142 :group 'editing)
1144 ;; (defun set-mark-command (arg)
1145 ;; "Set mark at where point is, or jump to mark.
1146 ;; With no prefix argument, set mark, and push old mark position on local
1147 ;; mark ring; also push mark on global mark ring if last mark was set in
1148 ;; another buffer. Immediately repeating the command activates
1149 ;; `transient-mark-mode' temporarily.
1151 ;; With argument, e.g. \\[universal-argument] \\[set-mark-command], \
1152 ;; jump to mark, and pop a new position
1153 ;; for mark off the local mark ring \(this does not affect the global
1154 ;; mark ring\). Use \\[pop-global-mark] to jump to a mark off the global
1155 ;; mark ring \(see `pop-global-mark'\).
1157 ;; If `set-mark-command-repeat-pop' is non-nil, repeating
1158 ;; the \\[set-mark-command] command with no prefix pops the next position
1159 ;; off the local (or global) mark ring and jumps there.
1161 ;; With a double \\[universal-argument] prefix argument, e.g. \\[universal-argument] \
1162 ;; \\[universal-argument] \\[set-mark-command], unconditionally
1163 ;; set mark where point is.
1165 ;; Setting the mark also sets the \"region\", which is the closest
1166 ;; equivalent in Emacs to what some editors call the \"selection\".
1168 ;; Novice Emacs Lisp programmers often try to use the mark for the wrong
1169 ;; purposes. See the documentation of `set-mark' for more information."
1170 ;; (interactive "P")
1171 ;; (if (eq transient-mark-mode 'lambda)
1172 ;; (setq transient-mark-mode nil))
1173 ;; (cond
1174 ;; ((and (consp arg) (> (prefix-numeric-value arg) 4))
1175 ;; (push-mark-command nil))
1176 ;; ((not (eq this-command 'set-mark-command))
1177 ;; (if arg
1178 ;; (pop-to-mark-command)
1179 ;; (push-mark-command t)))
1180 ;; ((and set-mark-command-repeat-pop
1181 ;; (eq last-command 'pop-to-mark-command))
1182 ;; (setq this-command 'pop-to-mark-command)
1183 ;; (pop-to-mark-command))
1184 ;; ((and set-mark-command-repeat-pop
1185 ;; (eq last-command 'pop-global-mark)
1186 ;; (not arg))
1187 ;; (setq this-command 'pop-global-mark)
1188 ;; (pop-global-mark))
1189 ;; (arg
1190 ;; (setq this-command 'pop-to-mark-command)
1191 ;; (pop-to-mark-command))
1192 ;; ((and (eq last-command 'set-mark-command)
1193 ;; mark-active (null transient-mark-mode))
1194 ;; (setq transient-mark-mode 'lambda)
1195 ;; (message "Transient-mark-mode temporarily enabled"))
1196 ;; (t
1197 ;; (push-mark-command nil))))
1199 ;; (defun push-mark (&optional location nomsg activate)
1200 ;; "Set mark at LOCATION (point, by default) and push old mark on mark ring.
1201 ;; If the last global mark pushed was not in the current buffer,
1202 ;; also push LOCATION on the global mark ring.
1203 ;; Display `Mark set' unless the optional second arg NOMSG is non-nil.
1204 ;; In Transient Mark mode, activate mark if optional third arg ACTIVATE non-nil.
1206 ;; Novice Emacs Lisp programmers often try to use the mark for the wrong
1207 ;; purposes. See the documentation of `set-mark' for more information.
1209 ;; In Transient Mark mode, this does not activate the mark."
1210 ;; (unless (null (mark t))
1211 ;; (setq mark-ring (cons (copy-marker (mark-marker)) mark-ring))
1212 ;; (when (> (length mark-ring) mark-ring-max)
1213 ;; (move-marker (car (nthcdr mark-ring-max mark-ring)) nil)
1214 ;; (setcdr (nthcdr (1- mark-ring-max) mark-ring) nil)))
1215 ;; (set-marker (mark-marker) (or location (point)) (current-buffer))
1216 ;; ;; Now push the mark on the global mark ring.
1217 ;; (if (and global-mark-ring
1218 ;; (eq (marker-buffer (car global-mark-ring)) (current-buffer)))
1219 ;; ;; The last global mark pushed was in this same buffer.
1220 ;; ;; Don't push another one.
1221 ;; nil
1222 ;; (setq global-mark-ring (cons (copy-marker (mark-marker)) global-mark-ring))
1223 ;; (when (> (length global-mark-ring) global-mark-ring-max)
1224 ;; (move-marker (car (nthcdr global-mark-ring-max global-mark-ring)) nil)
1225 ;; (setcdr (nthcdr (1- global-mark-ring-max) global-mark-ring) nil)))
1226 ;; (or nomsg executing-kbd-macro (> (minibuffer-depth) 0)
1227 ;; (message "Mark set"))
1228 ;; (if (or activate (not transient-mark-mode))
1229 ;; (set-mark (mark t)))
1230 ;; nil)
1232 ;; (defun pop-mark ()
1233 ;; "Pop off mark ring into the buffer's actual mark.
1234 ;; Does not set point. Does nothing if mark ring is empty."
1235 ;; (when mark-ring
1236 ;; (setq mark-ring (nconc mark-ring (list (copy-marker (mark-marker)))))
1237 ;; (set-marker (mark-marker) (+ 0 (car mark-ring)) (current-buffer))
1238 ;; (move-marker (car mark-ring) nil)
1239 ;; (if (null (mark t)) (ding))
1240 ;; (setq mark-ring (cdr mark-ring)))
1241 ;; (deactivate-mark))
1243 (defcommand back-to-indentation ()
1244 "Move point to the first non-whitespace character on this line."
1245 (beginning-of-line 1)
1246 (skip-syntax-forward '(:whitespace) (line-end-position))
1247 ;; Move back over chars that have whitespace syntax but have the p flag.
1248 (backward-prefix-chars))
1251 ;;; undo
1253 ;; XXX: gnu emacs uses a weak hashtable that automatically removes
1254 ;; references. We need some mechanism to do similar.
1255 (defvar undo-equiv-table (make-hash-table :test 'eq #|:weakness t|#)
1256 "Table mapping redo records to the corresponding undo one.
1257 A redo record for undo-in-region maps to t.
1258 A redo record for ordinary undo maps to the following (earlier) undo.")
1260 (defvar undo-in-region nil
1261 "Non-nil if `pending-undo-list' is not just a tail of `buffer-undo-list'.")
1263 (defvar undo-no-redo nil
1264 "If t, `undo' doesn't go through redo entries.")
1266 (defvar pending-undo-list nil
1267 "Within a run of consecutive undo commands, list remaining to be undone.
1268 If t, we undid all the way to the end of it.")
1270 (defcommand undo ((&optional arg)
1271 ;; XXX: what about the *?
1272 :raw-prefix)
1273 "Undo some previous changes.
1274 Repeat this command to undo more changes.
1275 A numeric argument serves as a repeat count.
1277 In Transient Mark mode when the mark is active, only undo changes within
1278 the current region. Similarly, when not in Transient Mark mode, just \\[universal-argument]
1279 as an argument limits undo to changes within the current region."
1280 ;;(interactive "*P")
1281 ;; Make last-command indicate for the next command that this was an undo.
1282 ;; That way, another undo will undo more.
1283 ;; If we get to the end of the undo history and get an error,
1284 ;; another undo command will find the undo history empty
1285 ;; and will get another error. To begin undoing the undos,
1286 ;; you must type some other command.
1287 (let ((modified (buffer-modified-p (current-buffer)))
1288 (recent-save (recent-auto-save-p))
1289 message)
1290 ;; If we get an error in undo-start,
1291 ;; the next command should not be a "consecutive undo".
1292 ;; So set `this-command' to something other than `undo'.
1293 (setq *this-command* 'undo-start)
1295 (unless (and (eq *last-command* 'undo)
1296 (or (eq pending-undo-list t)
1297 ;; If something (a timer or filter?) changed the buffer
1298 ;; since the previous command, don't continue the undo seq.
1299 (let ((list (buffer-undo-list (current-buffer))))
1300 (while (eq (car list) nil)
1301 (setq list (cdr list)))
1302 ;; If the last undo record made was made by undo
1303 ;; it shows nothing else happened in between.
1304 (gethash list undo-equiv-table))))
1305 (message "guuuungh")
1306 (setq undo-in-region
1307 (if transient-mark-mode *mark-active* (and arg (not (numberp arg)))))
1308 (if undo-in-region
1309 (undo-start (region-beginning) (region-end))
1310 (undo-start))
1311 ;; get rid of initial undo boundary
1312 (undo-more 1))
1313 ;; If we got this far, the next command should be a consecutive undo.
1314 (setq *this-command* 'undo)
1315 ;; Check to see whether we're hitting a redo record, and if
1316 ;; so, ask the user whether she wants to skip the redo/undo pair.
1317 (let ((equiv (gethash pending-undo-list undo-equiv-table)))
1318 (or (eq (selected-window) (minibuffer-window))
1319 (setq message (if undo-in-region
1320 (if equiv "Redo in region!" "Undo in region!")
1321 (if equiv "Redo!" "Undo!"))))
1322 (when (and (consp equiv) undo-no-redo)
1323 ;; The equiv entry might point to another redo record if we have done
1324 ;; undo-redo-undo-redo-... so skip to the very last equiv.
1325 (while (let ((next (gethash equiv undo-equiv-table)))
1326 (if next (setq equiv next))))
1327 (setq pending-undo-list equiv)))
1328 (undo-more
1329 (if (or transient-mark-mode (numberp arg))
1330 (prefix-numeric-value arg)
1332 ;; Record the fact that the just-generated undo records come from an
1333 ;; undo operation--that is, they are redo records.
1334 ;; In the ordinary case (not within a region), map the redo
1335 ;; record to the following undos.
1336 ;; I don't know how to do that in the undo-in-region case.
1337 (setf (gethash (buffer-undo-list (current-buffer)) undo-equiv-table)
1338 (if undo-in-region t pending-undo-list))
1339 ;; Don't specify a position in the undo record for the undo command.
1340 ;; Instead, undoing this should move point to where the change is.
1341 (let ((tail (buffer-undo-list (current-buffer)))
1342 (prev nil))
1343 (message "its: ~s" tail)
1344 (while (car tail)
1345 (when (integerp (car tail))
1346 (let ((pos (car tail)))
1347 (if prev
1348 (setf (cdr prev) (cdr tail))
1349 (setf (buffer-undo-list (current-buffer)) (cdr tail)))
1350 (setq tail (cdr tail))
1351 (while (car tail)
1352 (if (eql pos (car tail))
1353 (if prev
1354 (setf (cdr prev) (cdr tail))
1355 (setf (buffer-undo-list (current-buffer)) (cdr tail)))
1356 (setq prev tail))
1357 (setq tail (cdr tail)))
1358 (setq tail nil)))
1359 (setq prev tail
1360 tail (cdr tail))))
1361 ;; Record what the current undo list says,
1362 ;; so the next command can tell if the buffer was modified in between.
1363 (and modified (not (buffer-modified-p (current-buffer)))
1364 (delete-auto-save-file-if-necessary recent-save))
1365 ;; Display a message announcing success.
1366 (if message
1367 (message message))))
1369 (defcommand buffer-disable-undo ((&optional buffer))
1370 "Make BUFFER stop keeping undo information.
1371 No argument or nil as argument means do this for the current buffer."
1372 (with-current-buffer (if buffer (get-buffer buffer) (current-buffer))
1373 (setf (buffer-undo-list (current-buffer)) t)))
1375 (defcommand undo-only ((&optional arg)
1376 ;; XXX what about *
1377 :prefix)
1378 "Undo some previous changes.
1379 Repeat this command to undo more changes.
1380 A numeric argument serves as a repeat count.
1381 Contrary to `undo', this will not redo a previous undo."
1382 ;;(interactive "*p")
1383 (let ((undo-no-redo t)) (undo arg)))
1385 (defvar undo-in-progress nil
1386 "Non-nil while performing an undo.
1387 Some change-hooks test this variable to do something different.")
1389 (defun undo-more (n)
1390 "Undo back N undo-boundaries beyond what was already undone recently.
1391 Call `undo-start' to get ready to undo recent changes,
1392 then call `undo-more' one or more times to undo them."
1393 (or (listp pending-undo-list)
1394 (error (concat "No further undo information"
1395 (and transient-mark-mode *mark-active*
1396 " for region"))))
1397 (let ((undo-in-progress t))
1398 (setq pending-undo-list (primitive-undo n pending-undo-list))
1399 (if (null pending-undo-list)
1400 (setq pending-undo-list t))))
1402 ;; Deep copy of a list
1403 (defun undo-copy-list (list)
1404 "Make a copy of undo list LIST."
1405 (labels ((helper (elt)
1406 (if (typep elt 'structure-object)
1407 (copy-structure elt)
1408 elt)))
1409 (mapcar #'helper list)))
1411 (defun undo-start (&optional beg end)
1412 "Set `pending-undo-list' to the front of the undo list.
1413 The next call to `undo-more' will undo the most recently made change.
1414 If BEG and END are specified, then only undo elements
1415 that apply to text between BEG and END are used; other undo elements
1416 are ignored. If BEG and END are nil, all undo elements are used."
1417 (if (eq (buffer-undo-list (current-buffer)) t)
1418 (error "No undo information in this buffer"))
1419 (setq pending-undo-list
1420 (if (and beg end (not (= beg end)))
1421 (undo-make-selective-list (min beg end) (max beg end))
1422 (buffer-undo-list (current-buffer)))))
1424 (defvar undo-adjusted-markers)
1426 (defun undo-make-selective-list (start end)
1427 "Return a list of undo elements for the region START to END.
1428 The elements come from `buffer-undo-list', but we keep only
1429 the elements inside this region, and discard those outside this region.
1430 If we find an element that crosses an edge of this region,
1431 we stop and ignore all further elements."
1432 (let ((undo-list-copy (undo-copy-list (buffer-undo-list (current-buffer))))
1433 (undo-list (list nil))
1434 undo-adjusted-markers
1435 some-rejected
1436 undo-elt temp-undo-list delta)
1437 (while undo-list-copy
1438 (setq undo-elt (car undo-list-copy))
1439 (let ((keep-this
1440 (cond ((typep undo-elt 'undo-entry-modified) ;;(and (consp undo-elt) (eq (car undo-elt) t))
1441 ;; This is a "was unmodified" element.
1442 ;; Keep it if we have kept everything thus far.
1443 (not some-rejected))
1445 (undo-elt-in-region undo-elt start end)))))
1446 (if keep-this
1447 (progn
1448 (setq end (+ end (cdr (undo-delta undo-elt))))
1449 ;; Don't put two nils together in the list
1450 (if (not (and (eq (car undo-list) nil)
1451 (eq undo-elt nil)))
1452 (setq undo-list (cons undo-elt undo-list))))
1453 (if (undo-elt-crosses-region undo-elt start end)
1454 (setq undo-list-copy nil)
1455 (progn
1456 (setq some-rejected t)
1457 (setq temp-undo-list (cdr undo-list-copy))
1458 (setq delta (undo-delta undo-elt))
1460 (when (/= (cdr delta) 0)
1461 (let ((position (car delta))
1462 (offset (cdr delta)))
1464 ;; Loop down the earlier events adjusting their buffer
1465 ;; positions to reflect the fact that a change to the buffer
1466 ;; isn't being undone. We only need to process those element
1467 ;; types which undo-elt-in-region will return as being in
1468 ;; the region since only those types can ever get into the
1469 ;; output
1471 (dolist (undo-elt temp-undo-list)
1472 (cond ((integerp undo-elt)
1473 (if (>= undo-elt position)
1474 (setf (car temp-undo-list) (- undo-elt offset))))
1475 ;;((atom undo-elt) nil)
1476 ((typep undo-elt 'undo-entry-delete) ;(stringp (car undo-elt))
1477 ;; (TEXT . POSITION)
1478 (let ((text-pos (abs (undo-entry-delete-position undo-elt)))
1479 (point-at-end (< (undo-entry-delete-position undo-elt) 0 )))
1480 (if (>= text-pos position)
1481 (setf (undo-entry-delete-position undo-elt) (* (if point-at-end -1 1)
1482 (- text-pos offset))))))
1483 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1484 ;; (BEGIN . END)
1485 (when (>= (undo-entry-insertion-beg undo-elt) position)
1486 (setf (undo-entry-insertion-beg undo-elt) (- (undo-entry-insertion-beg undo-elt) offset))
1487 (setf (undo-entry-insertion-end undo-elt) (- (undo-entry-insertion-end undo-elt) offset))))
1488 ((typep undo-elt 'undo-entry-property) ;(null (car undo-elt))
1489 ;; (nil PROPERTY VALUE BEG . END)
1490 (when (>= (undo-entry-property-beg undo-elt) position)
1491 (setf (undo-entry-property-beg undo-elt) (- (undo-entry-property-beg undo-elt) offset))
1492 (setf (undo-entry-property-end undo-elt) (- (undo-entry-property-end undo-elt) offset))))))))))))
1493 (setq undo-list-copy (cdr undo-list-copy)))
1494 (nreverse undo-list)))
1496 (defun undo-elt-in-region (undo-elt start end)
1497 "Determine whether UNDO-ELT falls inside the region START ... END.
1498 If it crosses the edge, we return nil."
1499 (cond ((integerp undo-elt)
1500 (and (>= undo-elt start)
1501 (<= undo-elt end)))
1502 ((eq undo-elt nil)
1504 ;; ((atom undo-elt)
1505 ;; nil)
1506 ((typep undo-elt 'undo-entry-delete) ; (stringp (car undo-elt))
1507 ;; (TEXT . POSITION)
1508 (and (>= (abs (undo-entry-delete-position undo-elt)) start)
1509 (< (abs (undo-entry-delete-position undo-elt)) end)))
1510 ((typep undo-elt 'undo-entry-marker) ;(and (consp undo-elt) (markerp (car undo-elt)))
1511 ;; This is a marker-adjustment element (MARKER . ADJUSTMENT).
1512 ;; See if MARKER is inside the region.
1513 (let ((alist-elt (assq (undo-entry-marker-marker undo-elt) undo-adjusted-markers)))
1514 (unless alist-elt
1515 (setq alist-elt (make-undo-entry-marker :marker (undo-entry-marker-marker undo-elt)
1516 :distance (marker-position (undo-entry-marker-marker undo-elt))))
1517 (setq undo-adjusted-markers
1518 (cons alist-elt undo-adjusted-markers)))
1519 (and (undo-entry-marker-distance alist-elt) ;(cdr alist-elt)
1520 (>= (undo-entry-marker-distance alist-elt) start)
1521 (<= (undo-entry-marker-distance alist-elt) end))))
1522 ((typep undo-elt 'undo-entry-property) ;(null (car undo-elt))
1523 ;; (nil PROPERTY VALUE BEG . END)
1524 (and (>= (undo-entry-property-beg undo-elt) start)
1525 (<= (undo-entry-property-end undo-elt) end)))
1526 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1527 ;; (BEGIN . END)
1528 (and (>= (undo-entry-insertion-beg undo-elt) start)
1529 (<= (undo-entry-insertion-end undo-elt) end)))))
1531 (defun undo-elt-crosses-region (undo-elt start end)
1532 "Test whether UNDO-ELT crosses one edge of that region START ... END.
1533 This assumes we have already decided that UNDO-ELT
1534 is not *inside* the region START...END."
1535 (cond ;; (atom undo-elt) nil)
1536 ((typep undo-elt 'undo-entry-property) ;(null (car undo-elt))
1537 ;; (nil PROPERTY VALUE BEG . END)
1538 ;;(let ((tail (nthcdr 3 undo-elt)))
1539 (not (or (< (undo-entry-property-beg undo-elt) end)
1540 (> (undo-entry-property-end undo-elt) start))))
1541 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1542 ;; (BEGIN . END)
1543 (not (or (< (undo-entry-insertion-beg undo-elt) end)
1544 (> (undo-entry-insertion-end undo-elt) start))))))
1546 ;; Return the first affected buffer position and the delta for an undo element
1547 ;; delta is defined as the change in subsequent buffer positions if we *did*
1548 ;; the undo.
1549 (defun undo-delta (undo-elt)
1550 (cond ((typep undo-elt 'undo-entry-delete) ;(stringp (car undo-elt))
1551 ;; (TEXT . POSITION)
1552 (cons (abs (undo-entry-delete-position undo-elt)) (length (undo-entry-delete-text undo-elt))))
1553 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1554 ;; (BEGIN . END)
1555 (cons (undo-entry-insertion-beg undo-elt) (- (undo-entry-insertion-beg undo-elt) (undo-entry-insertion-end undo-elt))))
1557 '(0 . 0))))
1559 (defcustom undo-ask-before-discard nil
1560 "If non-nil ask about discarding undo info for the current command.
1561 Normally, Emacs discards the undo info for the current command if
1562 it exceeds `undo-outer-limit'. But if you set this option
1563 non-nil, it asks in the echo area whether to discard the info.
1564 If you answer no, there a slight risk that Emacs might crash, so
1565 only do it if you really want to undo the command.
1567 This option is mainly intended for debugging. You have to be
1568 careful if you use it for other purposes. Garbage collection is
1569 inhibited while the question is asked, meaning that Emacs might
1570 leak memory. So you should make sure that you do not wait
1571 excessively long before answering the question."
1572 :type 'boolean
1573 :group 'undo
1574 :version "22.1")
1576 (define-buffer-local *undo-extra-outer-limit* 'undo-outer-limit-truncate ;;nil
1577 "If non-nil, an extra level of size that's ok in an undo item.
1578 We don't ask the user about truncating the undo list until the
1579 current item gets bigger than this amount.
1581 This variable only matters if `undo-ask-before-discard' is non-nil.")
1583 ;;(make-variable-buffer-local 'undo-extra-outer-limit)
1585 ;; When the first undo batch in an undo list is longer than
1586 ;; undo-outer-limit, this function gets called to warn the user that
1587 ;; the undo info for the current command was discarded. Garbage
1588 ;; collection is inhibited around the call, so it had better not do a
1589 ;; lot of consing.
1590 ;;(setq undo-outer-limit-function 'undo-outer-limit-truncate)
1591 (defun undo-outer-limit-truncate (size)
1592 (if undo-ask-before-discard
1593 (when (or (null *undo-extra-outer-limit*)
1594 (> size *undo-extra-outer-limit*))
1595 ;; Don't ask the question again unless it gets even bigger.
1596 ;; This applies, in particular, if the user quits from the question.
1597 ;; Such a quit quits out of GC, but something else will call GC
1598 ;; again momentarily. It will call this function again,
1599 ;; but we don't want to ask the question again.
1600 (setf *undo-extra-outer-limit* (+ size 50000))
1601 (if (let (*use-dialog-box* *track-mouse* *executing-kbd-macro* )
1602 (yes-or-no-p (format nil "Buffer `~a' undo info is ~d bytes long; discard it? "
1603 (buffer-name (current-buffer)) size)))
1604 (progn (setf (buffer-undo-list (current-buffer)) nil)
1605 (setf *undo-extra-outer-limit* nil)
1607 nil))
1608 (progn
1609 (display-warning '(undo discard-info)
1610 (concat
1611 (format nil "Buffer `~a' undo info was ~d bytes long.~%"
1612 (buffer-name (current-buffer)) size)
1613 "The undo info was discarded because it exceeded \
1614 `undo-outer-limit'.
1616 This is normal if you executed a command that made a huge change
1617 to the buffer. In that case, to prevent similar problems in the
1618 future, set `undo-outer-limit' to a value that is large enough to
1619 cover the maximum size of normal changes you expect a single
1620 command to make, but not so large that it might exceed the
1621 maximum memory allotted to Emacs.
1623 If you did not execute any such command, the situation is
1624 probably due to a bug and you should report it.
1626 You can disable the popping up of this buffer by adding the entry
1627 \(undo discard-info) to the user option `warning-suppress-types'.
1629 :warning)
1630 (setf (buffer-undo-list (current-buffer)) nil)
1631 t)))
1634 (defcommand kill-word ((arg)
1635 :prefix)
1636 "Kill characters forward until encountering the end of a word.
1637 With argument, do this that many times."
1638 (kill-region (point) (progn (forward-word arg) (point))))
1640 (defcommand backward-kill-word ((arg)
1641 :prefix)
1642 "Kill characters backward until encountering the end of a word.
1643 With argument, do this that many times."
1644 (kill-word (- arg)))
1646 (defcommand backward-word ((n) :prefix)
1647 "Move point forward ARG words (backward if ARG is negative).
1648 Normally returns t.
1649 If an edge of the buffer or a field boundary is reached, point is left there
1650 and the function returns nil. Field boundaries are not noticed if
1651 `inhibit-field-text-motion' is non-nil."
1652 (forward-word (- n)))
1654 (defcommand forward-word ((n) :prefix)
1655 "Move point forward ARG words (backward if ARG is negative).
1656 Normally returns t.
1657 If an edge of the buffer or a field boundary is reached, point is left there
1658 and the function returns nil. Field boundaries are not noticed if
1659 `inhibit-field-text-motion' is non-nil."
1660 (labels ((isaword (c)
1661 (find c +word-constituents+ :test #'char=)))
1662 (let ((buffer (current-buffer)))
1663 (cond ((> n 0)
1664 (gap-move-to buffer (buffer-point-aref buffer))
1665 ;; do it n times
1666 (loop for i from 0 below n
1667 while (let (p1 p2)
1668 ;; search forward for a word constituent
1669 (setf p1 (position-if #'isaword (buffer-data buffer)
1670 :start (buffer-point-aref buffer)))
1671 ;; search forward for a non word constituent
1672 (when p1
1673 (setf p2 (position-if (complement #'isaword) (buffer-data buffer) :start p1)))
1674 (if p2
1675 (goto-char (buffer-aref-to-char buffer p2))
1676 (goto-char (point-max)))
1677 p2)))
1678 ((< n 0)
1679 (setf n (- n))
1680 (gap-move-to buffer (buffer-point-aref buffer))
1681 ;; do it n times
1682 (loop for i from 0 below n
1683 for start = (buffer-gap-start buffer) then (buffer-point-aref buffer)
1684 while (let (p1 p2)
1685 ;; search backward for a word constituent
1686 (setf p1 (position-if #'isaword (buffer-data buffer)
1687 :from-end t
1688 :end start))
1689 ;; search backward for a non word constituent
1690 (when p1
1691 (setf p2 (position-if (complement #'isaword) (buffer-data buffer) :from-end t :end p1)))
1692 (if p2
1693 (goto-char (1+ (buffer-aref-to-char buffer p2)))
1694 (goto-char (point-min)))
1695 p2)))))))
1697 (provide :lice-0.1/simple)