Mar 05,
2019

Emacs Context Menu

Howdy folks!

Today I want to talk about the Emacs context menu, or the lack of it on a default install.

Out of the box, when clicking the right mouse button on an Emacs' window in graphical mode nothing happens, well the mouse-save-then-kill function is invoked1 but it's not what one usually expect. I must admit that sometime I also fumbled with the mouse before reaching for the keyboard, usually when interacting with other applications like web browsers or file managers.

As a side note, speaking of interaction between Emacs and file managers, it never occurred to me that the Dired mode could react to drag&drop actions until I "randomly" copied a file to a currently opened Emacs' Dired window. I was quite surprised to see the file copied to the relative directory.

Try to replicate that vi.

Anywho, this is my take on the context menu in graphical mode:

My take on Emacs context menu

Well, I didn't want anything fancy, I like to keep things simple; if I'm using the mouse it's probably because I've copied a string from another application and I want to yank/paste2 it or the other way around, so that's what I was striving for.

For the interested reader, I'll put all the code below as it's quite minimal:

(global-set-key [mouse-3] 'my-context-menu)

(with-eval-after-load "menu-bar"
  (require 'url-util)

  (defvar edit-popup-menu
    '(keymap
      (undo menu-item "Undo" undo
            :enable (and
                     (not buffer-read-only)
                     (not
                      (eq t buffer-undo-list))
                     (if
                         (eq last-command 'undo)
                         (listp pending-undo-list)
                       (consp buffer-undo-list)))
            :keys "")
      (separator-undo menu-item "--")
      (cut menu-item "Cut" clipboard-kill-region
           :enable (use-region-p)
           :keys "")
      (copy-link menu-item "Copy Link" 
                 (lambda () (interactive) (kill-new (url-get-url-at-point)))
            :enable (and (url-get-url-at-point))
            :keys "")
      (copy menu-item "Copy" clipboard-kill-ring-save
            :enable (use-region-p)
            :keys "")
      (paste menu-item "Paste" clipboard-yank
             :keys "")
      (paste-from-menu menu-item "Paste from Kill Menu" yank-menu
                       :enable (and
                                (cdr yank-menu)
                                (not buffer-read-only))
                       :help "Select a string from the kill ring and paste it")
      (clear menu-item "Delete" delete-region
             :enable (and mark-active (not buffer-read-only))
             :help "Clear region"
             :keys "Del")
      (separator-select-all menu-item "--")
      (mark-whole-buffer menu-item "Select All" mark-whole-buffer
                         :enable (not (= (buffer-size) 0)))))

  (defun my-context-menu (event)
    "Pop up a context menu."
    (interactive "e")
    (popup-menu edit-popup-menu)))

(provide 'context-menu)

That's all.


  1. on a terminal it should pop up the terminal emulator context menu but that depends on the terminal emulator implementation ↩︎

  2. my defaults are the traditional Alt-w/Ctrl-w for copy/kill and Alt-y for yank ↩︎