fix split-window command
[lice.git] / src / lisp / simple.lisp
blob9d34504a6ef175deee3d62163087faad45ba4123
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)))))
446 (defcommand end-of-line ((&optional (n 1))
447 :prefix)
448 "Move point to end of current line.
449 With argument N not nil or 1, move forward N - 1 lines first.
450 If point reaches the beginning or end of buffer, it stops there.
451 To ignore intangibility, bind `inhibit-point-motion-hooks' to t.
453 This function constrains point to the current field unless this moves
454 point to a different line than the original, unconstrained result. If
455 N is nil or 1, and a rear-sticky field ends at point, the point does
456 not move. To ignore field boundaries bind `inhibit-field-text-motion'
457 to t."
458 (let (newpos)
459 (loop
460 (setf newpos (line-end-position n))
461 (set-point newpos)
462 (cond
463 ((and (> (point) newpos)
464 (char= (buffer-fetch-char (1- (point)) (current-buffer))
465 #\Newline))
466 ;; If we skipped over a newline that follows an invisible
467 ;; intangible run, move back to the last tangible position
468 ;; within the line.
469 (set-point (1- (point)))
470 (return))
471 ((and (> (point) newpos)
472 (< (point) (zv))
473 (char/= (buffer-fetch-char (point) (current-buffer))
474 #\Newline))
475 ;; If we skipped something intangible and now we're not
476 ;; really at eol, keep going.
477 (setf n 1))
478 (t (return))))
479 nil))
481 (defcommand move-end-of-line ((arg)
482 :prefix)
483 "Move point to end of current line as displayed.
484 \(If there's an image in the line, this disregards newlines
485 which are part of the text that the image rests on.)
487 With argument ARG not nil or 1, move forward ARG - 1 lines first.
488 If point reaches the beginning or end of buffer, it stops there.
489 To ignore intangibility, bind `inhibit-point-motion-hooks' to t."
490 (or arg (setq arg 1))
491 (let (done)
492 (while (not done)
493 (let ((newpos
494 (save-excursion
495 (let ((goal-column 0))
496 (and (line-move arg t)
497 (not (bobp))
498 (progn
499 (while (and (not (bobp)) (line-move-invisible-p (1- (point))))
500 (goto-char (previous-char-property-change (point))))
501 (backward-char 1)))
502 (point)))))
503 (goto-char newpos)
504 (if (and (> (point) newpos)
505 (eq (preceding-char) #\Newline))
506 (backward-char 1)
507 (if (and (> (point) newpos) (not (eobp))
508 (not (eq (following-char) #\Newline)))
509 ;; If we skipped something intangible
510 ;; and now we're not really at eol,
511 ;; keep going.
512 (setq arg 1)
513 (setq done t)))))))
515 (defcommand execute-extended-command ((prefix)
516 :raw-prefix)
517 "Read a user command from the minibuffer."
518 (let* ((name (read-command (case (prefix-numeric-value prefix)
519 (1 "M-x ")
520 (4 "C-u M-x ")
521 (t (format nil "~a M-x " prefix)))))
522 (cmd (lookup-command name)))
523 (if cmd
524 (let ((*prefix-arg* prefix))
525 (dispatch-command name)
526 (setf *this-command* (command-name cmd)))
527 (message "No Match"))))
529 (defcommand switch-to-buffer ((buffer &optional norecord)
530 (:buffer "Switch To Buffer: " (buffer-name (other-buffer (current-buffer)))))
531 "Select buffer buffer in the current window.
532 If buffer does not identify an existing buffer,
533 then this function creates a buffer with that name.
535 When called from Lisp, buffer may be a buffer, a string (a buffer name),
536 or nil. If buffer is nil, then this function chooses a buffer
537 using `other-buffer'.
538 Optional second arg norecord non-nil means
539 do not put this buffer at the front of the list of recently selected ones.
540 This function returns the buffer it switched to.
542 WARNING: This is NOT the way to work on another buffer temporarily
543 within a Lisp program! Use `set-buffer' instead. That avoids messing with
544 the window-buffer correspondences."
545 (unless buffer
546 (setf buffer (other-buffer (current-buffer))))
547 (let ((w (frame-selected-window (selected-frame))))
548 (when (typep w 'minibuffer-window)
549 (error "its a minibuffer"))
550 (setf buffer (get-buffer-create buffer))
551 (set-buffer buffer)
552 (unless norecord
553 (record-buffer buffer))
554 (set-window-buffer w buffer)))
556 (defun eval-echo (string)
557 ;; FIXME: don't just abandon the output
558 (let* ((stream (make-string-output-stream))
559 (*standard-output* stream)
560 (*error-output* stream)
561 (*debug-io* stream))
562 (multiple-value-bind (sexpr pos) (read-from-string string)
563 (if (= pos (length string))
564 (message "~s" (eval sexpr))
565 (error "Trailing garbage is ~a" string)))))
567 (defun eval-print (string)
568 (multiple-value-bind (sexpr pos) (read-from-string string)
569 (if (= pos (length string))
570 (insert (format nil "~%~s~%" (eval sexpr)))
571 (error "Trailing garbage is ~a" string))))
573 (defcommand eval-expression ((s)
574 (:string "Eval: "))
575 ;;(handler-case
576 (eval-echo s))
577 ;;(error (c) (message "Eval error: ~s" c))))
579 (defcommand exchange-point-and-mark ()
580 (let ((p (point)))
581 (goto-char (marker-position (mark-marker)))
582 (set-marker (mark-marker) p)))
584 ;; FIXME: this variable is here just so code compiles. we still need
585 ;; to implement it.
586 (defvar transient-mark-mode nil)
588 (defcommand set-mark-command ()
589 (set-marker (mark-marker) (point))
590 (message "Mark set"))
592 (defun push-mark (&optional location nomsg activate)
593 "Set mark at LOCATION (point, by default) and push old mark on mark ring.
594 If the last global mark pushed was not in the current buffer,
595 also push LOCATION on the global mark ring.
596 Display `Mark set' unless the optional second arg NOMSG is non-nil.
597 In Transient Mark mode, activate mark if optional third arg ACTIVATE non-nil.
599 Novice Emacs Lisp programmers often try to use the mark for the wrong
600 purposes. See the documentation of `set-mark' for more information.
602 In Transient Mark mode, this does not activate the mark."
603 (declare (ignore location activate))
604 ;; TODO implement
605 (set-marker (mark-marker) (point))
606 (unless nomsg
607 (message "Mark set")))
609 ;; (defun kill-ring-save (beg end)
610 ;; "Save the region to the kill ring."
612 (defcommand scroll-up ((&optional arg)
613 :raw-prefix)
614 (let ((win (selected-window)))
615 (window-scroll-up win (max 1 (or (and arg (prefix-numeric-value arg))
616 (- (window-height win nil)
617 *next-screen-context-lines*))))))
619 (defcommand scroll-down ((&optional arg)
620 :raw-prefix)
621 (let ((win (selected-window)))
622 (window-scroll-down win (max 1 (or (and arg (prefix-numeric-value arg))
623 (- (window-height win nil)
624 *next-screen-context-lines*))))))
626 (defcommand end-of-buffer ()
627 "Move point to the end of the buffer; leave mark at previous position.
628 With arg N, put point N/10 of the way from the end.
630 If the buffer is narrowed, this command uses the beginning and size
631 of the accessible part of the buffer."
632 (set-mark-command)
633 (goto-char (point-max)))
635 (defcommand just-one-space ((&optional (n 1))
636 :prefix)
637 "Delete all spaces and tabs around point, leaving one space (or N spaces)."
638 (let ((orig-pos (point)))
639 (skip-chars-backward (coerce '(#\Space #\Tab) 'string))
640 (constrain-to-field nil orig-pos)
641 (dotimes (i n)
642 (if (char= (following-char) #\Space)
643 (forward-char 1)
644 (insert #\Space)))
645 (delete-region
646 (point)
647 (progn
648 (skip-whitespace-forward)
649 (constrain-to-field nil orig-pos t)))))
651 (defcommand beginning-of-buffer ()
652 "Move point to the beginning of the buffer; leave mark at previous position.
653 With arg N, put point N/10 of the way from the beginning.
655 If the buffer is narrowed, this command uses the beginning and size
656 of the accessible part of the buffer."
657 (set-mark-command)
658 (goto-char (point-min)))
660 (defcommand split-window ()
661 (split-window-internal (selected-window)))
663 (defcommand split-window-horizontally ()
664 (split-window-internal (selected-window) nil t))
666 (defcommand switch-to-buffer-other-window ((buffer)
667 (:buffer "Switch to buffer in other window: " (buffer-name (other-buffer (current-buffer)))))
668 (let* ((cw (selected-window))
669 (w (or (next-window cw)
670 (split-window-internal cw))))
671 (select-window w)
672 (switch-to-buffer buffer)))
674 (defcommand keyboard-quit ()
675 (signal 'quit))
677 ;;; kill ring
679 (defun kill-new (string &optional replace)
680 "Make STRING the latest kill in the kill ring.
681 Set the kill-ring-yank pointer to point to it.
682 Optional second argument REPLACE non-nil means that STRING will replace
683 the front of the kill ring, rather than being added to the list."
684 (if (and replace
685 *kill-ring*)
686 (setf (car *kill-ring*) string)
687 (push string *kill-ring*))
688 (when (> (length *kill-ring*) *kill-ring-max*)
689 (setf (cdr (nthcdr (1- *kill-ring-max*) *kill-ring*)) nil))
690 (setf *kill-ring-yank-pointer* *kill-ring*))
692 (defun copy-region-as-kill (start end &optional (buffer (current-buffer)))
693 (multiple-value-setq (start end) (validate-region start end buffer))
694 (kill-new (buffer-substring start end buffer)))
696 (defcommand kill-ring-save ()
697 (copy-region-as-kill (mark) (point)))
699 (defcommand kill-region ((beg end)
700 :region-beginning
701 :region-end)
702 "Kill between point and mark.
703 The text is deleted but saved in the kill ring.
704 The command C-y can retrieve it from there.
705 (If you want to kill and then yank immediately, use M-w.)"
706 (copy-region-as-kill beg end)
707 (delete-region beg end))
710 (defcommand kill-line ()
711 (kill-region (point)
712 (progn
713 (when (eobp)
714 (signal 'end-of-buffer))
715 (if (char= (buffer-char-after (current-buffer) (point)) #\Newline)
716 (forward-line 1)
717 (goto-char (buffer-end-of-line)))
718 (point))))
720 (defun current-kill (n &optional do-not-move)
721 "Rotate the yanking point by N places, and then return that kill.
722 If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
723 yanking point; just return the Nth kill forward."
724 (unless *kill-ring*
725 (signal 'kill-ring-empty))
726 (let ((argth-kill-element
727 (nthcdr (mod (- n (length *kill-ring-yank-pointer*))
728 (length *kill-ring*))
729 *kill-ring*)))
730 (unless do-not-move
731 (setf *kill-ring-yank-pointer* argth-kill-element))
732 (car argth-kill-element)))
734 (defcommand yank ()
735 (set-mark-command)
736 (insert (current-kill 0)))
738 (defcommand yank-pop ()
739 (unless (eq *last-command* 'yank)
740 (error "Previous command was not a yank: ~a" *last-command*))
741 (setf *this-command* 'yank)
742 (delete-region (mark) (point))
743 (insert (current-kill 1)))
745 ;;; universal argument
747 (defun prefix-arg ()
748 "Return numeric meaning of *prefix-arg*"
749 (prefix-numeric-value *prefix-arg*))
751 (defun raw-prefix-arg ()
752 "Return the current prefix arg in raw form."
753 *prefix-arg*)
755 (defvar *overriding-map-is-bound* nil)
756 (defvar *saved-overriding-map* nil)
757 (defvar *universal-argument-num-events* nil)
759 (defvar *universal-argument-map*
760 (let ((map (make-sparse-keymap)))
761 ;;(define-key map (kbd "t") 'universal-argument-other-key)
762 (define-key map t 'universal-argument-other-key)
763 ;;(define-key map [switch-frame] nil)
764 (define-key map (kbd "C-u") 'universal-argument-more)
765 (define-key map (kbd "-") 'universal-argument-minus)
766 (define-key map (kbd "0") 'digit-argument)
767 (define-key map (kbd "1") 'digit-argument)
768 (define-key map (kbd "2") 'digit-argument)
769 (define-key map (kbd "3") 'digit-argument)
770 (define-key map (kbd "4") 'digit-argument)
771 (define-key map (kbd "5") 'digit-argument)
772 (define-key map (kbd "6") 'digit-argument)
773 (define-key map (kbd "7") 'digit-argument)
774 (define-key map (kbd "8") 'digit-argument)
775 (define-key map (kbd "9") 'digit-argument)
776 ;; (define-key map [kp-0] 'digit-argument)
777 ;; (define-key map [kp-1] 'digit-argument)
778 ;; (define-key map [kp-2] 'digit-argument)
779 ;; (define-key map [kp-3] 'digit-argument)
780 ;; (define-key map [kp-4] 'digit-argument)
781 ;; (define-key map [kp-5] 'digit-argument)
782 ;; (define-key map [kp-6] 'digit-argument)
783 ;; (define-key map [kp-7] 'digit-argument)
784 ;; (define-key map [kp-8] 'digit-argument)
785 ;; (define-key map [kp-9] 'digit-argument)
786 ;; (define-key map [kp-subtract] 'universal-argument-minus)
787 map)
788 "Keymap used while processing \\[universal-argument].")
790 (defun ensure-overriding-map-is-bound ()
791 "Check `*overriding-terminal-local-map*' is `*universal-argument-map*'."
792 (unless *overriding-map-is-bound*
793 (setf *saved-overriding-map* *overriding-terminal-local-map*
794 *overriding-terminal-local-map* *universal-argument-map*
795 *overriding-map-is-bound* t)))
797 (defun restore-overriding-map ()
798 "Restore `*overriding-terminal-local-map*' to its saved value."
799 (setf *overriding-terminal-local-map* *saved-overriding-map*
800 *overriding-map-is-bound* nil))
802 (defcommand universal-argument ()
803 (setf *prefix-arg* (list 4)
804 *universal-argument-num-events* (length (this-command-keys)))
805 (ensure-overriding-map-is-bound))
807 (defcommand universal-argument-more ((arg)
808 :raw-prefix)
809 (if (consp arg)
810 (setf *prefix-arg* (list (* 4 (car arg))))
811 (if (eq arg '-)
812 (setf *prefix-arg* (list -4))
813 (progn
814 (setf *prefix-arg* arg)
815 (restore-overriding-map))))
816 (setf *universal-argument-num-events* (length (this-command-keys))))
818 (defcommand negative-argument ((arg)
819 :raw-prefix)
820 "Begin a negative numeric argument for the next command.
821 \\[universal-argument] following digits or minus sign ends the argument."
822 (cond ((integerp arg)
823 (setf *prefix-arg* (- arg)))
824 ((eq arg '-)
825 (setf *prefix-arg* nil))
827 (setf *prefix-arg* '-)))
828 (setf *universal-argument-num-events* (length (this-command-keys)))
829 (ensure-overriding-map-is-bound))
831 (defcommand digit-argument ((arg)
832 :raw-prefix)
833 "Part of the numeric argument for the next command.
834 \\[universal-argument] following digits or minus sign ends the argument."
835 (let* ((char (last-command-char))
836 (digit (- (logand (char-code char) #o177) (char-code #\0))))
837 (cond ((integerp arg)
838 (setf *prefix-arg* (+ (* arg 10)
839 (if (< arg 0) (- digit) digit))))
840 ((eq arg '-)
841 ;; Treat -0 as just -, so that -01 will work.
842 (setf *prefix-arg* (if (zerop digit) '- (- digit))))
844 (setf *prefix-arg* digit))))
845 (setf *universal-argument-num-events* (length (this-command-keys)))
846 (ensure-overriding-map-is-bound))
848 ;; For backward compatibility, minus with no modifiers is an ordinary
849 ;; command if digits have already been entered.
850 (defcommand universal-argument-minus ((arg)
851 :raw-prefix)
852 (if (integerp arg)
853 (universal-argument-other-key arg)
854 (negative-argument arg)))
856 ;; Anything else terminates the argument and is left in the queue to be
857 ;; executed as a command.
858 (defcommand universal-argument-other-key ((arg)
859 :raw-prefix)
860 (setf *prefix-arg* arg)
861 (let* ((keylist (this-command-keys)))
862 (setf *unread-command-events* keylist))
863 ;; (append (nthcdr *universal-argument-num-events* keylist)
864 ;; *unread-command-events*)))
865 ;;FIXME: (reset-this-command-lengths)
866 (restore-overriding-map))
869 ;; (defcommand append-to-buffer ((buffer :buffer "Append to buffer: " (buffer-name (other-buffer (current-buffer))))
870 ;; (start :region-beginning)
871 ;; (end :region-end))
872 ;; "Append to specified buffer the text of the region.
873 ;; It is inserted into that buffer before its point.
875 ;; When calling from a program, give three arguments:
876 ;; buffer (or buffer name), start and end.
877 ;; start and end specify the portion of the current buffer to be copied."
878 ;; (let ((oldbuf (current-buffer)))
879 ;; (save-excursion
880 ;; (let* ((append-to (get-buffer-create buffer))
881 ;; (windows (get-buffer-window-list append-to t t))
882 ;; point)
883 ;; (set-buffer append-to)
884 ;; (setf point (point))
885 ;; (barf-if-buffer-read-only)
886 ;; (insert-buffer-substring oldbuf start end)
887 ;; (dolist (window windows)
888 ;; (when (= (window-point window) point)
889 ;; (set-window-point window (point))))))))
891 (defcommand transpose-chars ((arg)
892 :prefix)
893 "Interchange characters around point, moving forward one character.
894 With prefix arg ARG, effect is to take character before point
895 and drag it forward past ARG other characters (backward if ARG negative).
896 If no argument and at end of line, the previous two chars are exchanged."
897 (and (null arg) (eolp) (forward-char -1))
898 (transpose-subr 'forward-char (prefix-numeric-value arg)))
900 (defcommand transpose-words ((arg)
901 :prefix)
902 "Interchange words around point, leaving point at end of them.
903 With prefix arg ARG, effect is to take word before or around point
904 and drag it forward past ARG other words (backward if ARG negative).
905 If ARG is zero, the words around or after point and around or after mark
906 are interchanged."
907 ;; FIXME: `foo a!nd bar' should transpose into `bar and foo'.
908 (transpose-subr 'forward-word arg))
910 ;; (defun transpose-sexps ((arg)
911 ;; :prefix)
912 ;; "Like \\[transpose-words] but applies to sexps.
913 ;; Does not work on a sexp that point is in the middle of
914 ;; if it is a list or string."
915 ;; (transpose-subr
916 ;; (lambda (arg)
917 ;; ;; Here we should try to simulate the behavior of
918 ;; ;; (cons (progn (forward-sexp x) (point))
919 ;; ;; (progn (forward-sexp (- x)) (point)))
920 ;; ;; Except that we don't want to rely on the second forward-sexp
921 ;; ;; putting us back to where we want to be, since forward-sexp-function
922 ;; ;; might do funny things like infix-precedence.
923 ;; (if (if (> arg 0)
924 ;; ;;(looking-at "\\sw\\|\\s_")
925 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
926 ;; (or (alpha-char-p (char-after (point)))
927 ;; (find (char-after (point)) "*/+-%$!@&"))
928 ;; (and (not (bobp))
929 ;; (save-excursion (forward-char -1)
930 ;; ;; (looking-at "\\sw\\|\\s_")
931 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
932 ;; (or (alpha-char-p (char-after (point)))
933 ;; (find (char-after (point)) "*/+-%$!@&"))
934 ;; )))
935 ;; ;; Jumping over a symbol. We might be inside it, mind you.
936 ;; (progn (funcall (if (> arg 0)
937 ;; 'skip-syntax-backward 'skip-syntax-forward)
938 ;; "w_")
939 ;; (cons (save-excursion (forward-sexp arg) (point)) (point)))
940 ;; ;; Otherwise, we're between sexps. Take a step back before jumping
941 ;; ;; to make sure we'll obey the same precedence no matter which direction
942 ;; ;; we're going.
943 ;; (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) " .")
944 ;; (cons (save-excursion (forward-sexp arg) (point))
945 ;; (progn (while (or (forward-comment (if (> arg 0) 1 -1))
946 ;; (not (zerop (funcall (if (> arg 0)
947 ;; 'skip-syntax-forward
948 ;; 'skip-syntax-backward)
949 ;; ".")))))
950 ;; (point)))))
951 ;; arg 'special))
953 (defcommand transpose-lines ((arg)
954 :prefix)
955 "Exchange current line and previous line, leaving point after both.
956 With argument ARG, takes previous line and moves it past ARG lines.
957 With argument 0, interchanges line point is in with line mark is in."
958 (transpose-subr (function
959 (lambda (arg)
960 (if (> arg 0)
961 (progn
962 ;; Move forward over ARG lines,
963 ;; but create newlines if necessary.
964 (setq arg (forward-line arg))
965 (if (char/= (preceding-char) #\Newline)
966 (setq arg (1+ arg)))
967 (if (> arg 0)
968 (newline arg)))
969 (forward-line arg))))
970 arg))
972 (defun transpose-subr (mover arg &optional special)
973 (let ((aux (if special mover
974 (lambda (x)
975 (cons (progn (funcall mover x) (point))
976 (progn (funcall mover (- x)) (point))))))
977 pos1 pos2)
978 (cond
979 ((= arg 0)
980 (save-excursion
981 (setq pos1 (funcall aux 1))
982 (goto-char (mark))
983 (setq pos2 (funcall aux 1))
984 (transpose-subr-1 pos1 pos2))
985 (exchange-point-and-mark))
986 ((> arg 0)
987 (setq pos1 (funcall aux -1))
988 (setq pos2 (funcall aux arg))
989 (transpose-subr-1 pos1 pos2)
990 (goto-char (car pos2)))
992 (setq pos1 (funcall aux -1))
993 (goto-char (car pos1))
994 (setq pos2 (funcall aux arg))
995 (transpose-subr-1 pos1 pos2)))))
997 (defun transpose-subr-1 (pos1 pos2)
998 (when (> (car pos1) (cdr pos1)) (setq pos1 (cons (cdr pos1) (car pos1))))
999 (when (> (car pos2) (cdr pos2)) (setq pos2 (cons (cdr pos2) (car pos2))))
1000 (when (> (car pos1) (car pos2))
1001 (let ((swap pos1))
1002 (setq pos1 pos2 pos2 swap)))
1003 (if (> (cdr pos1) (car pos2)) (error "Don't have two things to transpose"))
1004 ;; (atomic-change-group
1005 (let (word2)
1006 ;; FIXME: We first delete the two pieces of text, so markers that
1007 ;; used to point to after the text end up pointing to before it :-(
1008 (setq word2 (delete-and-extract-region (car pos2) (cdr pos2)))
1009 (goto-char (car pos2))
1010 (insert (delete-and-extract-region (car pos1) (cdr pos1)))
1011 (goto-char (car pos1))
1012 (insert word2)))
1015 ;;;
1017 (defcustom-buffer-local *fill-prefix* nil
1018 "*String for filling to insert at front of new line, or nil for none."
1019 :type '(choice (const :tag "None" nil)
1020 string)
1021 :group 'fill)
1023 (defvar *fundamental-mode*
1024 (make-instance 'major-mode
1025 :name "Fundamental")
1026 "Major mode not specialized for anything in particular.
1027 Other major modes are defined by comparison with this one.")
1029 (defun fundamental-mode ()
1030 (set-major-mode '*fundamental-mode*))
1032 (defun turn-on-auto-fill ()
1033 "Unconditionally turn on Auto Fill mode."
1034 ;; FIXME: implement
1037 (define-buffer-local comment-line-break-function 'comment-indent-new-line
1038 "*Mode-specific function which line breaks and continues a comment.
1040 This function is only called during auto-filling of a comment section.
1041 The function should take a single optional argument, which is a flag
1042 indicating whether it should use soft newlines.")
1044 (defun do-auto-fill ()
1045 "This function is used as the auto-fill-function of a buffer
1046 when Auto-Fill mode is enabled.
1047 It returns t if it really did any work.
1048 \(Actually some major modes use a different auto-fill function,
1049 but this one is the default one.)"
1050 (let (fc justify give-up
1051 (*fill-prefix* *fill-prefix*))
1052 (el:if (or (not (setq justify (current-justification)))
1053 (null (setq fc (current-fill-column)))
1054 (and (eq justify 'left)
1055 (<= (current-column) fc))
1056 (and auto-fill-inhibit-regexp
1057 (save-excursion (beginning-of-line)
1058 (looking-at auto-fill-inhibit-regexp))))
1059 nil ;; Auto-filling not required
1060 (el:if (memq justify '(full center right))
1061 (save-excursion (unjustify-current-line)))
1063 ;; Choose a *fill-prefix* automatically.
1064 (when (and adaptive-fill-mode
1065 (or (null *fill-prefix*) (string= *fill-prefix* "")))
1066 (let ((prefix
1067 (fill-context-prefix
1068 (save-excursion (backward-paragraph 1) (point))
1069 (save-excursion (forward-paragraph 1) (point)))))
1070 (and prefix (not (equal prefix ""))
1071 ;; Use auto-indentation rather than a guessed empty prefix.
1072 (not (and fill-indent-according-to-mode
1073 (string-match "\\`[ \t]*\\'" prefix)))
1074 (setq *fill-prefix* prefix))))
1076 (while (and (not give-up) (> (current-column) fc))
1077 ;; Determine where to split the line.
1078 (let* (after-prefix
1079 (fill-point
1080 (save-excursion
1081 (beginning-of-line)
1082 (setq after-prefix (point))
1083 (and *fill-prefix*
1084 (looking-at (regexp-quote *fill-prefix*))
1085 (setq after-prefix (match-end 0)))
1086 (move-to-column (1+ fc))
1087 (fill-move-to-break-point after-prefix)
1088 (point))))
1090 ;; See whether the place we found is any good.
1091 (el:if (save-excursion
1092 (goto-char fill-point)
1093 (or (bolp)
1094 ;; There is no use breaking at end of line.
1095 (save-excursion (skip-chars-forward " ") (eolp))
1096 ;; It is futile to split at the end of the prefix
1097 ;; since we would just insert the prefix again.
1098 (and after-prefix (<= (point) after-prefix))
1099 ;; Don't split right after a comment starter
1100 ;; since we would just make another comment starter.
1101 (and comment-start-skip
1102 (let ((limit (point)))
1103 (beginning-of-line)
1104 (and (re-search-forward comment-start-skip
1105 limit t)
1106 (eq (point) limit))))))
1107 ;; No good place to break => stop trying.
1108 (setq give-up t)
1109 ;; Ok, we have a useful place to break the line. Do it.
1110 (let ((prev-column (current-column)))
1111 ;; If point is at the fill-point, do not `save-excursion'.
1112 ;; Otherwise, if a comment prefix or *fill-prefix* is inserted,
1113 ;; point will end up before it rather than after it.
1114 (el:if (save-excursion
1115 (skip-chars-backward " \t")
1116 (= (point) fill-point))
1117 (funcall comment-line-break-function t)
1118 (save-excursion
1119 (goto-char fill-point)
1120 (funcall comment-line-break-function t)))
1121 ;; Now do justification, if required
1122 (el:if (not (eq justify 'left))
1123 (save-excursion
1124 (end-of-line 0)
1125 (justify-current-line justify nil t)))
1126 ;; If making the new line didn't reduce the hpos of
1127 ;; the end of the line, then give up now;
1128 ;; trying again will not help.
1129 (el:if (>= (current-column) prev-column)
1130 (setq give-up t))))))
1131 ;; Justify last line.
1132 (justify-current-line justify t t)
1133 t)))
1136 ;; FIXME: put this info in the following condition
1137 ;; (put 'mark-inactive 'error-conditions '(mark-inactive error))
1138 ;; (put 'mark-inactive 'error-message "The mark is not active now")
1140 (define-condition mark-inactive (lice-condition)
1143 (defvar activate-mark-hook nil
1144 "Hook run when the mark becomes active.
1145 It is also run at the end of a command, if the mark is active and
1146 it is possible that the region may have changed")
1148 (defvar deactivate-mark-hook nil
1149 "Hook run when the mark becomes inactive.")
1151 (defun mark (&optional force)
1152 "Return this buffer's mark value as integer, or nil if never set.
1154 In Transient Mark mode, this function signals an error if
1155 the mark is not active. However, if `mark-even-if-inactive' is non-nil,
1156 or the argument FORCE is non-nil, it disregards whether the mark
1157 is active, and returns an integer or nil in the usual way.
1159 If you are using this in an editing command, you are most likely making
1160 a mistake; see the documentation of `set-mark'."
1161 (if (or force (not transient-mark-mode) mark-active mark-even-if-inactive)
1162 (marker-position (mark-marker))
1163 (signal 'mark-inactive nil)))
1165 ;; ;; Many places set mark-active directly, and several of them failed to also
1166 ;; ;; run deactivate-mark-hook. This shorthand should simplify.
1167 ;; (defsubst deactivate-mark ()
1168 ;; "Deactivate the mark by setting `mark-active' to nil.
1169 ;; \(That makes a difference only in Transient Mark mode.)
1170 ;; Also runs the hook `deactivate-mark-hook'."
1171 ;; (cond
1172 ;; ((eq transient-mark-mode 'lambda)
1173 ;; (setq transient-mark-mode nil))
1174 ;; (transient-mark-mode
1175 ;; (setq mark-active nil)
1176 ;; (run-hooks 'deactivate-mark-hook))))
1178 (defun set-mark (pos)
1179 "Set this buffer's mark to POS. Don't use this function!
1180 That is to say, don't use this function unless you want
1181 the user to see that the mark has moved, and you want the previous
1182 mark position to be lost.
1184 Normally, when a new mark is set, the old one should go on the stack.
1185 This is why most applications should use `push-mark', not `set-mark'.
1187 Novice Emacs Lisp programmers often try to use the mark for the wrong
1188 purposes. The mark saves a location for the user's convenience.
1189 Most editing commands should not alter the mark.
1190 To remember a location for internal use in the Lisp program,
1191 store it in a Lisp variable. Example:
1193 (let ((beg (point))) (forward-line 1) (delete-region beg (point)))."
1195 (if pos
1196 (progn
1197 (setq mark-active t)
1198 (run-hooks 'activate-mark-hook)
1199 (set-marker (mark-marker) pos (current-buffer)))
1200 ;; Normally we never clear mark-active except in Transient Mark mode.
1201 ;; But when we actually clear out the mark value too,
1202 ;; we must clear mark-active in any mode.
1203 (progn
1204 (setq mark-active nil)
1205 (run-hooks 'deactivate-mark-hook)
1206 (set-marker (mark-marker) nil))))
1208 (define-buffer-local mark-ring nil
1209 "The list of former marks of the current buffer, most recent first.")
1210 (make-variable-buffer-local 'mark-ring)
1211 (setf (get 'mark-ring 'permanent-local) t)
1213 (defcustom mark-ring-max 16
1214 "*Maximum size of mark ring. Start discarding off end if gets this big."
1215 :type 'integer
1216 :group 'editing-basics)
1218 (defvar global-mark-ring nil
1219 "The list of saved global marks, most recent first.")
1221 (defcustom global-mark-ring-max 16
1222 "*Maximum size of global mark ring. \
1223 Start discarding off end if gets this big."
1224 :type 'integer
1225 :group 'editing-basics)
1227 (defcommand pop-to-mark-command ()
1228 "Jump to mark, and pop a new position for mark off the ring
1229 \(does not affect global mark ring\)."
1230 (if (null (mark t))
1231 (error "No mark set in this buffer")
1232 (progn
1233 (goto-char (mark t))
1234 (pop-mark))))
1236 ;; (defun push-mark-command (arg &optional nomsg)
1237 ;; "Set mark at where point is.
1238 ;; If no prefix arg and mark is already set there, just activate it.
1239 ;; Display `Mark set' unless the optional second arg NOMSG is non-nil."
1240 ;; (interactive "P")
1241 ;; (let ((mark (marker-position (mark-marker))))
1242 ;; (if (or arg (null mark) (/= mark (point)))
1243 ;; (push-mark nil nomsg t)
1244 ;; (setq mark-active t)
1245 ;; (run-hooks 'activate-mark-hook)
1246 ;; (unless nomsg
1247 ;; (message "Mark activated")))))
1249 (defcustom set-mark-command-repeat-pop nil
1250 "*Non-nil means that repeating \\[set-mark-command] after popping will pop.
1251 This means that if you type C-u \\[set-mark-command] \\[set-mark-command]
1252 will pop twice."
1253 :type 'boolean
1254 :group 'editing)
1256 ;; (defun set-mark-command (arg)
1257 ;; "Set mark at where point is, or jump to mark.
1258 ;; With no prefix argument, set mark, and push old mark position on local
1259 ;; mark ring; also push mark on global mark ring if last mark was set in
1260 ;; another buffer. Immediately repeating the command activates
1261 ;; `transient-mark-mode' temporarily.
1263 ;; With argument, e.g. \\[universal-argument] \\[set-mark-command], \
1264 ;; jump to mark, and pop a new position
1265 ;; for mark off the local mark ring \(this does not affect the global
1266 ;; mark ring\). Use \\[pop-global-mark] to jump to a mark off the global
1267 ;; mark ring \(see `pop-global-mark'\).
1269 ;; If `set-mark-command-repeat-pop' is non-nil, repeating
1270 ;; the \\[set-mark-command] command with no prefix pops the next position
1271 ;; off the local (or global) mark ring and jumps there.
1273 ;; With a double \\[universal-argument] prefix argument, e.g. \\[universal-argument] \
1274 ;; \\[universal-argument] \\[set-mark-command], unconditionally
1275 ;; set mark where point is.
1277 ;; Setting the mark also sets the \"region\", which is the closest
1278 ;; equivalent in Emacs to what some editors call the \"selection\".
1280 ;; Novice Emacs Lisp programmers often try to use the mark for the wrong
1281 ;; purposes. See the documentation of `set-mark' for more information."
1282 ;; (interactive "P")
1283 ;; (if (eq transient-mark-mode 'lambda)
1284 ;; (setq transient-mark-mode nil))
1285 ;; (cond
1286 ;; ((and (consp arg) (> (prefix-numeric-value arg) 4))
1287 ;; (push-mark-command nil))
1288 ;; ((not (eq this-command 'set-mark-command))
1289 ;; (if arg
1290 ;; (pop-to-mark-command)
1291 ;; (push-mark-command t)))
1292 ;; ((and set-mark-command-repeat-pop
1293 ;; (eq last-command 'pop-to-mark-command))
1294 ;; (setq this-command 'pop-to-mark-command)
1295 ;; (pop-to-mark-command))
1296 ;; ((and set-mark-command-repeat-pop
1297 ;; (eq last-command 'pop-global-mark)
1298 ;; (not arg))
1299 ;; (setq this-command 'pop-global-mark)
1300 ;; (pop-global-mark))
1301 ;; (arg
1302 ;; (setq this-command 'pop-to-mark-command)
1303 ;; (pop-to-mark-command))
1304 ;; ((and (eq last-command 'set-mark-command)
1305 ;; mark-active (null transient-mark-mode))
1306 ;; (setq transient-mark-mode 'lambda)
1307 ;; (message "Transient-mark-mode temporarily enabled"))
1308 ;; (t
1309 ;; (push-mark-command nil))))
1311 ;; (defun push-mark (&optional location nomsg activate)
1312 ;; "Set mark at LOCATION (point, by default) and push old mark on mark ring.
1313 ;; If the last global mark pushed was not in the current buffer,
1314 ;; also push LOCATION on the global mark ring.
1315 ;; Display `Mark set' unless the optional second arg NOMSG is non-nil.
1316 ;; In Transient Mark mode, activate mark if optional third arg ACTIVATE non-nil.
1318 ;; Novice Emacs Lisp programmers often try to use the mark for the wrong
1319 ;; purposes. See the documentation of `set-mark' for more information.
1321 ;; In Transient Mark mode, this does not activate the mark."
1322 ;; (unless (null (mark t))
1323 ;; (setq mark-ring (cons (copy-marker (mark-marker)) mark-ring))
1324 ;; (when (> (length mark-ring) mark-ring-max)
1325 ;; (move-marker (car (nthcdr mark-ring-max mark-ring)) nil)
1326 ;; (setcdr (nthcdr (1- mark-ring-max) mark-ring) nil)))
1327 ;; (set-marker (mark-marker) (or location (point)) (current-buffer))
1328 ;; ;; Now push the mark on the global mark ring.
1329 ;; (if (and global-mark-ring
1330 ;; (eq (marker-buffer (car global-mark-ring)) (current-buffer)))
1331 ;; ;; The last global mark pushed was in this same buffer.
1332 ;; ;; Don't push another one.
1333 ;; nil
1334 ;; (setq global-mark-ring (cons (copy-marker (mark-marker)) global-mark-ring))
1335 ;; (when (> (length global-mark-ring) global-mark-ring-max)
1336 ;; (move-marker (car (nthcdr global-mark-ring-max global-mark-ring)) nil)
1337 ;; (setcdr (nthcdr (1- global-mark-ring-max) global-mark-ring) nil)))
1338 ;; (or nomsg executing-kbd-macro (> (minibuffer-depth) 0)
1339 ;; (message "Mark set"))
1340 ;; (if (or activate (not transient-mark-mode))
1341 ;; (set-mark (mark t)))
1342 ;; nil)
1344 ;; (defun pop-mark ()
1345 ;; "Pop off mark ring into the buffer's actual mark.
1346 ;; Does not set point. Does nothing if mark ring is empty."
1347 ;; (when mark-ring
1348 ;; (setq mark-ring (nconc mark-ring (list (copy-marker (mark-marker)))))
1349 ;; (set-marker (mark-marker) (+ 0 (car mark-ring)) (current-buffer))
1350 ;; (move-marker (car mark-ring) nil)
1351 ;; (if (null (mark t)) (ding))
1352 ;; (setq mark-ring (cdr mark-ring)))
1353 ;; (deactivate-mark))
1355 (defcommand back-to-indentation ()
1356 "Move point to the first non-whitespace character on this line."
1357 (beginning-of-line 1)
1358 (skip-syntax-forward '(:whitespace) (line-end-position))
1359 ;; Move back over chars that have whitespace syntax but have the p flag.
1360 (backward-prefix-chars))
1363 ;;; undo
1365 ;; XXX: gnu emacs uses a weak hashtable that automatically removes
1366 ;; references. We need some mechanism to do similar.
1367 (defvar undo-equiv-table (make-hash-table :test 'eq #|:weakness t|#)
1368 "Table mapping redo records to the corresponding undo one.
1369 A redo record for undo-in-region maps to t.
1370 A redo record for ordinary undo maps to the following (earlier) undo.")
1372 (defvar undo-in-region nil
1373 "Non-nil if `pending-undo-list' is not just a tail of `buffer-undo-list'.")
1375 (defvar undo-no-redo nil
1376 "If t, `undo' doesn't go through redo entries.")
1378 (defvar pending-undo-list nil
1379 "Within a run of consecutive undo commands, list remaining to be undone.
1380 If t, we undid all the way to the end of it.")
1382 (defcommand undo ((&optional arg)
1383 ;; XXX: what about the *?
1384 :raw-prefix)
1385 "Undo some previous changes.
1386 Repeat this command to undo more changes.
1387 A numeric argument serves as a repeat count.
1389 In Transient Mark mode when the mark is active, only undo changes within
1390 the current region. Similarly, when not in Transient Mark mode, just \\[universal-argument]
1391 as an argument limits undo to changes within the current region."
1392 ;;(interactive "*P")
1393 ;; Make last-command indicate for the next command that this was an undo.
1394 ;; That way, another undo will undo more.
1395 ;; If we get to the end of the undo history and get an error,
1396 ;; another undo command will find the undo history empty
1397 ;; and will get another error. To begin undoing the undos,
1398 ;; you must type some other command.
1399 (let ((modified (buffer-modified-p (current-buffer)))
1400 (recent-save (recent-auto-save-p))
1401 message)
1402 ;; If we get an error in undo-start,
1403 ;; the next command should not be a "consecutive undo".
1404 ;; So set `this-command' to something other than `undo'.
1405 (setq *this-command* 'undo-start)
1407 (unless (and (eq *last-command* 'undo)
1408 (or (eq pending-undo-list t)
1409 ;; If something (a timer or filter?) changed the buffer
1410 ;; since the previous command, don't continue the undo seq.
1411 (let ((list (buffer-undo-list (current-buffer))))
1412 (while (eq (car list) nil)
1413 (setq list (cdr list)))
1414 ;; If the last undo record made was made by undo
1415 ;; it shows nothing else happened in between.
1416 (gethash list undo-equiv-table))))
1417 (message "guuuungh")
1418 (setq undo-in-region
1419 (if transient-mark-mode *mark-active* (and arg (not (numberp arg)))))
1420 (if undo-in-region
1421 (undo-start (region-beginning) (region-end))
1422 (undo-start))
1423 ;; get rid of initial undo boundary
1424 (undo-more 1))
1425 ;; If we got this far, the next command should be a consecutive undo.
1426 (setq *this-command* 'undo)
1427 ;; Check to see whether we're hitting a redo record, and if
1428 ;; so, ask the user whether she wants to skip the redo/undo pair.
1429 (let ((equiv (gethash pending-undo-list undo-equiv-table)))
1430 (or (eq (selected-window) (minibuffer-window))
1431 (setq message (if undo-in-region
1432 (if equiv "Redo in region!" "Undo in region!")
1433 (if equiv "Redo!" "Undo!"))))
1434 (when (and (consp equiv) undo-no-redo)
1435 ;; The equiv entry might point to another redo record if we have done
1436 ;; undo-redo-undo-redo-... so skip to the very last equiv.
1437 (while (let ((next (gethash equiv undo-equiv-table)))
1438 (if next (setq equiv next))))
1439 (setq pending-undo-list equiv)))
1440 (undo-more
1441 (if (or transient-mark-mode (numberp arg))
1442 (prefix-numeric-value arg)
1444 ;; Record the fact that the just-generated undo records come from an
1445 ;; undo operation--that is, they are redo records.
1446 ;; In the ordinary case (not within a region), map the redo
1447 ;; record to the following undos.
1448 ;; I don't know how to do that in the undo-in-region case.
1449 (setf (gethash (buffer-undo-list (current-buffer)) undo-equiv-table)
1450 (if undo-in-region t pending-undo-list))
1451 ;; Don't specify a position in the undo record for the undo command.
1452 ;; Instead, undoing this should move point to where the change is.
1453 (let ((tail (buffer-undo-list (current-buffer)))
1454 (prev nil))
1455 (message "its: ~s" tail)
1456 (while (car tail)
1457 (when (integerp (car tail))
1458 (let ((pos (car tail)))
1459 (if prev
1460 (setf (cdr prev) (cdr tail))
1461 (setf (buffer-undo-list (current-buffer)) (cdr tail)))
1462 (setq tail (cdr tail))
1463 (while (car tail)
1464 (if (eql pos (car tail))
1465 (if prev
1466 (setf (cdr prev) (cdr tail))
1467 (setf (buffer-undo-list (current-buffer)) (cdr tail)))
1468 (setq prev tail))
1469 (setq tail (cdr tail)))
1470 (setq tail nil)))
1471 (setq prev tail
1472 tail (cdr tail))))
1473 ;; Record what the current undo list says,
1474 ;; so the next command can tell if the buffer was modified in between.
1475 (and modified (not (buffer-modified-p (current-buffer)))
1476 (delete-auto-save-file-if-necessary recent-save))
1477 ;; Display a message announcing success.
1478 (if message
1479 (message message))))
1481 (defcommand buffer-disable-undo ((&optional buffer))
1482 "Make BUFFER stop keeping undo information.
1483 No argument or nil as argument means do this for the current buffer."
1484 (with-current-buffer (if buffer (get-buffer buffer) (current-buffer))
1485 (setf (buffer-undo-list (current-buffer)) t)))
1487 (defcommand undo-only ((&optional arg)
1488 ;; XXX what about *
1489 :prefix)
1490 "Undo some previous changes.
1491 Repeat this command to undo more changes.
1492 A numeric argument serves as a repeat count.
1493 Contrary to `undo', this will not redo a previous undo."
1494 ;;(interactive "*p")
1495 (let ((undo-no-redo t)) (undo arg)))
1497 (defvar undo-in-progress nil
1498 "Non-nil while performing an undo.
1499 Some change-hooks test this variable to do something different.")
1501 (defun undo-more (n)
1502 "Undo back N undo-boundaries beyond what was already undone recently.
1503 Call `undo-start' to get ready to undo recent changes,
1504 then call `undo-more' one or more times to undo them."
1505 (or (listp pending-undo-list)
1506 (error (concat "No further undo information"
1507 (and transient-mark-mode *mark-active*
1508 " for region"))))
1509 (let ((undo-in-progress t))
1510 (setq pending-undo-list (primitive-undo n pending-undo-list))
1511 (if (null pending-undo-list)
1512 (setq pending-undo-list t))))
1514 ;; Deep copy of a list
1515 (defun undo-copy-list (list)
1516 "Make a copy of undo list LIST."
1517 (labels ((helper (elt)
1518 (if (typep elt 'structure-object)
1519 (copy-structure elt)
1520 elt)))
1521 (mapcar #'helper list)))
1523 (defun undo-start (&optional beg end)
1524 "Set `pending-undo-list' to the front of the undo list.
1525 The next call to `undo-more' will undo the most recently made change.
1526 If BEG and END are specified, then only undo elements
1527 that apply to text between BEG and END are used; other undo elements
1528 are ignored. If BEG and END are nil, all undo elements are used."
1529 (if (eq (buffer-undo-list (current-buffer)) t)
1530 (error "No undo information in this buffer"))
1531 (setq pending-undo-list
1532 (if (and beg end (not (= beg end)))
1533 (undo-make-selective-list (min beg end) (max beg end))
1534 (buffer-undo-list (current-buffer)))))
1536 (defvar undo-adjusted-markers)
1538 (defun undo-make-selective-list (start end)
1539 "Return a list of undo elements for the region START to END.
1540 The elements come from `buffer-undo-list', but we keep only
1541 the elements inside this region, and discard those outside this region.
1542 If we find an element that crosses an edge of this region,
1543 we stop and ignore all further elements."
1544 (let ((undo-list-copy (undo-copy-list (buffer-undo-list (current-buffer))))
1545 (undo-list (list nil))
1546 undo-adjusted-markers
1547 some-rejected
1548 undo-elt temp-undo-list delta)
1549 (while undo-list-copy
1550 (setq undo-elt (car undo-list-copy))
1551 (let ((keep-this
1552 (cond ((typep undo-elt 'undo-entry-modified) ;;(and (consp undo-elt) (eq (car undo-elt) t))
1553 ;; This is a "was unmodified" element.
1554 ;; Keep it if we have kept everything thus far.
1555 (not some-rejected))
1557 (undo-elt-in-region undo-elt start end)))))
1558 (if keep-this
1559 (progn
1560 (setq end (+ end (cdr (undo-delta undo-elt))))
1561 ;; Don't put two nils together in the list
1562 (if (not (and (eq (car undo-list) nil)
1563 (eq undo-elt nil)))
1564 (setq undo-list (cons undo-elt undo-list))))
1565 (if (undo-elt-crosses-region undo-elt start end)
1566 (setq undo-list-copy nil)
1567 (progn
1568 (setq some-rejected t)
1569 (setq temp-undo-list (cdr undo-list-copy))
1570 (setq delta (undo-delta undo-elt))
1572 (when (/= (cdr delta) 0)
1573 (let ((position (car delta))
1574 (offset (cdr delta)))
1576 ;; Loop down the earlier events adjusting their buffer
1577 ;; positions to reflect the fact that a change to the buffer
1578 ;; isn't being undone. We only need to process those element
1579 ;; types which undo-elt-in-region will return as being in
1580 ;; the region since only those types can ever get into the
1581 ;; output
1583 (dolist (undo-elt temp-undo-list)
1584 (cond ((integerp undo-elt)
1585 (if (>= undo-elt position)
1586 (setf (car temp-undo-list) (- undo-elt offset))))
1587 ;;((atom undo-elt) nil)
1588 ((typep undo-elt 'undo-entry-delete) ;(stringp (car undo-elt))
1589 ;; (TEXT . POSITION)
1590 (let ((text-pos (abs (undo-entry-delete-position undo-elt)))
1591 (point-at-end (< (undo-entry-delete-position undo-elt) 0 )))
1592 (if (>= text-pos position)
1593 (setf (undo-entry-delete-position undo-elt) (* (if point-at-end -1 1)
1594 (- text-pos offset))))))
1595 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1596 ;; (BEGIN . END)
1597 (when (>= (undo-entry-insertion-beg undo-elt) position)
1598 (setf (undo-entry-insertion-beg undo-elt) (- (undo-entry-insertion-beg undo-elt) offset))
1599 (setf (undo-entry-insertion-end undo-elt) (- (undo-entry-insertion-end undo-elt) offset))))
1600 ((typep undo-elt 'undo-entry-property) ;(null (car undo-elt))
1601 ;; (nil PROPERTY VALUE BEG . END)
1602 (when (>= (undo-entry-property-beg undo-elt) position)
1603 (setf (undo-entry-property-beg undo-elt) (- (undo-entry-property-beg undo-elt) offset))
1604 (setf (undo-entry-property-end undo-elt) (- (undo-entry-property-end undo-elt) offset))))))))))))
1605 (setq undo-list-copy (cdr undo-list-copy)))
1606 (nreverse undo-list)))
1608 (defun undo-elt-in-region (undo-elt start end)
1609 "Determine whether UNDO-ELT falls inside the region START ... END.
1610 If it crosses the edge, we return nil."
1611 (cond ((integerp undo-elt)
1612 (and (>= undo-elt start)
1613 (<= undo-elt end)))
1614 ((eq undo-elt nil)
1616 ;; ((atom undo-elt)
1617 ;; nil)
1618 ((typep undo-elt 'undo-entry-delete) ; (stringp (car undo-elt))
1619 ;; (TEXT . POSITION)
1620 (and (>= (abs (undo-entry-delete-position undo-elt)) start)
1621 (< (abs (undo-entry-delete-position undo-elt)) end)))
1622 ((typep undo-elt 'undo-entry-marker) ;(and (consp undo-elt) (markerp (car undo-elt)))
1623 ;; This is a marker-adjustment element (MARKER . ADJUSTMENT).
1624 ;; See if MARKER is inside the region.
1625 (let ((alist-elt (assq (undo-entry-marker-marker undo-elt) undo-adjusted-markers)))
1626 (unless alist-elt
1627 (setq alist-elt (make-undo-entry-marker :marker (undo-entry-marker-marker undo-elt)
1628 :distance (marker-position (undo-entry-marker-marker undo-elt))))
1629 (setq undo-adjusted-markers
1630 (cons alist-elt undo-adjusted-markers)))
1631 (and (undo-entry-marker-distance alist-elt) ;(cdr alist-elt)
1632 (>= (undo-entry-marker-distance alist-elt) start)
1633 (<= (undo-entry-marker-distance alist-elt) end))))
1634 ((typep undo-elt 'undo-entry-property) ;(null (car undo-elt))
1635 ;; (nil PROPERTY VALUE BEG . END)
1636 (and (>= (undo-entry-property-beg undo-elt) start)
1637 (<= (undo-entry-property-end undo-elt) end)))
1638 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1639 ;; (BEGIN . END)
1640 (and (>= (undo-entry-insertion-beg undo-elt) start)
1641 (<= (undo-entry-insertion-end undo-elt) end)))))
1643 (defun undo-elt-crosses-region (undo-elt start end)
1644 "Test whether UNDO-ELT crosses one edge of that region START ... END.
1645 This assumes we have already decided that UNDO-ELT
1646 is not *inside* the region START...END."
1647 (cond ;; (atom undo-elt) nil)
1648 ((typep undo-elt 'undo-entry-property) ;(null (car undo-elt))
1649 ;; (nil PROPERTY VALUE BEG . END)
1650 ;;(let ((tail (nthcdr 3 undo-elt)))
1651 (not (or (< (undo-entry-property-beg undo-elt) end)
1652 (> (undo-entry-property-end undo-elt) start))))
1653 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1654 ;; (BEGIN . END)
1655 (not (or (< (undo-entry-insertion-beg undo-elt) end)
1656 (> (undo-entry-insertion-end undo-elt) start))))))
1658 ;; Return the first affected buffer position and the delta for an undo element
1659 ;; delta is defined as the change in subsequent buffer positions if we *did*
1660 ;; the undo.
1661 (defun undo-delta (undo-elt)
1662 (cond ((typep undo-elt 'undo-entry-delete) ;(stringp (car undo-elt))
1663 ;; (TEXT . POSITION)
1664 (cons (abs (undo-entry-delete-position undo-elt)) (length (undo-entry-delete-text undo-elt))))
1665 ((typep undo-elt 'undo-entry-insertion) ;(integerp (car undo-elt))
1666 ;; (BEGIN . END)
1667 (cons (undo-entry-insertion-beg undo-elt) (- (undo-entry-insertion-beg undo-elt) (undo-entry-insertion-end undo-elt))))
1669 '(0 . 0))))
1671 (defcustom undo-ask-before-discard nil
1672 "If non-nil ask about discarding undo info for the current command.
1673 Normally, Emacs discards the undo info for the current command if
1674 it exceeds `undo-outer-limit'. But if you set this option
1675 non-nil, it asks in the echo area whether to discard the info.
1676 If you answer no, there a slight risk that Emacs might crash, so
1677 only do it if you really want to undo the command.
1679 This option is mainly intended for debugging. You have to be
1680 careful if you use it for other purposes. Garbage collection is
1681 inhibited while the question is asked, meaning that Emacs might
1682 leak memory. So you should make sure that you do not wait
1683 excessively long before answering the question."
1684 :type 'boolean
1685 :group 'undo
1686 :version "22.1")
1688 (define-buffer-local *undo-extra-outer-limit* 'undo-outer-limit-truncate ;;nil
1689 "If non-nil, an extra level of size that's ok in an undo item.
1690 We don't ask the user about truncating the undo list until the
1691 current item gets bigger than this amount.
1693 This variable only matters if `undo-ask-before-discard' is non-nil.")
1695 ;;(make-variable-buffer-local 'undo-extra-outer-limit)
1697 ;; When the first undo batch in an undo list is longer than
1698 ;; undo-outer-limit, this function gets called to warn the user that
1699 ;; the undo info for the current command was discarded. Garbage
1700 ;; collection is inhibited around the call, so it had better not do a
1701 ;; lot of consing.
1702 ;;(setq undo-outer-limit-function 'undo-outer-limit-truncate)
1703 (defun undo-outer-limit-truncate (size)
1704 (if undo-ask-before-discard
1705 (when (or (null *undo-extra-outer-limit*)
1706 (> size *undo-extra-outer-limit*))
1707 ;; Don't ask the question again unless it gets even bigger.
1708 ;; This applies, in particular, if the user quits from the question.
1709 ;; Such a quit quits out of GC, but something else will call GC
1710 ;; again momentarily. It will call this function again,
1711 ;; but we don't want to ask the question again.
1712 (setf *undo-extra-outer-limit* (+ size 50000))
1713 (if (let (*use-dialog-box* *track-mouse* *executing-kbd-macro* )
1714 (yes-or-no-p (format nil "Buffer `~a' undo info is ~d bytes long; discard it? "
1715 (buffer-name (current-buffer)) size)))
1716 (progn (setf (buffer-undo-list (current-buffer)) nil)
1717 (setf *undo-extra-outer-limit* nil)
1719 nil))
1720 (progn
1721 (display-warning '(undo discard-info)
1722 (concat
1723 (format nil "Buffer `~a' undo info was ~d bytes long.~%"
1724 (buffer-name (current-buffer)) size)
1725 "The undo info was discarded because it exceeded \
1726 `undo-outer-limit'.
1728 This is normal if you executed a command that made a huge change
1729 to the buffer. In that case, to prevent similar problems in the
1730 future, set `undo-outer-limit' to a value that is large enough to
1731 cover the maximum size of normal changes you expect a single
1732 command to make, but not so large that it might exceed the
1733 maximum memory allotted to Emacs.
1735 If you did not execute any such command, the situation is
1736 probably due to a bug and you should report it.
1738 You can disable the popping up of this buffer by adding the entry
1739 \(undo discard-info) to the user option `warning-suppress-types'.
1741 :warning)
1742 (setf (buffer-undo-list (current-buffer)) nil)
1743 t)))
1746 (defcommand kill-word ((arg)
1747 :prefix)
1748 "Kill characters forward until encountering the end of a word.
1749 With argument, do this that many times."
1750 (kill-region (point) (progn (forward-word arg) (point))))
1752 (defcommand backward-kill-word ((arg)
1753 :prefix)
1754 "Kill characters backward until encountering the end of a word.
1755 With argument, do this that many times."
1756 (kill-word (- arg)))
1758 (defcommand backward-word ((n) :prefix)
1759 "Move point forward ARG words (backward if ARG is negative).
1760 Normally returns t.
1761 If an edge of the buffer or a field boundary is reached, point is left there
1762 and the function returns nil. Field boundaries are not noticed if
1763 `inhibit-field-text-motion' is non-nil."
1764 (forward-word (- n)))
1766 (defcommand forward-word ((n) :prefix)
1767 "Move point forward ARG words (backward if ARG is negative).
1768 Normally returns t.
1769 If an edge of the buffer or a field boundary is reached, point is left there
1770 and the function returns nil. Field boundaries are not noticed if
1771 `inhibit-field-text-motion' is non-nil."
1772 (labels ((isaword (c)
1773 (find c +word-constituents+ :test #'char=)))
1774 (let ((buffer (current-buffer)))
1775 (cond ((> n 0)
1776 (gap-move-to buffer (buffer-point-aref buffer))
1777 ;; do it n times
1778 (loop for i from 0 below n
1779 while (let (p1 p2)
1780 ;; search forward for a word constituent
1781 (setf p1 (position-if #'isaword (buffer-data buffer)
1782 :start (buffer-point-aref buffer)))
1783 ;; search forward for a non word constituent
1784 (when p1
1785 (setf p2 (position-if (complement #'isaword) (buffer-data buffer) :start p1)))
1786 (if p2
1787 (goto-char (buffer-aref-to-char buffer p2))
1788 (goto-char (point-max)))
1789 p2)))
1790 ((< n 0)
1791 (setf n (- n))
1792 (gap-move-to buffer (buffer-point-aref buffer))
1793 ;; do it n times
1794 (loop for i from 0 below n
1795 for start = (buffer-gap-start buffer) then (buffer-point-aref buffer)
1796 while (let (p1 p2)
1797 ;; search backward for a word constituent
1798 (setf p1 (position-if #'isaword (buffer-data buffer)
1799 :from-end t
1800 :end start))
1801 ;; search backward for a non word constituent
1802 (when p1
1803 (setf p2 (position-if (complement #'isaword) (buffer-data buffer) :from-end t :end p1)))
1804 (if p2
1805 (goto-char (1+ (buffer-aref-to-char buffer p2)))
1806 (goto-char (point-min)))
1807 p2)))))))
1809 (defvar line-number-mode nil
1812 (defvar column-number-mode nil
1815 (defun line-number-mode (&optional arg)
1817 (warn "Unimplemented line-number-mode"))
1819 (defun column-number-mode (&optional arg)
1821 (warn "Unimplemented column-number-mode"))
1824 (provide :lice-0.1/simple)