Elmacro: Write Emacs Lisp snippets even when you aren’t a programmer


Are you an Emacs User who is convinced that you cannot make the most out of the editor because you cannot program in Emacs Lisp?

If yes, you need to hunt down a few secretaries from the 70s who used to work at MIT’s Artifical Intelligence Lab, and apprentice yourself to them. 

Don’t take offense at my remark. 

Instead, listen to what Richard M Stallman, the author of GNU Emacs, has to say about those secretaries …

Multics Emacs proved to be a great success — programming new editing commands was so convenient that even the secretaries in his office started learning how to use it. They used a manual someone had written which showed how to extend Emacs, but didn’t say it was a programming. So the secretaries, who believed they couldn’t do programming, weren’t scared off. They read the manual, discovered they could do useful things and they learned to program.

So Bernie saw that an application — a program that does something useful for you — which has Lisp inside it and which you could extendby rewriting the Lisp programs, is actually a very good way for people to learn programming. It gives them a chance to write small programs that are useful for them, which in most arenas you can’t possibly do. They can get encouragement for their own practical use — at the stage where it’s the hardest — where they don’t believe they canprogram, until they get to the point where they are programmers.

— Richard Stallman, My Lisp Experiences and the Development of GNU Emacs(1)

Yes.  You understood that right. You too can write little Emacs Lisp snippets to tame GNU Emacs to your needs.  And you can accomplish this with the package called elmacro(1, 2).

What is elmacro?

elmacro is a package to

Convert keyboard macros to emacs lisp

The description above not only says what the package does—it outputs Emacs Lisp, but also hints at what it expects of you—a felicity with Keyboard Macros.

The Pre-requisite

In order use elmacro, you should comfortable creating Keyboard Macros.  If you are new to keyboard macros, see my earlier article on this topic.(1)

Purpose of this article

In this article, you will learn how to write Emacs Lisp snippets using elmacro.  Specifically, you will create your own custom Emacs Lisp command that de-clutters your edit-space by removing the Menu Bar  etc .  Put simply, you will learn how to create your own (degenerate version of) writeroom-mode (12) or darkroom-mode (12).

Step 1:  Download and Install elmacro

Download and install the package elmacro(1). This package is available at MELPA,(1) the Milkypostman’s Emacs Lisp Archive. If you are new to installing packages, see my earlier article (1).

Step 2: Create a menu for elmacro

Copy the Emacs Lisp snippet(1)  below to your .emacs and restart your Emacs.

(ignore-errors
  (require 'my-kmacro-menu))

(require 'elmacro)

(with-eval-after-load 'elmacro
  (unless (lookup-key global-map [menu-bar extra-tools])
    (define-key-after global-map
      [menu-bar extra-tools]
      (cons "Extra Tools"
            (easy-menu-create-menu "Extra Tools" nil))
      'tools))
  
  (easy-menu-define my-elmacro-menu nil "Menu for Elmacro."
    '("Elmacro"
      ["Elmacro Mode" (customize-save-variable 'elmacro-mode (not elmacro-mode)) :style toggle :selected elmacro-mode :help "(elmacro-mode &optional ARG)\n\nToggle emacs activity recording (elmacro mode).\nWith a prefix argument ARG, enable elmacro mode if ARG is\npositive, and disable it otherwise. If called from Lisp, enable\nthe mode if ARG is omitted or nil."]
      "--"
      ["Show Last Commands" elmacro-show-last-commands :active elmacro-mode :help "(elmacro-show-last-commands &optional COUNT)\n\nTake the latest COUNT commands and show them as emacs lisp.\n\nThis is basically a better version of `kmacro-edit-lossage'.\n\nThe default number of commands shown is modifiable in variable\n`elmacro-show-last-commands-default'.\n\nYou can also modify this number by using a numeric prefix argument or\nby using the universal argument, in which case it'll ask for how many\nin the minibuffer."]
      ["Show Last Macro" elmacro-show-last-macro :active elmacro-mode :help "(elmacro-show-last-macro NAME)\n\nShow the last macro as emacs lisp with NAME."]
      "--"
      ["Clear Command History" elmacro-clear-command-history :active elmacro-mode :help "(elmacro-clear-command-history)\n\nClear the list of recorded commands."]))

  (easy-menu-add-item
   (current-global-map)
   '("menu-bar" "extra-tools")
   my-elmacro-menu))

(provide 'my-elmacro-menu)

This snippet

  1. loads my-kmacro-menu.  This library makes the Keyboard Macros available through the menu.(1)
  2. adds a sub-menu named Extra Tools to the menu.  To this sub-menu, it adds another sub-menu named Elmacro. Under this sub-menu, you will find all commands that are provided by the Elmacro package.

Step 3: Ensure that you have  Extra Tools -> Elmacro andTools ->Keyboard Macro

Once you restart you Emacs,  your menu-bar should have the following two sub-menus:  (i) Extra Tools -> Elmacro and (ii)  Tools->Keyboard Macro.  See below for a screenshot.  If you aren’t seeing  these, repeat the earlier steps.

Step 4: Turn on elmacro-mode

Screenshot from 2018-11-14 17-16-42

Step 5: Record your Keyboard Macro

As mentioned earlier, you will create a Keyboard Macro that de-clutters your edit-space.

Specifically, you will

  1. Enlarge the Emacs window so that it occupies your entire desktop(M-F10)
  2. Remove the title bar(1, F11)
  3. Remove the tool bar(1)
  4. Remove the vertical scroll bar(1)
  5. Remove the fringe(1)
  6. Remove the Menu Bar(1)

See the GIF below for details.  [CLICK HERE FOR UNSCALED GIF]

As you walk through these steps,  you will realize that more and more edit space becomes available to you.

elmacro-2018-11-14

Step 6: Convert Keyboard Macro to Emacs Lisp

Screenshot from 2018-11-14 17-17-08

Step 7: Clean-up the Emacs Lisp code

Here is the sample Emacs Lisp created by elmacro.

(defun last-macro ()
  (interactive)
  (setq last-command-event 'Start\ Macro)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'Start\ Macro)
  (handle-move-frame
   `(move-frame
     (,(elmacro-get-frame "0xf6fc80"))))
  (setq last-command-event 'Start\ Macro)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'f11)
  (toggle-frame-fullscreen)
  (setq last-command-event 'f11)
  (handle-move-frame
   `(move-frame
     (,(elmacro-get-frame "0xf6fc80"))))
  (setq last-command-event 'f11)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'f11)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'f11)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'f11)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'showhide-tool-bar-none)
  (menu-bar-showhide-tool-bar-menu-customize-disable)
  (setq last-command-event 'showhide-tool-bar-none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'showhide-tool-bar-none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'showhide-tool-bar-none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'showhide-tool-bar-none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (menu-bar-no-scroll-bar)
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (menu-bar-showhide-fringe-menu-customize-disable)
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'none)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'menu-bar-mode)
  (toggle-menu-bar-mode-from-frame 'toggle)
  (setq last-command-event 'menu-bar-mode)
  (handle-focus-in
   `(focus-in ,(elmacro-get-frame "0xf6fc80")))
  (setq last-command-event 'End\ Macro))

As you can see, the bulk of the above snippet handles the mouse events as you click through the various items in the menu.  These are mere noises, and you can remove them.

You see below the same snippet after the clean-up.   I have re-named the  custom command to my-toggle-frame-fullscreen, and added some documentation for future reference.

You can copy this snippet, your own custom command, to your .emacs and invoke it anytime with my-toggle-frame-fullscreen

(defun my-toggle-frame-fullscreen ()
  "Toggle fullscreen state of selected frame.
But do it my way."
  (interactive)
  (toggle-frame-fullscreen)                             ; Toggle Fullscreen
  (menu-bar-showhide-tool-bar-menu-customize-disable)   ; Disable Tool Bar
  (menu-bar-no-scroll-bar)                              ; No Vertical Scroll Bar
  (menu-bar-showhide-fringe-menu-customize-disable)     ; No Fringe
  (toggle-menu-bar-mode-from-frame 'toggle)             ; Toggle Menu Bar
  )

Note: If you take a close look at the transcript generated by elmacro, you will notice the command toggle-frame-maximized (invoked with M-f10) is absent.  This is because the key sequence never reaches Emacs but is hijacked by GNOME Desktop to provide the same functionality.   In the above demonstration, had I used ESC <f10>, instead of M-f10 , the transcript from elmacro would include toggle-frame-maximized.   This oversight on my part is not a serious concern. This is because the immediately following command  toggle-frame-fullscreen  (invoked with F11) does toggle-frame-maximized and much more.

Step 8: Run the Custom Command

You can see how the new  my-toggle-frame-fullscreen works in the GIF below.  [CLICK HERE FOR UNSCALED GIF]

last-macro-2018-11-14

Elmacro can do more

You have seen that  Elmacro can be used to create custom Emacs Lisp snippets.  But it is not the only use for it.  You can use it as an X-Ray tool to probe what the Emacs does under the surface.   Any time you are in Elmacro-mode, you can summon Elmacro to list the last few commands that Emacs executed.  Think of this feature as view-lossage(1)on steroids.  See below for a screenshot.

Screenshot from 2018-11-14 17-17-48

The above feature is particularly useful for newbies who try out various keys (when starting out) and end up with Emacs that is an unusable state (for them).

Concluding Words

As we have seen,Elmacro is a handy tool for writing Emacs Lisp snippets.  The Emacs Lisp snippets may not be immediately usable. It requires some skill to convert the raw Emacs Lisp to a usable Emacs Lisp.

When you are a programmer, that has passing familiarity with Emacs eco-system, the clean-up wouldn’t pose a significant challenge, and you can churn out custom extensions in no time.

When aren’t a programmer, there is an element of challenge involved in cleaning-up the Emacs Lisp snippets generated by this package.  Even if you feel that you aren’t up to the demands of the clean-up task, you can peek at the Emacs Lisp APIs you need to call to accomplish the task at hand.

Whether you are a programmer or not, you need to realize that elmacro has it’s quirks, and find ways of overcoming it.  Despite all this, I assert that elmacro is a must-have tool if you aspire to graduate from being a mere user of Emacs to a builder of Emacs Lisp programs.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close