[lice @ simulate interrupt key when waiting for input]
[lice.git] / simple.lisp
blobf5d4f8d463b8e30875d9ae1bcca70dbe7d8c28cf
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))
42 (defcommand forward-char ((&optional (n 1))
43 :prefix)
44 "Move the point forward N characters in the current buffer."
45 (incf (marker-position (buffer-point (current-buffer))) n)
46 (cond ((< (point) (begv))
47 (goto-char (begv))
48 (signal 'beginning-of-buffer))
49 ((> (point) (zv))
50 (goto-char (zv))
51 (signal 'end-of-buffer))))
53 (defcommand backward-char ((&optional (n 1))
54 :prefix)
55 (forward-char (- n)))
57 (defun buffer-beginning-of-line ()
58 "Return the point in the buffer that is the beginning of the line that P is on."
59 (if (or (not (char-before))
60 (char= (char-before) #\Newline))
61 (point)
62 (let ((bol (buffer-scan-newline (current-buffer) (point) 0 0)))
63 (if (and (char= (char-after bol) #\Newline)
64 (< bol (1- (buffer-size (current-buffer)))))
65 (1+ bol)
66 bol))))
68 (defun buffer-end-of-line ()
69 "Return the point in the buffer that is the end of the line that P is on."
70 (if (or (not (char-after))
71 (char= (char-after) #\Newline))
72 (point)
73 (let ((eol (buffer-scan-newline (current-buffer) (point) (1- (buffer-size (current-buffer))) 1)))
74 ;; XXX: a bit of a kludge. if the eol char isn't a newline then it
75 ;; has to be the end of the buffer, so advance the point by one,
76 ;; which is the actual end of the line.
77 (if (char= (char-after eol) #\Newline)
78 eol
79 (1+ eol)))))
81 (defun forward-line (n)
82 "Move n lines forward (backward if n is negative).
83 Precisely, if point is on line I, move to the start of line I + n.
84 If there isn't room, go as far as possible (no error).
85 Returns the count of lines left to move. If moving forward,
86 that is n - number of lines moved; if backward, n + number moved.
87 With positive n, a non-empty line at the end counts as one line
88 successfully moved (for the return value)."
89 (cond ((and (> n 0)
90 (= (point) (zv)))
91 (signal 'end-of-buffer))
92 ((and (< n 0)
93 (= (point) (begv)))
94 (signal 'beginning-of-buffer)))
95 (if (> n 0)
96 (multiple-value-bind (p lines) (buffer-scan-newline (current-buffer)
97 (point (current-buffer))
98 (1- (buffer-size (current-buffer)))
100 ;; Increment p by one so the point is at the beginning of the
101 ;; line.
102 (when (or (char= (char-after p) #\Newline)
103 (= p (1- (buffer-size (current-buffer)))))
104 (incf p))
105 (goto-char p)
106 (when (zerop lines)
107 (signal 'end-of-buffer))
108 (- n lines))
109 (if (and (= n 0)
110 (not (char-before)))
112 (multiple-value-bind (p lines)
113 (buffer-scan-newline (current-buffer)
114 (point) 0
115 ;; A little mess to figure out how
116 ;; many newlines to search for to
117 ;; give the proper output.
118 (if (zerop n)
120 (if (and (char-after (point))
121 (char= (char-after (point)) #\Newline))
122 (- n 2)
123 (1- n))))
124 (when (char= (char-after p) #\Newline)
125 (incf p))
126 (goto-char p)
127 (when (and (< n 0)
128 (zerop lines))
129 (signal 'beginning-of-buffer))
130 (+ n lines)))))
132 (defcommand self-insert-command ((arg)
133 :prefix)
134 "Insert the character you type.
135 Whichever character you type to run this command is inserted."
136 (dformat +debug-v+ "currentb: ~a ~a~%" (current-buffer) *current-buffer*)
137 (if (>= arg 2)
138 (insert-move-point (current-buffer) (make-string arg :initial-element (key-char *current-event*)))
139 (when (> arg 0)
140 (insert-move-point (current-buffer) (key-char *current-event*)))))
142 (defcommand newline ((&optional n)
143 :prefix)
144 "Insert N new lines."
145 (insert-move-point (current-buffer) (make-string (or n 1) :initial-element #\Newline)))
147 (defcommand open-line ((n) :prefix)
148 "Insert a newline and leave point before it.
149 **If there is a fill prefix and/or a left-margin, insert them on the new line
150 **if the line would have been blank.
151 With arg N, insert N newlines."
152 (let ((loc (point)))
153 (dotimes (i n) (newline 1))
154 (goto-char loc)))
156 (defcommand next-line ((&optional (arg 1))
157 :prefix)
158 "Move cursor vertically down N lines."
159 (let ((col (current-column)))
160 (forward-line arg)
161 (if (<= col (- (buffer-end-of-line) (point)))
162 (goto-char (+ (point) col))
163 (goto-char (buffer-end-of-line)))))
165 (defcommand previous-line ((&optional (arg 1))
166 :prefix)
167 "Move cursor vertically up N lines."
168 (let ((col (current-column)))
169 ;; FIXME: this is all fucked
170 (forward-line (- arg))
171 ;;(forward-line 0)
172 ;;(backward-char 1)
173 ;;(forward-line 0)
174 (if (<= col (- (buffer-end-of-line) (point)))
175 (goto-char (+ (point) col))
176 (goto-char (buffer-end-of-line)))))
178 (defcommand delete-backward-char ()
179 "Delete the previous N characters."
180 (buffer-delete (current-buffer) (point (current-buffer)) -1))
182 (defcommand delete-char ()
183 "Delete the following N characters."
184 (buffer-delete (current-buffer) (point (current-buffer)) 1))
186 (defun line-move-invisible-p (pos)
187 "Return non-nil if the character after POS is currently invisible."
188 (let ((prop
189 (get-char-property pos 'invisible)))
190 (if (eq (buffer-local :buffer-invisibility-spec) t)
191 prop
192 (or (find prop (buffer-local :buffer-invisibility-spec))
193 (assoc prop (remove-if-not 'listp (buffer-local :buffer-invisibility-spec)))))))
195 (defcustom track-eol nil
196 "*Non-nil means vertical motion starting at end of line keeps to ends of lines.
197 This means moving to the end of each line moved onto.
198 The beginning of a blank line does not count as the end of a line."
199 :type 'boolean
200 :group 'editing-basics)
202 (defcustom *line-move-ignore-invisible* t
203 "*Non-nil means \\[next-line] and \\[previous-line] ignore invisible lines.
204 Outline mode sets this."
205 :type 'boolean
206 :group 'editing-basics)
208 (defcustom-buffer-local :goal-column nil
209 "*Semipermanent goal column for vertical motion, as set by \\[set-goal-column], or nil."
210 :type '(choice integer
211 (const :tag "None" nil))
212 :group 'editing-basics)
214 (defvar *temporary-goal-column* 0
215 "Current goal column for vertical motion.
216 It is the column where point was
217 at the start of current run of vertical motion commands.
218 When the `track-eol' feature is doing its job, the value is 9999.")
220 (defun line-move (arg &optional noerror to-end try-vscroll)
221 "This is like line-move-1 except that it also performs
222 vertical scrolling of tall images if appropriate.
223 That is not really a clean thing to do, since it mixes
224 scrolling with cursor motion. But so far we don't have
225 a cleaner solution to the problem of making C-n do something
226 useful given a tall image."
227 ;; XXX: Fuckit the vertical scrolling for now
228 ;; (if (and auto-window-vscroll try-vscroll
229 ;; ;; But don't vscroll in a keyboard macro.
230 ;; ;; FIXME: kbd macros
231 ;; ;; (not defining-kbd-macro)
232 ;; ;; (not executing-kbd-macro)
233 ;; )
234 ;; (let ((forward (> arg 0))
235 ;; (part (nth 2 (pos-visible-in-window-p (point) nil t))))
236 ;; (if (and (consp part)
237 ;; (> (if forward (cdr part) (car part)) 0))
238 ;; (set-window-vscroll nil
239 ;; (if forward
240 ;; (+ (window-vscroll nil t)
241 ;; (min (cdr part)
242 ;; (* (frame-char-height) arg)))
243 ;; (max 0
244 ;; (- (window-vscroll nil t)
245 ;; (min (car part)
246 ;; (* (frame-char-height) (- arg))))))
247 ;; t)
248 ;; (set-window-vscroll nil 0)
249 ;; (when (line-move-1 arg noerror to-end)
250 ;; (when (not forward)
251 ;; ;; Update display before calling pos-visible-in-window-p,
252 ;; ;; because it depends on window-start being up-to-date.
253 ;; (sit-for 0)
254 ;; ;; If the current line is partly hidden at the bottom,
255 ;; ;; scroll it partially up so as to unhide the bottom.
256 ;; (if (and (setq part (nth 2 (pos-visible-in-window-p
257 ;; (line-beginning-position) nil t)))
258 ;; (> (cdr part) 0))
259 ;; (set-window-vscroll nil (cdr part) t)))
260 ;; t)))
261 (line-move-1 arg noerror to-end))
262 ;; ))
264 (defun line-move-1 (arg &optional noerror to-end)
265 "This is the guts of next-line and previous-line.
266 Arg says how many lines to move.
267 The value is t if we can move the specified number of lines."
268 ;; Don't run any point-motion hooks, and disregard intangibility,
269 ;; for intermediate positions.
270 (let ((*inhibit-point-motion-hooks* t)
271 (opoint (point))
272 (forward (> arg 0)))
273 (unwind-protect
274 (progn
275 (if (not (find *last-command* '(next-line previous-line)))
276 (setq *temporary-goal-column*
277 (if (and track-eol (eolp)
278 ;; Don't count beg of empty line as end of line
279 ;; unless we just did explicit end-of-line.
280 (or (not (bolp)) (eq *last-command* 'move-end-of-line)))
281 9999
282 (current-column))))
284 (if (and (not (integerp (buffer-local :selective-display)))
285 (not *line-move-ignore-invisible*))
286 ;; Use just newline characters.
287 ;; Set ARG to 0 if we move as many lines as requested.
288 (or (if (> arg 0)
289 (progn (if (> arg 1) (forward-line (1- arg)))
290 ;; This way of moving forward ARG lines
291 ;; verifies that we have a newline after the last one.
292 ;; It doesn't get confused by intangible text.
293 (end-of-line)
294 (if (zerop (forward-line 1))
295 (setq arg 0)))
296 (and (zerop (forward-line arg))
297 (bolp)
298 (setq arg 0)))
299 (unless noerror
300 (signal (if (< arg 0)
301 'beginning-of-buffer
302 'end-of-buffer)
303 nil)))
304 ;; Move by arg lines, but ignore invisible ones.
305 (let (done)
306 (while (and (> arg 0) (not done))
307 ;; If the following character is currently invisible,
308 ;; skip all characters with that same `invisible' property value.
309 (while (and (not (eobp)) (line-move-invisible-p (point)))
310 (goto-char (next-char-property-change (point))))
311 ;; Now move a line.
312 (end-of-line)
313 ;; If there's no invisibility here, move over the newline.
314 (cond
315 ((eobp)
316 (if (not noerror)
317 (signal 'end-of-buffer)
318 (setq done t)))
319 ((and (> arg 1) ;; Use vertical-motion for last move
320 (not (integerp (buffer-local :selective-display)))
321 (not (line-move-invisible-p (point))))
322 ;; We avoid vertical-motion when possible
323 ;; because that has to fontify.
324 (forward-line 1))
325 ;; Otherwise move a more sophisticated way.
326 ((zerop (vertical-motion 1))
327 (if (not noerror)
328 (signal 'end-of-buffer)
329 (setq done t))))
330 (unless done
331 (setq arg (1- arg))))
332 ;; The logic of this is the same as the loop above,
333 ;; it just goes in the other direction.
334 (while (and (< arg 0) (not done))
335 (beginning-of-line)
336 (cond
337 ((bobp)
338 (if (not noerror)
339 (signal 'beginning-of-buffer nil)
340 (setq done t)))
341 ((and (< arg -1) ;; Use vertical-motion for last move
342 (not (integerp (buffer-local :selective-display)))
343 (not (line-move-invisible-p (1- (point)))))
344 (forward-line -1))
345 ((zerop (vertical-motion -1))
346 (if (not noerror)
347 (signal 'beginning-of-buffer nil)
348 (setq done t))))
349 (unless done
350 (setq arg (1+ arg))
351 (while (and ;; Don't move over previous invis lines
352 ;; if our target is the middle of this line.
353 (or (zerop (or (buffer-local :goal-column) *temporary-goal-column*))
354 (< arg 0))
355 (not (bobp)) (line-move-invisible-p (1- (point))))
356 (goto-char (previous-char-property-change (point))))))))
357 ;; This is the value the function returns.
358 (= arg 0))
360 (cond ((> arg 0)
361 ;; If we did not move down as far as desired,
362 ;; at least go to end of line.
363 (end-of-line))
364 ((< arg 0)
365 ;; If we did not move up as far as desired,
366 ;; at least go to beginning of line.
367 (beginning-of-line))
369 (line-move-finish (or (buffer-local :goal-column) *temporary-goal-column*)
370 opoint forward))))))
372 (defun line-move-finish (column opoint forward)
373 (let ((repeat t))
374 (while repeat
375 ;; Set REPEAT to t to repeat the whole thing.
376 (setq repeat nil)
378 (let (new
379 (line-beg (save-excursion (beginning-of-line) (point)))
380 (line-end
381 ;; Compute the end of the line
382 ;; ignoring effectively invisible newlines.
383 (save-excursion
384 ;; Like end-of-line but ignores fields.
385 (skip-chars-forward "^\n")
386 (while (and (not (eobp)) (line-move-invisible-p (point)))
387 (goto-char (next-char-property-change (point)))
388 (skip-chars-forward "^\n"))
389 (point))))
391 ;; Move to the desired column.
392 (line-move-to-column column)
393 (setq new (point))
395 ;; Process intangibility within a line.
396 ;; With inhibit-point-motion-hooks bound to nil, a call to
397 ;; goto-char moves point past intangible text.
399 ;; However, inhibit-point-motion-hooks controls both the
400 ;; intangibility and the point-entered/point-left hooks. The
401 ;; following hack avoids calling the point-* hooks
402 ;; unnecessarily. Note that we move *forward* past intangible
403 ;; text when the initial and final points are the same.
404 (goto-char new)
405 (let ((inhibit-point-motion-hooks nil))
406 (goto-char new)
408 ;; If intangibility moves us to a different (later) place
409 ;; in the same line, use that as the destination.
410 (if (<= (point) line-end)
411 (setq new (point))
412 ;; If that position is "too late",
413 ;; try the previous allowable position.
414 ;; See if it is ok.
415 (progn
416 (backward-char)
417 (if (if forward
418 ;; If going forward, don't accept the previous
419 ;; allowable position if it is before the target line.
420 (< line-beg (point))
421 ;; If going backward, don't accept the previous
422 ;; allowable position if it is still after the target line.
423 (<= (point) line-end))
424 (setq new (point))
425 ;; As a last resort, use the end of the line.
426 (setq new line-end)))))
428 ;; Now move to the updated destination, processing fields
429 ;; as well as intangibility.
430 (goto-char opoint)
431 (let ((inhibit-point-motion-hooks nil))
432 (goto-char
433 (constrain-to-field new opoint nil t
434 'inhibit-line-move-field-capture)))
436 ;; If all this moved us to a different line,
437 ;; retry everything within that new line.
438 (when (or (< (point) line-beg) (> (point) line-end))
439 ;; Repeat the intangibility and field processing.
440 (setq repeat t))))))
442 (defun line-move-to-column (col)
443 "Try to find column COL, considering invisibility.
444 This function works only in certain cases,
445 because what we really need is for `move-to-column'
446 and `current-column' to be able to ignore invisible text."
447 (if (zerop col)
448 (beginning-of-line)
449 (let ((opoint (point)))
450 (move-to-column col)
451 ;; move-to-column doesn't respect field boundaries.
452 (goto-char (constrain-to-field (point) opoint))))
454 (when (and *line-move-ignore-invisible*
455 (not (bolp)) (line-move-invisible-p (1- (point))))
456 (let ((normal-location (point))
457 (normal-column (current-column)))
458 ;; If the following character is currently invisible,
459 ;; skip all characters with that same `invisible' property value.
460 (while (and (not (eobp))
461 (line-move-invisible-p (point)))
462 (goto-char (next-char-property-change (point))))
463 ;; Have we advanced to a larger column position?
464 (if (> (current-column) normal-column)
465 ;; We have made some progress towards the desired column.
466 ;; See if we can make any further progress.
467 (line-move-to-column (+ (current-column) (- col normal-column)))
468 ;; Otherwise, go to the place we originally found
469 ;; and move back over invisible text.
470 ;; that will get us to the same place on the screen
471 ;; but with a more reasonable buffer position.
472 (progn
473 (goto-char normal-location)
474 (let ((line-beg (save-excursion (beginning-of-line) (point))))
475 (while (and (not (bolp)) (line-move-invisible-p (1- (point))))
476 (goto-char (previous-char-property-change (point) line-beg)))))))))
478 (defcommand beginning-of-line ((&optional (n 1))
479 :prefix)
480 "Move the point to the beginning of the line in the current buffer."
481 (check-type n number)
482 (set-point (line-beginning-position n)))
484 (defcommand move-beginning-of-line ((arg)
485 :prefix)
486 "Move point to beginning of current line as displayed.
487 \(If there's an image in the line, this disregards newlines
488 which are part of the text that the image rests on.)
490 With argument ARG not nil or 1, move forward ARG - 1 lines first.
491 If point reaches the beginning or end of buffer, it stops there.
492 To ignore intangibility, bind `inhibit-point-motion-hooks' to t."
493 (or arg (setq arg 1))
495 (let ((orig (point))
496 start first-vis first-vis-field-value)
498 ;; Move by lines, if ARG is not 1 (the default).
499 (if (/= arg 1)
500 (line-move (1- arg) t))
502 ;; Move to beginning-of-line, ignoring fields and invisibles.
503 (skip-chars-backward "\\n\\n") ;; FIXME: was "^\n"
504 (while (and (not (bobp)) (line-move-invisible-p (1- (point))))
505 (goto-char (previous-char-property-change (point)))
506 (skip-chars-backward "\\n\\n")) ;; FIXME: was "^\n"
507 (setq start (point))
509 ;; Now find first visible char in the line
510 (while (and (not (eobp)) (line-move-invisible-p (point)))
511 (goto-char (next-char-property-change (point))))
512 (setq first-vis (point))
514 ;; See if fields would stop us from reaching FIRST-VIS.
515 (setq first-vis-field-value
516 (constrain-to-field first-vis orig (/= arg 1) t nil))
518 (goto-char (if (/= first-vis-field-value first-vis)
519 ;; If yes, obey them.
520 first-vis-field-value
521 ;; Otherwise, move to START with attention to fields.
522 ;; (It is possible that fields never matter in this case.)
523 (constrain-to-field (point) orig
524 (/= arg 1) t nil)))))
527 (defcommand end-of-line ((&optional n)
528 :prefix)
529 "Move the point to the end of the line in the current buffer."
530 ;; FIXME: handle prefix
531 (declare (ignore n))
532 (setf (marker-position (buffer-point (current-buffer))) (buffer-end-of-line)))
534 (defcommand erase-buffer ((&optional buffer))
535 "Erase the contents of the current buffer."
536 (buffer-erase (or buffer (current-buffer))))
538 (defcommand execute-extended-command ((prefix)
539 :raw-prefix)
540 "Read a user command from the minibuffer."
541 (let ((cmd (read-command (case (prefix-numeric-value prefix)
542 (1 "M-x ")
543 (4 "C-u M-x ")
544 (t (format nil "~a M-x " prefix))))))
545 (if (lookup-command cmd)
546 (progn
547 (dispatch-command cmd))
548 (message "No Match"))))
550 (defcommand switch-to-buffer ((buffer &optional norecord)
551 (:buffer "Switch To Buffer: " (buffer-name (other-buffer (current-buffer)))))
552 "Select buffer buffer in the current window.
553 If buffer does not identify an existing buffer,
554 then this function creates a buffer with that name.
556 When called from Lisp, buffer may be a buffer, a string (a buffer name),
557 or nil. If buffer is nil, then this function chooses a buffer
558 using `other-buffer'.
559 Optional second arg norecord non-nil means
560 do not put this buffer at the front of the list of recently selected ones.
561 This function returns the buffer it switched to.
563 WARNING: This is NOT the way to work on another buffer temporarily
564 within a Lisp program! Use `set-buffer' instead. That avoids messing with
565 the window-buffer correspondences."
566 (unless buffer
567 (setf buffer (other-buffer (current-buffer))))
568 (let ((w (frame-current-window (selected-frame))))
569 (when (typep w 'minibuffer-window)
570 (error "its a minibuffer"))
571 (setf buffer (get-buffer-create buffer))
572 (set-buffer buffer)
573 (unless norecord
574 (record-buffer buffer))
575 (set-window-buffer w buffer)))
577 (defcommand save-buffers-kill-emacs ()
578 ;; TODO: save-some-buffers
579 (throw 'lice-quit t))
581 (defcommand kill-buffer ((buffer)
582 (:buffer "Kill buffer: " (buffer-name (current-buffer)) t))
583 "Kill the buffer BUFFER.
584 The argument may be a buffer or may be the name of a buffer.
585 defaults to the current buffer.
587 Value is t if the buffer is actually killed, nil if user says no.
589 The value of `kill-buffer-hook' (which may be local to that buffer),
590 if not void, is a list of functions to be called, with no arguments,
591 before the buffer is actually killed. The buffer to be killed is current
592 when the hook functions are called.
594 Any processes that have this buffer as the `process-buffer' are killed
595 with SIGHUP."
596 (let* ((target (get-buffer buffer))
597 (other (other-buffer target)))
598 (if target
599 (progn
600 ;; all windows carrying the buffer need a new buffer
601 (loop for w in (frame-window-list (selected-frame))
602 do (when (eq (window-buffer w) target)
603 (set-window-buffer w other)))
604 (setf *buffer-list* (delete target *buffer-list*)))
605 (error "No such buffer ~a" buffer))))
607 (defun eval-echo (string)
608 ;; FIXME: don't just abandon the output
609 (let* ((stream (make-string-output-stream))
610 (*standard-output* stream)
611 (*error-output* stream)
612 (*debug-io* stream))
613 (multiple-value-bind (sexpr pos) (read-from-string string)
614 (if (= pos (length string))
615 (message "~s" (eval sexpr))
616 (error "Trailing garbage is ~a" string)))))
618 (defun eval-print (string)
619 (multiple-value-bind (sexpr pos) (read-from-string string)
620 (if (= pos (length string))
621 (insert (format nil "~%~s~%" (eval sexpr)))
622 (error "Trailing garbage is ~a" string))))
624 (defcommand eval-expression ((s)
625 (:string "Eval: "))
626 ;;(handler-case
627 (eval-echo s))
628 ;;(error (c) (message "Eval error: ~s" c))))
630 (defcommand exchange-point-and-mark ()
631 (let ((p (point)))
632 (goto-char (marker-position (mark-marker)))
633 (set-marker (mark-marker) p)))
635 (defcommand set-mark-command ()
636 (set-marker (mark-marker) (point))
637 (message "Mark set"))
639 (defun push-mark (&optional location nomsg activate)
640 "Set mark at LOCATION (point, by default) and push old mark on mark ring.
641 If the last global mark pushed was not in the current buffer,
642 also push LOCATION on the global mark ring.
643 Display `Mark set' unless the optional second arg NOMSG is non-nil.
644 In Transient Mark mode, activate mark if optional third arg ACTIVATE non-nil.
646 Novice Emacs Lisp programmers often try to use the mark for the wrong
647 purposes. See the documentation of `set-mark' for more information.
649 In Transient Mark mode, this does not activate the mark."
650 ;; TODO implement
651 (set-marker (mark-marker) (point))
652 (unless nomsg
653 (message "Mark set")))
655 ;; (defun kill-ring-save (beg end)
656 ;; "Save the region to the kill ring."
658 (defcommand scroll-up ()
659 (let ((win (get-current-window)))
660 (window-scroll-up win (max 1 (- (window-height win)
661 *next-screen-context-lines*)))))
663 (defcommand scroll-down ()
664 (let ((win (get-current-window)))
665 (window-scroll-down win (max 1 (- (window-height win)
666 *next-screen-context-lines*)))))
668 (defcommand end-of-buffer ()
669 "Move point to the end of the buffer; leave mark at previous position.
670 With arg N, put point N/10 of the way from the end.
672 If the buffer is narrowed, this command uses the beginning and size
673 of the accessible part of the buffer."
674 (set-mark-command)
675 (goto-char (point-max)))
677 (defcommand just-one-space ((&optional (n 1))
678 :prefix)
679 "Delete all spaces and tabs around point, leaving one space (or N spaces)."
680 (let ((orig-pos (point)))
681 (skip-chars-backward (coerce '(#\Space #\Tab) 'string))
682 (constrain-to-field nil orig-pos)
683 (dotimes (i n)
684 (if (char= (following-char) #\Space)
685 (forward-char 1)
686 (insert #\Space)))
687 (delete-region
688 (point)
689 (progn
690 (skip-whitespace-forward)
691 (constrain-to-field nil orig-pos t)))))
693 (defcommand beginning-of-buffer ()
694 "Move point to the beginning of the buffer; leave mark at previous position.
695 With arg N, put point N/10 of the way from the beginning.
697 If the buffer is narrowed, this command uses the beginning and size
698 of the accessible part of the buffer."
699 (set-mark-command)
700 (goto-char (point-min)))
702 (defcommand split-window-vertically ()
703 (split-window (get-current-window)))
705 (defcommand split-window-horizontally ()
706 (split-window (get-current-window) nil t))
708 (defcommand other-window ()
709 (let ((w (next-window (get-current-window) t)))
710 (if w
711 (select-window w)
712 (message "No other window."))))
714 (defcommand switch-to-buffer-other-window ((buffer)
715 (:buffer "Switch to buffer in other window: " (buffer-name (other-buffer (current-buffer)))))
716 (let* ((cw (get-current-window))
717 (w (or (next-window cw)
718 (split-window cw))))
719 (select-window w)
720 (switch-to-buffer buffer)))
722 (defcommand keyboard-quit ()
723 (signal 'quit))
725 ;;; kill ring
727 (defun kill-new (string &optional replace)
728 "Make STRING the latest kill in the kill ring.
729 Set the kill-ring-yank pointer to point to it.
730 Optional second argument REPLACE non-nil means that STRING will replace
731 the front of the kill ring, rather than being added to the list."
732 (if (and replace
733 *kill-ring*)
734 (setf (car *kill-ring*) string)
735 (push string *kill-ring*))
736 (when (> (length *kill-ring*) *kill-ring-max*)
737 (setf (cdr (nthcdr (1- *kill-ring-max*) *kill-ring*)) nil))
738 (setf *kill-ring-yank-pointer* *kill-ring*))
740 (defun copy-region-as-kill (start end &optional (buffer (current-buffer)))
741 (multiple-value-setq (start end) (validate-region start end buffer))
742 (kill-new (buffer-substring start end buffer)))
744 (defcommand kill-ring-save ()
745 (copy-region-as-kill (mark) (point)))
747 (defcommand kill-region ((beg end)
748 :region-beginning
749 :region-end)
750 "Kill between point and mark.
751 The text is deleted but saved in the kill ring.
752 The command C-y can retrieve it from there.
753 (If you want to kill and then yank immediately, use M-w.)"
754 (copy-region-as-kill beg end)
755 (delete-region beg end))
758 (defcommand kill-line ()
759 (kill-region (point)
760 (progn
761 (when (eobp)
762 (signal 'end-of-buffer))
763 (if (char= (buffer-char-after (current-buffer) (point)) #\Newline)
764 (forward-line 1)
765 (goto-char (buffer-end-of-line)))
766 (point))))
768 (defun current-kill (n &optional do-not-move)
769 "Rotate the yanking point by N places, and then return that kill.
770 If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
771 yanking point; just return the Nth kill forward."
772 (unless *kill-ring*
773 (signal 'kill-ring-empty))
774 (let ((argth-kill-element
775 (nthcdr (mod (- n (length *kill-ring-yank-pointer*))
776 (length *kill-ring*))
777 *kill-ring*)))
778 (unless do-not-move
779 (setf *kill-ring-yank-pointer* argth-kill-element))
780 (car argth-kill-element)))
782 (defcommand yank ()
783 (set-mark-command)
784 (insert (current-kill 0)))
786 (defcommand yank-pop ()
787 (unless (eq *last-command* 'yank)
788 (error "Previous command was not a yank: ~a" *last-command*))
789 (setf *this-command* 'yank)
790 (delete-region (mark) (point))
791 (insert (current-kill 1)))
793 ;;; universal argument
795 (defun prefix-numeric-value (prefix)
796 "Return numeric meaning of raw prefix argument RAW.
797 A raw prefix argument is what you get from :raw-prefix.
798 Its numeric meaning is what you would get from :prefix."
799 ;; TODO
800 (cond ((null prefix)
802 ((eq prefix '-)
804 ((and (consp prefix)
805 (integerp (car prefix)))
806 (car prefix))
807 ((integerp prefix)
808 prefix)
809 (t 1)))
811 (defun prefix-arg ()
812 "Return numeric meaning of *prefix-arg*"
813 (prefix-numeric-value *prefix-arg*))
815 (defun raw-prefix-arg ()
816 "Return the current prefix arg in raw form."
817 *prefix-arg*)
819 (defvar *overriding-map-is-bound* nil)
820 (defvar *saved-overriding-map* nil)
821 (defvar *universal-argument-num-events* nil)
823 (defvar *universal-argument-map*
824 (let ((map (make-sparse-keymap)))
825 ;;(define-key map (kbd "t") 'universal-argument-other-key)
826 (define-key map t 'universal-argument-other-key)
827 ;;(define-key map [switch-frame] nil)
828 (define-key map (kbd "C-u") 'universal-argument-more)
829 (define-key map (kbd "-") 'universal-argument-minus)
830 (define-key map (kbd "0") 'digit-argument)
831 (define-key map (kbd "1") 'digit-argument)
832 (define-key map (kbd "2") 'digit-argument)
833 (define-key map (kbd "3") 'digit-argument)
834 (define-key map (kbd "4") 'digit-argument)
835 (define-key map (kbd "5") 'digit-argument)
836 (define-key map (kbd "6") 'digit-argument)
837 (define-key map (kbd "7") 'digit-argument)
838 (define-key map (kbd "8") 'digit-argument)
839 (define-key map (kbd "9") 'digit-argument)
840 ;; (define-key map [kp-0] 'digit-argument)
841 ;; (define-key map [kp-1] 'digit-argument)
842 ;; (define-key map [kp-2] 'digit-argument)
843 ;; (define-key map [kp-3] 'digit-argument)
844 ;; (define-key map [kp-4] 'digit-argument)
845 ;; (define-key map [kp-5] 'digit-argument)
846 ;; (define-key map [kp-6] 'digit-argument)
847 ;; (define-key map [kp-7] 'digit-argument)
848 ;; (define-key map [kp-8] 'digit-argument)
849 ;; (define-key map [kp-9] 'digit-argument)
850 ;; (define-key map [kp-subtract] 'universal-argument-minus)
851 map)
852 "Keymap used while processing \\[universal-argument].")
854 (defun ensure-overriding-map-is-bound ()
855 "Check `*overriding-terminal-local-map*' is `*universal-argument-map*'."
856 (unless *overriding-map-is-bound*
857 (setf *saved-overriding-map* *overriding-terminal-local-map*
858 *overriding-terminal-local-map* *universal-argument-map*
859 *overriding-map-is-bound* t)))
861 (defun restore-overriding-map ()
862 "Restore `*overriding-terminal-local-map*' to its saved value."
863 (setf *overriding-terminal-local-map* *saved-overriding-map*
864 *overriding-map-is-bound* nil))
866 (defcommand universal-argument ()
867 (setf *prefix-arg* (list 4)
868 *universal-argument-num-events* (length (this-command-keys)))
869 (ensure-overriding-map-is-bound))
871 (defcommand universal-argument-more ((arg)
872 :raw-prefix)
873 (if (consp arg)
874 (setf *prefix-arg* (list (* 4 (car arg))))
875 (if (eq arg '-)
876 (setf *prefix-arg* (list -4))
877 (progn
878 (setf *prefix-arg* arg)
879 (restore-overriding-map))))
880 (setf *universal-argument-num-events* (length (this-command-keys))))
882 (defcommand negative-argument ((arg)
883 :raw-prefix)
884 "Begin a negative numeric argument for the next command.
885 \\[universal-argument] following digits or minus sign ends the argument."
886 (cond ((integerp arg)
887 (setf *prefix-arg* (- arg)))
888 ((eq arg '-)
889 (setf *prefix-arg* nil))
891 (setf *prefix-arg* '-)))
892 (setf *universal-argument-num-events* (length (this-command-keys)))
893 (ensure-overriding-map-is-bound))
895 (defcommand digit-argument ((arg)
896 :raw-prefix)
897 "Part of the numeric argument for the next command.
898 \\[universal-argument] following digits or minus sign ends the argument."
899 (let* ((char (last-command-char))
900 (digit (- (logand (char-code char) #o177) (char-code #\0))))
901 (cond ((integerp arg)
902 (setf *prefix-arg* (+ (* arg 10)
903 (if (< arg 0) (- digit) digit))))
904 ((eq arg '-)
905 ;; Treat -0 as just -, so that -01 will work.
906 (setf *prefix-arg* (if (zerop digit) '- (- digit))))
908 (setf *prefix-arg* digit))))
909 (setf *universal-argument-num-events* (length (this-command-keys)))
910 (ensure-overriding-map-is-bound))
912 ;; For backward compatibility, minus with no modifiers is an ordinary
913 ;; command if digits have already been entered.
914 (defcommand universal-argument-minus ((arg)
915 :raw-prefix)
916 (if (integerp arg)
917 (universal-argument-other-key arg)
918 (negative-argument arg)))
920 ;; Anything else terminates the argument and is left in the queue to be
921 ;; executed as a command.
922 (defcommand universal-argument-other-key ((arg)
923 :raw-prefix)
924 (setf *prefix-arg* arg)
925 (let* ((keylist (this-command-keys)))
926 (setf *unread-command-events* keylist))
927 ;; (append (nthcdr *universal-argument-num-events* keylist)
928 ;; *unread-command-events*)))
929 ;;FIXME: (reset-this-command-lengths)
930 (restore-overriding-map))
933 ;; (defcommand append-to-buffer ((buffer :buffer "Append to buffer: " (buffer-name (other-buffer (current-buffer))))
934 ;; (start :region-beginning)
935 ;; (end :region-end))
936 ;; "Append to specified buffer the text of the region.
937 ;; It is inserted into that buffer before its point.
939 ;; When calling from a program, give three arguments:
940 ;; buffer (or buffer name), start and end.
941 ;; start and end specify the portion of the current buffer to be copied."
942 ;; (let ((oldbuf (current-buffer)))
943 ;; (save-excursion
944 ;; (let* ((append-to (get-buffer-create buffer))
945 ;; (windows (get-buffer-window-list append-to t t))
946 ;; point)
947 ;; (set-buffer append-to)
948 ;; (setf point (point))
949 ;; (barf-if-buffer-read-only)
950 ;; (insert-buffer-substring oldbuf start end)
951 ;; (dolist (window windows)
952 ;; (when (= (window-point window) point)
953 ;; (set-window-point window (point))))))))
955 (defcommand transpose-chars ((arg)
956 :prefix)
957 "Interchange characters around point, moving forward one character.
958 With prefix arg ARG, effect is to take character before point
959 and drag it forward past ARG other characters (backward if ARG negative).
960 If no argument and at end of line, the previous two chars are exchanged."
961 (and (null arg) (eolp) (forward-char -1))
962 (transpose-subr 'forward-char (prefix-numeric-value arg)))
964 (defcommand transpose-words ((arg)
965 :prefix)
966 "Interchange words around point, leaving point at end of them.
967 With prefix arg ARG, effect is to take word before or around point
968 and drag it forward past ARG other words (backward if ARG negative).
969 If ARG is zero, the words around or after point and around or after mark
970 are interchanged."
971 ;; FIXME: `foo a!nd bar' should transpose into `bar and foo'.
972 (transpose-subr 'forward-word arg))
974 ;; (defun transpose-sexps ((arg)
975 ;; :prefix)
976 ;; "Like \\[transpose-words] but applies to sexps.
977 ;; Does not work on a sexp that point is in the middle of
978 ;; if it is a list or string."
979 ;; (transpose-subr
980 ;; (lambda (arg)
981 ;; ;; Here we should try to simulate the behavior of
982 ;; ;; (cons (progn (forward-sexp x) (point))
983 ;; ;; (progn (forward-sexp (- x)) (point)))
984 ;; ;; Except that we don't want to rely on the second forward-sexp
985 ;; ;; putting us back to where we want to be, since forward-sexp-function
986 ;; ;; might do funny things like infix-precedence.
987 ;; (if (if (> arg 0)
988 ;; ;;(looking-at "\\sw\\|\\s_")
989 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
990 ;; (or (alpha-char-p (char-after (point)))
991 ;; (find (char-after (point)) "*/+-%$!@&"))
992 ;; (and (not (bobp))
993 ;; (save-excursion (forward-char -1)
994 ;; ;; (looking-at "\\sw\\|\\s_")
995 ;; ;; FIXME: we don't have looking-at or syntax classes. Fake it for now
996 ;; (or (alpha-char-p (char-after (point)))
997 ;; (find (char-after (point)) "*/+-%$!@&"))
998 ;; )))
999 ;; ;; Jumping over a symbol. We might be inside it, mind you.
1000 ;; (progn (funcall (if (> arg 0)
1001 ;; 'skip-syntax-backward 'skip-syntax-forward)
1002 ;; "w_")
1003 ;; (cons (save-excursion (forward-sexp arg) (point)) (point)))
1004 ;; ;; Otherwise, we're between sexps. Take a step back before jumping
1005 ;; ;; to make sure we'll obey the same precedence no matter which direction
1006 ;; ;; we're going.
1007 ;; (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) " .")
1008 ;; (cons (save-excursion (forward-sexp arg) (point))
1009 ;; (progn (while (or (forward-comment (if (> arg 0) 1 -1))
1010 ;; (not (zerop (funcall (if (> arg 0)
1011 ;; 'skip-syntax-forward
1012 ;; 'skip-syntax-backward)
1013 ;; ".")))))
1014 ;; (point)))))
1015 ;; arg 'special))
1017 (defcommand transpose-lines ((arg)
1018 :prefix)
1019 "Exchange current line and previous line, leaving point after both.
1020 With argument ARG, takes previous line and moves it past ARG lines.
1021 With argument 0, interchanges line point is in with line mark is in."
1022 (transpose-subr (function
1023 (lambda (arg)
1024 (if (> arg 0)
1025 (progn
1026 ;; Move forward over ARG lines,
1027 ;; but create newlines if necessary.
1028 (setq arg (forward-line arg))
1029 (if (char/= (preceding-char) #\Newline)
1030 (setq arg (1+ arg)))
1031 (if (> arg 0)
1032 (newline arg)))
1033 (forward-line arg))))
1034 arg))
1036 (defun transpose-subr (mover arg &optional special)
1037 (let ((aux (if special mover
1038 (lambda (x)
1039 (cons (progn (funcall mover x) (point))
1040 (progn (funcall mover (- x)) (point))))))
1041 pos1 pos2)
1042 (cond
1043 ((= arg 0)
1044 (save-excursion
1045 (setq pos1 (funcall aux 1))
1046 (goto-char (mark))
1047 (setq pos2 (funcall aux 1))
1048 (transpose-subr-1 pos1 pos2))
1049 (exchange-point-and-mark))
1050 ((> arg 0)
1051 (setq pos1 (funcall aux -1))
1052 (setq pos2 (funcall aux arg))
1053 (transpose-subr-1 pos1 pos2)
1054 (goto-char (car pos2)))
1056 (setq pos1 (funcall aux -1))
1057 (goto-char (car pos1))
1058 (setq pos2 (funcall aux arg))
1059 (transpose-subr-1 pos1 pos2)))))
1061 (defun transpose-subr-1 (pos1 pos2)
1062 (when (> (car pos1) (cdr pos1)) (setq pos1 (cons (cdr pos1) (car pos1))))
1063 (when (> (car pos2) (cdr pos2)) (setq pos2 (cons (cdr pos2) (car pos2))))
1064 (when (> (car pos1) (car pos2))
1065 (let ((swap pos1))
1066 (setq pos1 pos2 pos2 swap)))
1067 (if (> (cdr pos1) (car pos2)) (error "Don't have two things to transpose"))
1068 ;; (atomic-change-group
1069 (let (word2)
1070 ;; FIXME: We first delete the two pieces of text, so markers that
1071 ;; used to point to after the text end up pointing to before it :-(
1072 (setq word2 (delete-and-extract-region (car pos2) (cdr pos2)))
1073 (goto-char (car pos2))
1074 (insert (delete-and-extract-region (car pos1) (cdr pos1)))
1075 (goto-char (car pos1))
1076 (insert word2)))
1078 ;;;
1080 (defcustom-buffer-local :fill-prefix nil
1081 "*String for filling to insert at front of new line, or nil for none."
1082 :type '(choice (const :tag "None" nil)
1083 string)
1084 :group 'fill)
1088 (provide :lice-0.1/simple)