[comp.emacs] super-kill function for Gnu Emacs

gudeman@arizona.UUCP (05/20/87)

Here's a function I have used for over a year, I don't know how I ever
lived without it.  It lets you rebind a lot of function keys that are
presently taken up with kill commands.
--- cut here ---
;;; Super-kill acts as a kill prefix.  You type C-k (or whatever
;;; super-kill is bound to) followed by a command key sequence,
;;; and super-kill kills some text depending on the command.  If
;;; the key sequence is a printing character, this function acts
;;; much like 'zap-to-char.  If the key sequence represents a
;;; movement command, the text between the starting and ending
;;; points is deleted.  There are also a number of special
;;; commands.  Unfortunately, there is no way to change the
;;; "bindings" of these keys short of editing the super-kill
;;; function.

;;; Hints:
;;;   Bind 'recursive-edit to some control key such as C-\.  Then
;;; you can move to the start of an arbitrary block of text, type
;;; C-k C-\, then move to the end of the text, hit ESC C-c, and
;;; the block of text will be deleted.
;;;   Bind 'forward-sexp and 'backward-sexp to some control keys,
;;; you will be amazed at how often you want to delete the
;;; previous or following sexp.  If you use arrow keys for
;;; 'forward-char and 'backward-char, bind the sexp commands to
;;; C-f and C-b.
;;;   The effects of 'kill-line can be simulated (more or less)
;;; by C-k C-e and C-k C-l (where C-e is bound to 'end-of-line).

;;; Written by David Gudeman (gudeman@arizona.edu) April 1987

(defun super-kill (arg)
  "Kill text between current point and point after the next command.
If the prefix-arg is ARG, and the following key stroke is:

C-w		    delete-horizontal-space (as the command)
C-o		    delete-blank-lines (as the command)
C-l		    kill whole line and the ARG - 1 following lines
C-j		    join lines current line to arg following lines,
		    delete any fill prefix, and fixup whitespace
printing char       kill upto and including the ARGth occurrence of the
			character (which can be quoted).
C-q char	    as above, except that char is quoted if it is not C-g.
DEL		    kill back to the ARGth occurrence of the next char
			which is quoted if it is not C-g.
movement command    kill the buffer section between starting point
			and point after the command is executed with ARG
			as its prefix-arg
C-k		    Read another character and interpret as above, but copy
			the indicated text to the kill-ring instead of killing
			it.  More C-k's toggle from kill to copy.
C-y		    Read another character and interpret as above, but toggle
			whether the text will be appended to the kill-ring
			or put in a new slot.
otherwise	    no affect

Called from an elisp function, takes one argument, the prefix arg."
  (interactive "P")
  (let* ((key (read-key-sequence nil))
	 (c (string-to-char key))
	 (n (prefix-numeric-value arg))
	 (buf (current-buffer))
	 (p1 (point))
	 p2 copy-only)
    (while (memq c '(?\C-k ?\C-y))
      (if (= c ?\C-y)
	  (setq last-command
		(if (equal 'kill-region last-command)
		    nil
		  'kill-region))
	(setq copy-only (not copy-only)))
      (setq key (read-key-sequence nil))
      (setq c (string-to-char key)))
    (cond
     ((or (and (>= c ? ) (<= c ?~)) (= c ?\t))
      (search-forward key nil nil n))
     ((= c ?\C-m)
      (search-forward ?\n nil nil n))
     ((= c ?\C-q)
      (search-forward (char-to-string (read-char)) nil nil n))
     ((= c ?\C-?)
      (search-forward (char-to-string (read-char)) nil nil (- n)))
     ((= c ?\C-w)
      (delete-horizontal-space)
      (setq buf nil))		;prevent deletion later
     ((= c ?\C-o)
      (delete-blank-lines)
      (setq buf nil))		;ditto above
     ((= c ?\C-l)
      (beginning-of-line 1)
      (setq p1 (point))
      (beginning-of-line (1+ n)))
     ((= c ?\C-j)
      (if (< n 0)		; p2 is used as an increment,
	  (setq p2  1 c 0)	;    and c is a direction
	(setq p2 -1 c 1))
      (while (/= n 0)
	(end-of-line c)
	(setq p1 (point))
	(forward-char 1)
	(and fill-prefix
	     (looking-at fill-prefix)
	     (forward-char (length fill-prefix)))
	(delete-region p1 (point))
	(fixup-whitespace)
	(setq n (+ n p2)))
      (setq buf nil))		;ditto above
     (t ;(let ((current-prefix-arg arg))
      (call-interactively (key-binding key))));)
    (setq p2 (point))
    (if (and (/= p1 p2) (eql buf (current-buffer)))
	(if copy-only
	    (copy-region-as-kill p1 p2)
	  (kill-region p1 p2))))
  (sit-for 0))