3 (defvar *kill-ring
* nil
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 (define-condition kill-ring-empty
(lice-condition)
13 () (:documentation
"Raised when a yank is attempted but the kill ring is empty"))
15 ;; (when (or (and (< n 0)
16 ;; (< (point (current-buffer)) 0))
17 ;; (> (point (current-buffer))
19 ;; (decf (marker-position (buffer-point (current-buffer))) n))
21 (defcommand forward-char
((&optional
(n 1))
23 "Move the point forward N characters in the current buffer."
24 (incf (marker-position (buffer-point (current-buffer))) n
)
25 (cond ((< (point) (begv))
27 (signal 'beginning-of-buffer
))
30 (signal 'end-of-buffer
))))
32 (defcommand backward-char
((&optional
(n 1))
36 (defun buffer-beginning-of-line ()
37 "Return the point in the buffer that is the beginning of the line that P is on."
38 (if (or (not (char-before))
39 (char= (char-before) #\Newline
))
41 (let ((bol (buffer-scan-newline (current-buffer) (point) 0 0)))
42 (if (and (char= (char-after bol
) #\Newline
)
43 (< bol
(1- (buffer-size (current-buffer)))))
47 (defun buffer-end-of-line ()
48 "Return the point in the buffer that is the end of the line that P is on."
49 (if (or (not (char-after))
50 (char= (char-after) #\Newline
))
52 (let ((eol (buffer-scan-newline (current-buffer) (point) (1- (buffer-size (current-buffer))) 1)))
53 ;; XXX: a bit of a kludge. if the eol char isn't a newline then it
54 ;; has to be the end of the buffer, so advance the point by one,
55 ;; which is the actual end of the line.
56 (if (char= (char-after eol
) #\Newline
)
60 (defun forward-line (n)
61 "Move n lines forward (backward if n is negative).
62 Precisely, if point is on line I, move to the start of line I + n.
63 If there isn't room, go as far as possible (no error).
64 Returns the count of lines left to move. If moving forward,
65 that is n - number of lines moved; if backward, n + number moved.
66 With positive n, a non-empty line at the end counts as one line
67 successfully moved (for the return value)."
70 (signal 'end-of-buffer
))
73 (signal 'beginning-of-buffer
)))
75 (multiple-value-bind (p lines
) (buffer-scan-newline (current-buffer)
76 (point (current-buffer))
77 (1- (buffer-size (current-buffer)))
79 ;; Increment p by one so the point is at the beginning of the
81 (when (or (char= (char-after p
) #\Newline
)
82 (= p
(1- (buffer-size (current-buffer)))))
86 (signal 'end-of-buffer
))
91 (multiple-value-bind (p lines
)
92 (buffer-scan-newline (current-buffer)
94 ;; A little mess to figure out how
95 ;; many newlines to search for to
96 ;; give the proper output.
99 (if (and (char-after (point))
100 (char= (char-after (point)) #\Newline
))
103 (when (char= (char-after p
) #\Newline
)
108 (signal 'beginning-of-buffer
))
111 (defun current-column ()
112 "Return the current column that the current buffer's point is on."
113 (let ((bol (buffer-beginning-of-line)))
116 (defcommand self-insert-command
((arg)
118 "Insert the character you type.
119 Whichever character you type to run this command is inserted."
120 (dformat +debug-v
+ "currentb: ~a ~a~%" (current-buffer) *current-buffer
*)
122 (insert-move-point (current-buffer) (make-string arg
:initial-element
(key-char *current-event
*)))
124 (insert-move-point (current-buffer) (key-char *current-event
*)))))
126 (defcommand newline
((&optional n
)
128 "Insert N new lines."
129 (insert-move-point (current-buffer) (make-string (or n
1) :initial-element
#\Newline
)))
131 (defcommand open-line
((n) :prefix
)
132 "Insert a newline and leave point before it.
133 **If there is a fill prefix and/or a left-margin, insert them on the new line
134 **if the line would have been blank.
135 With arg N, insert N newlines."
137 (dotimes (i n
) (newline 1))
140 (defcommand next-line
((&optional
(arg 1))
142 "Move cursor vertically down N lines."
143 (let ((col (current-column)))
145 (if (<= col
(- (buffer-end-of-line) (point)))
146 (goto-char (+ (point) col
))
147 (goto-char (buffer-end-of-line)))))
149 (defcommand previous-line
((&optional
(arg 1))
151 "Move cursor vertically up N lines."
152 (let ((col (current-column)))
153 ;; FIXME: this is all fucked
154 (forward-line (- arg
))
158 (if (<= col
(- (buffer-end-of-line) (point)))
159 (goto-char (+ (point) col
))
160 (goto-char (buffer-end-of-line)))))
162 (defcommand delete-backward-char
()
163 "Delete the previous N characters."
164 (buffer-delete (current-buffer) (point (current-buffer)) -
1))
166 (defcommand delete-char
()
167 "Delete the following N characters."
168 (buffer-delete (current-buffer) (point (current-buffer)) 1))
170 (defcommand beginning-of-line
()
171 "Move the point to the beginning of the line in the current buffer."
172 (setf (marker-position (buffer-point (current-buffer))) (buffer-beginning-of-line)))
174 (defcommand end-of-line
()
175 "Move the point to the end of the line in the current buffer."
176 (setf (marker-position (buffer-point (current-buffer))) (buffer-end-of-line)))
178 (defcommand erase-buffer
((&optional buffer
))
179 "Erase the contents of the current buffer."
180 (buffer-erase (or buffer
(current-buffer))))
182 (defcommand execute-extended-command
((prefix)
184 "Read a user command from the minibuffer."
185 (let ((cmd (read-command (case prefix
188 (t (format nil
"~a M-x " prefix
))))))
189 (if (lookup-command cmd
)
191 (setf *prefix-arg
* prefix
)
192 (dispatch-command cmd
))
193 (message "No Match"))))
195 (defcommand switch-to-buffer
((buffer &optional norecord
)
196 (:buffer
"Switch To Buffer: " (buffer-name (other-buffer (current-buffer)))))
197 "Select buffer buffer in the current window.
198 If buffer does not identify an existing buffer,
199 then this function creates a buffer with that name.
201 When called from Lisp, buffer may be a buffer, a string (a buffer name),
202 or nil. If buffer is nil, then this function chooses a buffer
203 using `other-buffer'.
204 Optional second arg norecord non-nil means
205 do not put this buffer at the front of the list of recently selected ones.
206 This function returns the buffer it switched to.
208 WARNING: This is NOT the way to work on another buffer temporarily
209 within a Lisp program! Use `set-buffer' instead. That avoids messing with
210 the window-buffer correspondences."
212 (setf buffer
(other-buffer (current-buffer))))
213 (let ((w (frame-current-window (selected-frame))))
214 (when (typep w
'minibuffer-window
)
215 (error "its a minibuffer"))
216 (setf buffer
(get-buffer-create buffer
))
219 (record-buffer buffer
))
220 (set-window-buffer w buffer
)))
222 (defcommand save-buffers-kill-emacs
()
223 ;; TODO: save-some-buffers
224 (throw 'lice-quit t
))
226 (defcommand kill-buffer
((buffer)
227 (:buffer
"Kill buffer: " (buffer-name (current-buffer)) t
))
228 "Kill the buffer BUFFER.
229 The argument may be a buffer or may be the name of a buffer.
230 defaults to the current buffer.
232 Value is t if the buffer is actually killed, nil if user says no.
234 The value of `kill-buffer-hook' (which may be local to that buffer),
235 if not void, is a list of functions to be called, with no arguments,
236 before the buffer is actually killed. The buffer to be killed is current
237 when the hook functions are called.
239 Any processes that have this buffer as the `process-buffer' are killed
241 (let* ((target (get-buffer buffer
))
242 (other (other-buffer target
)))
245 ;; all windows carrying the buffer need a new buffer
246 (loop for w in
(frame-window-list (selected-frame))
247 do
(when (eq (window-buffer w
) target
)
248 (set-window-buffer w other
)))
249 (setf *buffer-list
* (delete target
*buffer-list
*)))
250 (error "No such buffer ~a" buffer
))))
252 (defun eval-echo (string)
253 (multiple-value-bind (sexpr pos
) (read-from-string string
)
254 (if (= pos
(length string
))
255 (message "~s" (eval sexpr
))
256 (error "Trailing garbage is ~a" string
))))
258 (defun eval-print (string)
259 (multiple-value-bind (sexpr pos
) (read-from-string string
)
260 (if (= pos
(length string
))
261 (insert (format nil
"~%~s~%" (eval sexpr
)))
262 (error "Trailing garbage is ~a" string
))))
264 (defcommand eval-expression
((s)
268 ;;(error (c) (message "Eval error: ~s" c))))
270 (defcommand exchange-point-and-mark
()
272 (goto-char (marker-position (mark-marker)))
273 (set-marker (mark-marker) p
)))
275 (defcommand set-mark-command
()
276 (set-marker (mark-marker) (point))
277 (message "Mark set"))
279 ;; (defun kill-ring-save (beg end)
280 ;; "Save the region to the kill ring."
282 (defcommand scroll-up
()
283 (let ((win (get-current-window)))
284 (window-scroll-up win
(max 1 (- (window-height win
)
285 *next-screen-context-lines
*)))))
287 (defcommand scroll-down
()
288 (let ((win (get-current-window)))
289 (window-scroll-down win
(max 1 (- (window-height win
)
290 *next-screen-context-lines
*)))))
292 (defcommand end-of-buffer
()
293 "Move point to the end of the buffer; leave mark at previous position.
294 With arg N, put point N/10 of the way from the end.
296 If the buffer is narrowed, this command uses the beginning and size
297 of the accessible part of the buffer."
299 (goto-char (point-max)))
301 (defcommand beginning-of-buffer
()
302 "Move point to the beginning of the buffer; leave mark at previous position.
303 With arg N, put point N/10 of the way from the beginning.
305 If the buffer is narrowed, this command uses the beginning and size
306 of the accessible part of the buffer."
308 (goto-char (point-min)))
310 (defcommand split-window-vertically
()
311 (split-window (get-current-window)))
313 (defcommand split-window-horizontally
()
314 (split-window (get-current-window) nil t
))
316 (defcommand other-window
()
317 (let ((w (next-window (get-current-window) t
)))
320 (message "No other window."))))
322 (defcommand switch-to-buffer-other-window
((buffer)
323 (:buffer
"Switch to buffer in other window: " (buffer-name (other-buffer (current-buffer)))))
324 (let* ((cw (get-current-window))
325 (w (or (next-window cw
)
328 (switch-to-buffer buffer
)))
330 (defcommand keyboard-quit
()
335 (defun kill-new (string &optional replace
)
336 "Make STRING the latest kill in the kill ring.
337 Set the kill-ring-yank pointer to point to it.
338 Optional second argument REPLACE non-nil means that STRING will replace
339 the front of the kill ring, rather than being added to the list."
342 (setf (car *kill-ring
*) string
)
343 (push string
*kill-ring
*))
344 (when (> (length *kill-ring
*) *kill-ring-max
*)
345 (setf (cdr (nthcdr (1- *kill-ring-max
*) *kill-ring
*)) nil
))
346 (setf *kill-ring-yank-pointer
* *kill-ring
*))
348 (defun copy-region-as-kill (start end
&optional
(buffer (current-buffer)))
349 (multiple-value-setq (start end
) (validate-region start end buffer
))
350 (kill-new (buffer-substring start end buffer
)))
352 (defcommand kill-ring-save
()
353 (copy-region-as-kill (mark) (point)))
355 (defcommand kill-region
((beg end
)
358 "Kill between point and mark.
359 The text is deleted but saved in the kill ring.
360 The command C-y can retrieve it from there.
361 (If you want to kill and then yank immediately, use M-w.)"
362 (copy-region-as-kill beg end
)
363 (delete-region beg end
))
366 (defcommand kill-line
()
370 (signal 'end-of-buffer
))
371 (if (char= (buffer-char-after (current-buffer) (point)) #\Newline
)
373 (goto-char (buffer-end-of-line)))
376 (defun current-kill (n &optional do-not-move
)
377 "Rotate the yanking point by N places, and then return that kill.
378 If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
379 yanking point; just return the Nth kill forward."
381 (signal 'kill-ring-empty
))
382 (let ((argth-kill-element
383 (nthcdr (mod (- n
(length *kill-ring-yank-pointer
*))
384 (length *kill-ring
*))
387 (setf *kill-ring-yank-pointer
* argth-kill-element
))
388 (car argth-kill-element
)))
392 (insert (current-kill 0)))
394 (defcommand yank-pop
()
395 (unless (eq *last-command
* 'yank
)
396 (error "Previous command was not a yank: ~a" *last-command
*))
397 (setf *this-command
* 'yank
)
398 (delete-region (mark) (point))
399 (insert (current-kill 1)))
401 ;;; universal argument
403 (defun prefix-numeric-value (prefix)
404 "Return numeric meaning of raw prefix argument RAW.
405 A raw prefix argument is what you get from :raw-prefix.
406 Its numeric meaning is what you would get from :prefix."
413 (integerp (car prefix
)))
420 "Return numeric meaning of *prefix-arg*"
421 (prefix-numeric-value *prefix-arg
*))
423 (defun raw-prefix-arg ()
424 "Return the current prefix arg in raw form."
427 (defvar *overriding-map-is-bound
* nil
)
428 (defvar *saved-overriding-map
* nil
)
429 (defvar *universal-argument-num-events
* nil
)
431 (defvar *universal-argument-map
*
432 (let ((map (make-sparse-keymap)))
433 ;;(define-key map (kbd "t") 'universal-argument-other-key)
434 (define-key map t
'universal-argument-other-key
)
435 ;;(define-key map [switch-frame] nil)
436 (define-key map
(kbd "C-u") 'universal-argument-more
)
437 (define-key map
(kbd "-") 'universal-argument-minus
)
438 (define-key map
(kbd "0") 'digit-argument
)
439 (define-key map
(kbd "1") 'digit-argument
)
440 (define-key map
(kbd "2") 'digit-argument
)
441 (define-key map
(kbd "3") 'digit-argument
)
442 (define-key map
(kbd "4") 'digit-argument
)
443 (define-key map
(kbd "5") 'digit-argument
)
444 (define-key map
(kbd "6") 'digit-argument
)
445 (define-key map
(kbd "7") 'digit-argument
)
446 (define-key map
(kbd "8") 'digit-argument
)
447 (define-key map
(kbd "9") 'digit-argument
)
448 ;; (define-key map [kp-0] 'digit-argument)
449 ;; (define-key map [kp-1] 'digit-argument)
450 ;; (define-key map [kp-2] 'digit-argument)
451 ;; (define-key map [kp-3] 'digit-argument)
452 ;; (define-key map [kp-4] 'digit-argument)
453 ;; (define-key map [kp-5] 'digit-argument)
454 ;; (define-key map [kp-6] 'digit-argument)
455 ;; (define-key map [kp-7] 'digit-argument)
456 ;; (define-key map [kp-8] 'digit-argument)
457 ;; (define-key map [kp-9] 'digit-argument)
458 ;; (define-key map [kp-subtract] 'universal-argument-minus)
460 "Keymap used while processing \\[universal-argument].")
462 (defun ensure-overriding-map-is-bound ()
463 "Check `*overriding-terminal-local-map*' is `*universal-argument-map*'."
464 (unless *overriding-map-is-bound
*
465 (setf *saved-overriding-map
* *overriding-terminal-local-map
*
466 *overriding-terminal-local-map
* *universal-argument-map
*
467 *overriding-map-is-bound
* t
)))
469 (defun restore-overriding-map ()
470 "Restore `*overriding-terminal-local-map*' to its saved value."
471 (setf *overriding-terminal-local-map
* *saved-overriding-map
*
472 *overriding-map-is-bound
* nil
))
474 (defcommand universal-argument
()
475 (setf *prefix-arg
* (list 4)
476 *universal-argument-num-events
* (length (this-command-keys)))
477 (ensure-overriding-map-is-bound))
479 (defcommand universal-argument-more
((arg)
482 (setf *prefix-arg
* (list (* 4 (car arg
))))
484 (setf *prefix-arg
* (list -
4))
486 (setf *prefix-arg
* arg
)
487 (restore-overriding-map))))
488 (setf *universal-argument-num-events
* (length (this-command-keys))))
490 (defcommand negative-argument
((arg)
492 "Begin a negative numeric argument for the next command.
493 \\[universal-argument] following digits or minus sign ends the argument."
494 (cond ((integerp arg
)
495 (setf *prefix-arg
* (- arg
)))
497 (setf *prefix-arg
* nil
))
499 (setf *prefix-arg
* '-
)))
500 (setf *universal-argument-num-events
* (length (this-command-keys)))
501 (ensure-overriding-map-is-bound))
503 (defcommand digit-argument
((arg)
505 "Part of the numeric argument for the next command.
506 \\[universal-argument] following digits or minus sign ends the argument."
507 (let* ((char (last-command-char))
508 (digit (- (logand (char-code char
) #o177
) (char-code #\
0))))
509 (cond ((integerp arg
)
510 (setf *prefix-arg
* (+ (* arg
10)
511 (if (< arg
0) (- digit
) digit
))))
513 ;; Treat -0 as just -, so that -01 will work.
514 (setf *prefix-arg
* (if (zerop digit
) '-
(- digit
))))
516 (setf *prefix-arg
* digit
))))
517 (setf *universal-argument-num-events
* (length (this-command-keys)))
518 (ensure-overriding-map-is-bound))
520 ;; For backward compatibility, minus with no modifiers is an ordinary
521 ;; command if digits have already been entered.
522 (defcommand universal-argument-minus
((arg)
525 (universal-argument-other-key arg
)
526 (negative-argument arg
)))
528 ;; Anything else terminates the argument and is left in the queue to be
529 ;; executed as a command.
530 (defcommand universal-argument-other-key
((arg)
532 (setf *prefix-arg
* arg
)
533 (let* ((keylist (this-command-keys)))
534 (setf *unread-command-events
* keylist
))
535 ;; (append (nthcdr *universal-argument-num-events* keylist)
536 ;; *unread-command-events*)))
537 ;;FIXME: (reset-this-command-lengths)
538 (restore-overriding-map))
541 ;; (defcommand append-to-buffer ((buffer :buffer "Append to buffer: " (buffer-name (other-buffer (current-buffer))))
542 ;; (start :region-beginning)
543 ;; (end :region-end))
544 ;; "Append to specified buffer the text of the region.
545 ;; It is inserted into that buffer before its point.
547 ;; When calling from a program, give three arguments:
548 ;; buffer (or buffer name), start and end.
549 ;; start and end specify the portion of the current buffer to be copied."
550 ;; (let ((oldbuf (current-buffer)))
552 ;; (let* ((append-to (get-buffer-create buffer))
553 ;; (windows (get-buffer-window-list append-to t t))
555 ;; (set-buffer append-to)
556 ;; (setf point (point))
557 ;; (barf-if-buffer-read-only)
558 ;; (insert-buffer-substring oldbuf start end)
559 ;; (dolist (window windows)
560 ;; (when (= (window-point window) point)
561 ;; (set-window-point window (point))))))))
563 (defcommand transpose-chars
((arg)
565 "Interchange characters around point, moving forward one character.
566 With prefix arg ARG, effect is to take character before point
567 and drag it forward past ARG other characters (backward if ARG negative).
568 If no argument and at end of line, the previous two chars are exchanged."
569 (and (null arg
) (eolp) (forward-char -
1))
570 (transpose-subr 'forward-char
(prefix-numeric-value arg
)))
572 (defcommand transpose-words
((arg)
574 "Interchange words around point, leaving point at end of them.
575 With prefix arg ARG, effect is to take word before or around point
576 and drag it forward past ARG other words (backward if ARG negative).
577 If ARG is zero, the words around or after point and around or after mark
579 ;; FIXME: `foo a!nd bar' should transpose into `bar and foo'.
580 (transpose-subr 'forward-word arg
))
582 ;; (defun transpose-sexps ((arg)
584 ;; "Like \\[transpose-words] but applies to sexps.
585 ;; Does not work on a sexp that point is in the middle of
586 ;; if it is a list or string."
589 ;; ;; Here we should try to simulate the behavior of
590 ;; ;; (cons (progn (forward-sexp x) (point))
591 ;; ;; (progn (forward-sexp (- x)) (point)))
592 ;; ;; Except that we don't want to rely on the second forward-sexp
593 ;; ;; putting us back to where we want to be, since forward-sexp-function
594 ;; ;; might do funny things like infix-precedence.
596 ;; ;;(looking-at "\\sw\\|\\s_")
597 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
598 ;; (or (alpha-char-p (char-after (point)))
599 ;; (find (char-after (point)) "*/+-%$!@&"))
601 ;; (save-excursion (forward-char -1)
602 ;; ;; (looking-at "\\sw\\|\\s_")
603 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
604 ;; (or (alpha-char-p (char-after (point)))
605 ;; (find (char-after (point)) "*/+-%$!@&"))
607 ;; ;; Jumping over a symbol. We might be inside it, mind you.
608 ;; (progn (funcall (if (> arg 0)
609 ;; 'skip-syntax-backward 'skip-syntax-forward)
611 ;; (cons (save-excursion (forward-sexp arg) (point)) (point)))
612 ;; ;; Otherwise, we're between sexps. Take a step back before jumping
613 ;; ;; to make sure we'll obey the same precedence no matter which direction
615 ;; (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) " .")
616 ;; (cons (save-excursion (forward-sexp arg) (point))
617 ;; (progn (while (or (forward-comment (if (> arg 0) 1 -1))
618 ;; (not (zerop (funcall (if (> arg 0)
619 ;; 'skip-syntax-forward
620 ;; 'skip-syntax-backward)
625 (defcommand transpose-lines
((arg)
627 "Exchange current line and previous line, leaving point after both.
628 With argument ARG, takes previous line and moves it past ARG lines.
629 With argument 0, interchanges line point is in with line mark is in."
630 (transpose-subr (function
634 ;; Move forward over ARG lines,
635 ;; but create newlines if necessary.
636 (setq arg
(forward-line arg
))
637 (if (char/= (preceding-char) #\Newline
)
641 (forward-line arg
))))
644 (defun transpose-subr (mover arg
&optional special
)
645 (let ((aux (if special mover
647 (cons (progn (funcall mover x
) (point))
648 (progn (funcall mover
(- x
)) (point))))))
653 (setq pos1
(funcall aux
1))
655 (setq pos2
(funcall aux
1))
656 (transpose-subr-1 pos1 pos2
))
657 (exchange-point-and-mark))
659 (setq pos1
(funcall aux -
1))
660 (setq pos2
(funcall aux arg
))
661 (transpose-subr-1 pos1 pos2
)
662 (goto-char (car pos2
)))
664 (setq pos1
(funcall aux -
1))
665 (goto-char (car pos1
))
666 (setq pos2
(funcall aux arg
))
667 (transpose-subr-1 pos1 pos2
)))))
669 (defun transpose-subr-1 (pos1 pos2
)
670 (when (> (car pos1
) (cdr pos1
)) (setq pos1
(cons (cdr pos1
) (car pos1
))))
671 (when (> (car pos2
) (cdr pos2
)) (setq pos2
(cons (cdr pos2
) (car pos2
))))
672 (when (> (car pos1
) (car pos2
))
674 (setq pos1 pos2 pos2 swap
)))
675 (if (> (cdr pos1
) (car pos2
)) (error "Don't have two things to transpose"))
676 ;; (atomic-change-group
678 ;; FIXME: We first delete the two pieces of text, so markers that
679 ;; used to point to after the text end up pointing to before it :-(
680 (setq word2
(delete-and-extract-region (car pos2
) (cdr pos2
)))
681 (goto-char (car pos2
))
682 (insert (delete-and-extract-region (car pos1
) (cdr pos1
)))
683 (goto-char (car pos1
))
686 (provide :lice-0.1
/simple
)