Subject: bug#9406: 24.0.50; Use M-p/M-n to navigate through the kill ring

From: Stefan Monnier <[email-masked]>
Date: Thu, 01 Sep 2011 20:39:20 -0400

>> Why "free" the M-y binding if it means jailing M-n and M-p?

You didn't read me right: I only pointed out that *if/when* M-p/M-n is
used as suggested, then M-y can be freed.

>> M-y does nothing useful unless preceded by C-y today, so in that
>> sense it's already "free".

That's true, except that the current implementation occupies the M-y
binding all the time.

> It's so convenient to have a kill-ring browser, i don't understand why
> Emacs have not one and continue cycling blindly to find something in
> kill-ring...

It's already been suggested, and I agree it's a good idea.
I.e. patches welcome for Emacs-24.2.  But most likely I'd only accept
such a patch if the "kill-ring browser" uses a more-or-less standard
"minibuffer with completion".  OTOH it'd be OK for that patch to include
some changes to minibuffer.el, if needed.  FWIW, here's the code I'm
using right now.

        Stefan

(defun yank-browse (string)
  "Browse the `kill-ring' to choose which entry to yank."
  (interactive
   (minibuffer-with-setup-hook #'minibuffer-completion-help
     (let* ((kills (delete-dups (append kill-ring-yank-pointer kill-ring nil)))
            (entries
             (mapcar (lambda (string)
                       (let ((pos 0))
                         ;; FIXME: Maybe we should start by removing
                         ;; all properties.
                         (setq string (copy-sequence string))
                         (while (string-match "\n" string pos)
                           ;; FIXME: Maybe completion--insert-strings should
                           ;; do that for us.
                           (put-text-property
                            (match-beginning 0) (match-end 0)
                            'display (eval-when-compile
                                       (propertize "\\n" 'face 'escape-glyph))
                            string)
                           (setq pos (match-end 0)))
                         ;; FIXME: We may use the window-width of the
                         ;; wrong window.
                         (when (>= (* 3 (string-width string))
                                   (* 2 (window-width)))
                           (let ((half (- (/ (window-width) 3) 1)))
                             ;; FIXME: We're using char-counts rather than
                             ;; width-count.
                             (put-text-property
                              half (- (length string) half)
                              'display (eval-when-compile
                                         (propertize "……" 'face 'escape-glyph))
                              string)))
                         string))
                     kills))
            (table (lambda (string pred action)
                     (cond
                      ((eq action 'metadata)
                       '(metadata (category . kill-ring)))
                      (t
                       (complete-with-action action entries string pred))))))
       ;; FIXME: We should return the entry from the kill-ring rather than
       ;; the entry from the completion-table.
       ;; FIXME: substring completion doesn't work well because it only matches
       ;; subtrings before the first \n.
       ;; FIXME: completion--insert-strings assumes that boundaries of
       ;; candidates are obvious enough, but with kill-ring entries this is not
       ;; true, so we'd probably want to display them with «...» around them.
       (list (completing-read "Yank: " table nil t)))))
  (setq this-command 'yank)
  (insert-for-yank string))