From: jbw@bigbird.bu.edu (Joe Wells)
Newsgroups: comp.emacs
Subject: Re: Can't teach old dog new tricks...
Date: 10 Apr 92 06:46:46 GMT
 <JBW.92Apr1212127@bigbird.bu.edu> <1992Apr2.040115.4317@sunb10.cs.uiuc.edu>
 <1992Apr2.135308.29983@Csli.Stanford.EDU>
 <1992Apr2.180258.9351@sunb10.cs.uiuc.edu>
Organization: Boston University Computer Science Department
In-reply-to: epstein@sunc7.cs.uiuc.edu's message of 2 Apr 92 18:02:58 GMT

In article <1992Apr2.180258.9351@sunb10.cs.uiuc.edu> epstein@sunc7.cs.uiuc.edu (Milt Epstein) writes:

   In <1992Apr2.135308.29983@Csli.Stanford.EDU> gandalf@Csli.Stanford.EDU (Juergen Wagner) writes:

   >The `.' command can be emulated by marking the beginning and end of the
   >command sequence you want to repeat. If that's not acceptable because you
   >don't want to have "to plan ahead", define a function that looks at your
   >keystroke history and defines a special key to perform what you want to
   >extract from the history. It is possible to have the exact semantics of
   >`.' in Emacs once you define it precisely.

No it isn't.

   Now this I would like to see, and might not miss `.' after having it.
   Has anyone written such a command?

Yes.  I'm enclosing my version.  It works in many cases, but it's buggy.
Perhaps someone can enhance it.  Unfortunately, to make it work correctly
in all cases will require changes to the C code of Emacs.

-- 
Enjoy,

Joe Wells <jbw@cs.bu.edu>

Member of the League for Programming Freedom --- send e-mail for details

----------------------------------------------------------------------
;; Created by: Joe Wells, jbw@maverick.uswest.com
;; Created on: Sun Jul 28 00:41:34 1991
;; Last modified by: Joe Wells, jbw@bigbird.bu.edu
;; Last modified on: Fri Apr 10 01:46:03 1992
;; Filename: repeat.el
;; Purpose: repeat previous command
;; Version: 1.0
;; Change log: 
;; 
;; Fri Apr 10 01:46:04 1992  Joe Wells  (jbw at bigbird.bu.edu)
;; 
;; 	* Release version 1.0
;; 

;; David Spector <ds@primerd.prime.com, ds@hollin.prime.com>

;; Copyright (c) 1989 David Spector
;; This software may be used, copied, and modified freely, except not
;; as part of a product sold for profit, so long as these four copyright
;; lines are retained without change.  There is no warranty of any kind.

;; Copyright 1991, 1992 Joe Wells
;; I set the same copying conditions as David Spector does above.

;; LCD Archive Entry:
;; repeat|Joe Wells|jbw@cs.bu.edu|repeat last command|April 10 1992|1.0|????

(defvar repeat-command nil)
(defvar repeat-minibuf-exit-commands
  '(exit-minibuffer minibuffer-complete-and-exit))
(defvar repeat-kill-commands
  '(backward-kill-paragraph backward-kill-sentence backward-kill-sexp backward-kill-word kill-comment kill-line kill-paragraph kill-region kill-region-and-unmark kill-sentence kill-sexp kill-word))

(defun kbd-macro-p (bound-function)
  (while (and (symbolp bound-function)
	      (fboundp bound-function))
    (setq bound-function (symbol-function bound-function)))
  (stringp bound-function))

;; There is a bug that is triggered only on startup because recent-keys
;; has less than 100 keys in it ... FIX ***
(defun repeat (count)
  (interactive "p")
  (if (eq last-command 'repeat)
      nil
    (let* ((recent-keys (recent-keys))
	   (this-command-keys (this-command-keys))
	   (get-keys-form
	    (function
	     (lambda (length)
	       (let ((pos (- (- (length recent-keys) length)
			     (length this-command-keys))))
		 (substring recent-keys pos (+ pos length))))))
	   (strings (mapcar get-keys-form '(1 2 3 4 5 6)))
	   (get-binding-form
	    (function
	     (lambda (key-seq)
	       (let ((binding (local-key-binding key-seq)))
		 (if (or (null binding)
			 (numberp binding)
			 (keymapp binding))
		     (setq binding (global-key-binding key-seq)))
		 (if (or (numberp binding)
			 (keymapp binding))
		     nil
		   binding)))))
	   (bindings (mapcar get-binding-form strings))
	   string binding tentative-command command)
      (if (memq last-command repeat-minibuf-exit-commands)
	  (setq command (car command-history)))
      (while bindings
	(setq binding (car bindings)
	      bindings (cdr bindings)
	      string (car strings)
	      strings (cdr strings))
	(cond ((eq binding 'call-last-kbd-macro)
	       (setq command 'call-last-kbd-macro))
	      ((kbd-macro-p binding)
	       (setq command binding))
	      ((or (eq last-command binding)
		   (and (eq last-command 'kill-region)
			(memq binding repeat-kill-commands)))
	       (setq tentative-command
		     (if (eq binding 'self-insert-command)
			 string
		       binding)))))
      (setq repeat-command (or command tentative-command last-command))))
  (while (> count 0)
    (if (memq repeat-command repeat-kill-commands)
	(append-next-kill))
    (if (commandp repeat-command)
	(command-execute repeat-command)
      (eval repeat-command))
    (setq count (1- count)))
  (setq this-command 'repeat
	last-command 'repeat))

(provide 'repeat)