It seems as though an irrational fear of the mouse dominates amongst Un*x dogmatists. Be it because their tools don’t integrate, or because it is a symbol or rebellion, a means to differentiate their prior ignorance from the enlightenment they have attained between the standard input and the standard output stream, the self-emancipation from the mouse is a rite of passage or a shameful burden on those who fail1 2.
As might be clear by my tone, I have little regard for this position. It certainly is worthwhile knowing that and how it is possible to avoid using the mouse, when keyboard shortcuts more convenient3, but there is no need for the artificial asceticism of ready-to-use technology, for the sake of purity and dogma.
Featured Content Ads
add advertising hereThe denunciation of the mouse usually involves invoking concepts such as the “home row”, or the cumbersome migration of the hand between keyboard and mouse. These might all be well and good, if I were a typist and as such all I did was to type. But this isn’t the case, I ponder and perceive, more than I write.
When debugging code or studying a program, it is quite comfortable to depend on only one hand, and have the other free to scribble or relax. The issue isn’t using a mouse or only using a keyboard, it is context switching.
And now for something mostly different: Speaking of “context”, here is something more concrete:
The more or less recent addition of context-menu-mode
by the ever creative Juri Linkov to Emacs 28 is worth talking about.
Featured Content Ads
add advertising hereThe general idea is to provide a “context menu” to Emacs, that can be invoked by a simple right click. You might know these kinds of menus from your file manager or browser, where you get fewer or more options, depend on what you clicked. To enabled this feature in Emacs 28 or greater, one simply has to enable the aforementioned context-menu-mode
minor mode.
It wouldn’t be Emacs if it ended here! It has to be configurable, extendable and improvable in accordance to the users needs and wants. That is where context-menu-functions
comes into play. This is a list of functions used to populate the menu programmatically. In my case, I set it to:
setq context-menu-functions
(
'(context-menu-ffap
occur-context-menu
context-menu-region
context-menu-undo context-menu-dictionary))
For example, the first function context-menu-ffap
checks if there is a generalized file name wherever I clicked, and in that case it will insert a menu item for me to open whatever I clicked on:
When first playing around with context-menu-mode
, my experiments led me to contribute occur-context-menu
that generates an occur buffer for the word or symbol at point. As mentioned, this is a nice instrument when debugging4.
Featured Content Ads
add advertising hereI’d like to end with a few examples, demonstrating how to extend context-menu-functions
with your own functions:
By default this functionality is bound to M-s h .
, and I find it useful for debugging terse or complicated code. If we want to use the mouse instead, a ...-at-mouse
command can be defined, together with a function placed in context-menu-functions
that adds entries to the menu using define-key-after
:
defun highlight-symbol-at-mouse (e)
("Highlight symbol at mouse click E."
"e")
(interactive
(save-excursion
(mouse-set-point e)
(highlight-symbol-at-point)))
defun context-menu-highlight-symbol (menu click)
("Populate MENU with command to search online."
(save-excursion
(mouse-set-point click)when (symbol-at-point)
(
(define-key-after menu [highlight-search-separator] menu-bar-separator)
(define-key-after menu [highlight-search-mouse]"Highlight Symbol" highlight-symbol-at-mouse
'(menu-item "Highlight symbol at point"))))
:help
menu)
(add-hook 'context-menu-functions #'context-menu-highlight-symbol)
Notice how context-menu-highlight-symbol
only adds highlight-symbol-at-mouse
if symbol-at-point
indicates that there is a symbol that could be highlighted.
A popular feature from other text editors is to easily search for something online. The command mouse-online-search-at-point
implements something like this. As before, the command could be bound directly to some mouse key5, but to add it to the context menu we define another hook function:
require 'eww)
(
defun mouse-online-search-at-point (e)
("Search for word at point or selection."
"e")
(interactive let ((query (if (region-active-p)
(
(buffer-substring (region-beginning)
(region-end))
(save-excursion
(mouse-set-point e)
(thing-at-point 'symbol)))))unless query
("Nothing to search for"))
(user-error
(browse-url (concat
eww-search-prefix"+")))))
(mapconcat #'url-hexify-string (split-string query)
defun context-menu-online-search (menu click)
("Populate MENU with command to search online."
(save-excursion
(mouse-set-point click)
(define-key-after menu [online-search-separator] menu-bar-separator)
(define-key-after menu [online-search-at-mouse]"Online search" mouse-online-search-at-point
'(menu-item "Search for region or word online")))
:help menu)
Modify eww-search-prefix
to use a different search engine.
Another idea is to open man page, when clicking something like emacs(1)
. This uses man.el
(but could just as well use woman.el
) to display the requested page.
defun man-at-mouse (e)
("Open man manual at point."
"e")
(interactive
(save-excursion
(mouse-set-point e)
(man (Man-default-man-entry))))
defun man-context-menu (menu click)
("Populate MENU with commands that open a man page at point."
(save-excursion
(mouse-set-point click)when (save-excursion
("^ ")
(skip-syntax-backward and (looking-at
("[[:space:]]*\([[:alnum:]_-]+([[:alnum:]]+)\)")
1)))
(match-string
(define-key-after menu [man-separator] menu-bar-separator)
(define-key-after menu [man-at-mouse]"Open man page" man-at-mouse
'(menu-item "Open man page around mouse click"))))
:help
menu)
(add-hook 'context-menu-functions #'man-context-menu)
This could be extended to only offer displaying a man page, if it actually exists, and not just if something looks like a man page reference.
Emacs 28 has not yet been released, but pre-releases have been marked. If you want to try out this or other features, download the pre-release or clone the emacs-28
branch of development repository to try it out, and report bugs if you find any!