21

GitHub - alhassy/emacs.d: My Emacs configuration, literately

 4 years ago
source link: https://github.com/alhassy/emacs.d
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

A Life Configuring Emacs

emacs-logo.png

emacs-birthday-present.png

I enjoy reading others’ literate configuration files and incorporating what I learn into my own. The result is a sufficiently well-documented and accessible read that yields a stylish and functional system (•̀ᴗ•́)و

This README.org has been automatically generated from my configuration and its contents below are accessible in (outdated) blog format, with colour, or as colourful PDF, here. Enjoy

Abstract

Herein I document the configurations I utilise with Emacs.

As a literate program file with Org-mode, I am ensured optimal navigation through my ever growing configuration files, ease of usability and reference for peers, and, most importantly, better maintainability for myself!

Dear reader, when encountering a foregin command X I encourage you to execute (describe-symbol 'X), or press C-h o with the cursor on X. An elementary Elisp Cheat Sheet can be found here and here is a 2-page 3-column Emacs Cheat Sheet of the bindings in “this” configuration.

  • C-h oWhat’s this thing?
  • C-h eWhat’d /Emacs/ do?
  • C-h lWhat’d /I/ do?
  • C-h ?What’re the help topics? —gives possible completions to “C-h ⋯”.
  • “I accidentally hit a key, which one and what did it do!?” ⇒ C-h e and C-h l, then use C-h o to get more details on the action. ;-)

Finally, C-h d asks nicely what ‘d’ocumentation you’re interested in. After providing a few keywords, the apropos tool yields possible functions and variables that may accomplish my goal.

Table of Contents

Why Emacs?

Emacs is a flexible platform for developing end-user applications —unfortunately it is generally perceived as merely a text editor. Some people use it specifically for one or two applications.

For example, writers use it as an interface for Org-mode and others use it as an interface for version control with Magit. Org is an organisation tool that can be used for typesetting which subsumes LaTeX, generating many different formats –html, latex, pdf, etc– from a single source, keeping track of schedules & task management, blogging, habit tracking, personal information management tool, and much more. Moreover, its syntax is so natural that most people use it without even knowing! For me, Org allows me to do literate programming: I can program and document at the same time, with no need to seperate the two tasks and with the ability to generate multiple formats and files from a single file.

If you are a professional writer…Emacs outshines all other editing software in approximately the same way that the noonday sun does the stars. It is not just bigger and brighter; it simply makes everything else vanish. —Neal Stephenson, In the beginning was the command line

  • Extensible ⇒ IDEs are generally optimised for one framework, unlike Emacs!
    • You can program Emacs to automate anything you want.
    • Hence, it’s an environment, not just an editor.
    • ⇒ Unified keybinding across all tools in your environment.

    Users are given a high-level full-featured programming language, not just a small configuration language. For the non-programmers, there is Custom, a friendly point-and-click customisation interface.

  • Self Documented ⇒ Simply M-x info-apropos or C-h d to search all manuals or look up any function provided by Emacs!
  • Mature ⇒ tool with over 40 years of user created features
    • Plugins for nearly everything!
    • No distinction between built-ins and user-defined features! (Lisp!)
    • You can alter others’ code without even touching the source.
      • Advising functions and ‘hooking’ functionality onto events.
  • Free software ⇒ It will never die!
    • Emacs is one of the oldest open source projects still under developement.

Of course Emacs comes with the basic features of a text editor, but it is much more; for example, it comes with a powerful notion of ‘undo’: Basic text editors have a single stream of undo, yet in Emacs, we have a tree –when we undo and make new edits, we branch off in our editing stream as if our text was being version controlled as we type! –We can even switch between such branches!

;; Allow tree-semantics for undo operations.
(use-package undo-tree
  :diminish                       ;; Don't show an icon in the modeline
  :config
    ;; Always have it on
    (global-undo-tree-mode)

    ;; Each node in the undo tree should have a timestamp.
    (setq undo-tree-visualizer-timestamps t)

    ;; Show a diff window displaying changes between undo nodes.
    (setq undo-tree-visualizer-diff t))

;; Execute (undo-tree-visualize) then navigate along the tree to witness
;; changes being made to your file live!

( The above snippet has a noweb-ref: It is presented here in a natural position, but is only executable once use-package is setup and so it is weaved there! We can present code in any order and tangle it to the order the compilers need it to be! )

Emacs is an extensible editor: You can make it into the editor of your dreams! You can make it suited to your personal needs. If there’s a feature you would like, a behaviour your desire, you can simply code that into Emacs with a bit of Lisp. As a programming language enthusiast, for me Emacs is my default Lisp interpreter and a customisable IDE that I use for other programming languages –such as C, Haskell, Agda, Lisp, and Prolog. Moreover, being a Lisp interpreter, we can alter the look and feel of Emacs live, without having to restart it –e.g., press C-x C-e after the final parenthesis of (scroll-bar-mode 0) to run the code that removes the scroll-bar.

I use Emacs every day. I rarely notice it. But when I do, it usually brings me joy.Norman Walsh

I have used Emacs as an interface for developing cheat sheets, for making my blog, and as an application for ‘interactively learning C’. If anything Emacs is more like an OS than just a text editor –“living within Emacs” provides an abstraction over whatever operating system my machine has: It’s so easy to take everything with me. Moreover, the desire to mould Emacs to my needs has made me a better programmer: I am now a more literate programmer and, due to Elisp’s documentation-oriented nature, I actually take the time and effort to make meaningful documentation –even when the project is private and will likely only be seen by me.

Seeing Emacs as an editor is like seeing a car as a seating-accommodation.Karl Voit

Emacs is a flexible platform for developing end-user applications

Just as a web browser is utilised as a platform for deploying applications, or ‘extensions’, written in JavaScript that act on HTML documents, Emacs is a platform for deploying applications written in Emacs Lisp that act on buffers of text. In the same vein, people who say Emacs having Tetris is bloat are akin to non-coders who think their browser has bloat since it has a “view page source” feature —which nearly all browsers have, yet it’s only useful to web developers. Unlike a web browser in which the user must get accustomed to its features, Emacs is customised to meet the needs of its user. ( Incidentally, Emacs comes bundled with a web browser. )

In the case of Emacs the boundary between user and programmer is blurred as adapting the environment to one’s needs is already an act of programming with a very low barrier to entry.rekado

  • Don’t just get used to your tool, make it get used to you!

Emacs is not just an editor, but a host for running Lisp applications!

For example, Emacs is shipped as a language-specific IDE to a number of communities —e.g., Oz, Common Lisp, and, most notably, Agda. Emacs is a great IDE for a language —one just needs to provide a ‘major mode’ and will then have syntax highlighting, code compleition, jumping to definitions, etc. There is no need to make an IDE from scratch.

The Power of Text Manipulation

Emacs has ways to represent all kinds of information as text.

E.g., if want to make a regular expression rename of files in a directory, there’s no need to learn about a batch renaming tool: M-x dired <RET> M-x wdired-change-to-wdired-mode now simply perform a usual find-and-replace, then save with the usual C-x C-s to effect the changes!

Likewise for other system utilities and services (•̀ᴗ•́)و

Moreover, as will be shown below, you can literally use Emacs anywhere for textually input in your operating system –no copy-paste required.

Keyboard Navigation and Alteration

Suppose you wrote a paragraph of text, and wanted to ‘border’ it up for emphasies in hypens. Using the mouse to navigate along with a copy-paste of the hypens is vastely inferior to the incantation M-{ C-u 80 - RET M-} C-u 80 - RET. If we want to border up the previous 𝓃-many paragraphs, we simply prefix M-{,} above with C-u 𝓃 —a manual approach would have us count 𝓃 and slowly scroll. ( Exercise: What incantation of keys ‘underlines’ the current line with only the necessary amount of dashes? —Solution in the source file. )

MacOS supports many Emacs shortcuts, system-wide, such as C-a/e, C-d, C-k/y, C-o, C-p/n and even C-t for transposing two characters. ⇐

Emacs Proverbs as Koan

Below is an extract from William Cobb’s “Reflections on the Game of Go”, with minor personalised adjustements for Emacs. Enjoy!

The Japanese term satori refers to the experience of enlightenment, the realisation of how things really are that is the primary aim of practice and meditation. However, the Zen tradition is famous for claiming that one cannot say what it is that one realises, that is, one cannot articulate the content of the enlightenment experience. Although it makes everything clear, it is an experience beyond words. Instead of being given an explanation of how things are, the student of Zen hears sayings called koan, often somewhat paradoxical in character, that come from those who are enlightened:

  • “There are no CTRL and META.”
  • “If you meet an Emacs you dislike, kill it.”
  • “No one knows Emacs.”
  • “One can only learn Emacs by living within it.”
  • “To know Org mode is to know oneself.”

It is important to realise that koan are intended to move you off of one path and onto another. They are not just attempts to mystify you. For example, the first proverb is in regards to newcomers complaining about too many keybinings —eventually it’s muscle memory—, whereas the second is about using the right tool for the right task —Emacs is not for everyone. The fourth is, well, Emacs is an operating system.

Possibly Interesting Reads

—If eye-candy, a sleek and beautiful GUI, would entice you then consider starting with spacemacs. Here’s a helpful installation video, after which you may want to watch Org-mode in Spacemacs tutorial—

Remember: Emacs is a flexible platform for developing end-user applications; e.g., this configuration file is at its core an Emacs Lisp program that yields the editor of my dreams –it encourages me to grow and to be creative, and I hope the same for all who use it; moreover, it reflects my personality such as what I value and what I neglect in my workflow.

I’m stunned that you, as a professional software engineer, would eschew inferior computer languages that hinder your ability to craft code, but you put up with editors that bind your fingers to someone else’s accepted practice. —Howard Abrams

Fun commands to try out

Finally, here’s some fun commands to try out:

  • M-x doctor —generalising the idea of rubber ducks
  • M-x tetris or M-x gomoku or M-x snake—a break with a classic
    • C-u 𝓃 M-x hanoi for the 𝓃-towers of Hanoi
  • M-x butterfly —in reference to “real programmers”

A neat way to get started with Emacs is to solve a problem you have, such as taking notes or maintaining an agenda —both with Org-mode.

Before we get started…

What Does Literate Programming Look Like?

Briefly put, literate programming in Emacs allows us to evaluate source code within our text files, then using the results as values in other source blocks. When presenting an algorithm, we can talk it out, with a full commentary thereby providing ‘reproducible research’: Explorations and resulting algorithms are presented together in a natural style.

images/literate-programming.png

⟨ This image was created in org-mode; details below or by looking at the source file wink

Here’s an example of showing code in a natural style, but having the resulting code appear in a style amicable to a machine. Here’s what you type:

It's natural to decompose large problems,
#+begin_src haskell :noweb-ref defn-of-f :tangle no
f = h ∘ g
#+end_src

But we need to define $g$ and $h$ /beforehand/ before we can use them. Yet it's
natural to “motivate” their definitions ---rather than pull a rabbit out of
hat. Org-let's us do that!

Here's one,
#+begin_src haskell :noweb-ref code-from-other-places :tangle no
g = ⋯
#+end_src

then the other.
#+begin_src haskell :noweb-ref code-from-other-places :tangle no
h = ⋯
#+end_src

Of-course, we might also want a preamble:
#+BEGIN_SRC haskell :tangle myprogram.hs
import ⋯
#+END_SRC

We can now tangle together the tagged code blocks in the order we want.
#+BEGIN_SRC haskell :tangle myprogram.hs :comments none :noweb yes
<<code-from-other-places>>
<<defn-of-f>>
#+END_SRC

Now C-c C-v C-t yields a file named myprogram.hs with contents in an order amicable to a machine.

import ⋯

g = ⋯
h = ⋯
f = h ∘ g

Interestingly, unlike certain languages, Haskell doesn’t care too much about declaration order.

Warning! If we have different language blocks tangled to the same file, then they are tangled alphabetically —e.g., if one of the blocks is marked emacs-lisp then its contents will be the very first one in the resulting source file, since emacs-lisp begins with e which is alphabetically before h of haskell.

Why a monolithic configuration?

Why am I keeping my entire configuration —from those involving cosmetics & prose to those of agendas & programming— in one file? Being monolithic —“a large, mountain-sized, indivisible block of stone”— is generally not ideal in nearly any project: E.g., a book is split into chapters and a piece of software is partitioned into modules. Using Org-mode, we can still partition our setup while remaining in one file. An Emacs configuration is a personal, leisurely project, and one file is a simple architecture: I don’t have to worry about many files and the troubles of moving content between them; instead, I have headings and move content almost instantaneously —org-refile by pressing w at the start of the reader. Moreover, being one file, it is easy to distribute and to extract artefacts from it —such as the README for Github, the HTML for my blog, the colourful PDF rendition, and the all-important Emacs Lisp raw code file. Moreover, with a single # I can quickly comment out whole sections, thereby momentarily disabling features.

There’s no point in being modular if there’s nothing explaining what’s going on, so I document.

The concluding section of this read further argues the benefits of maintaining literate, and monolithic, configuration files. As a convention, I will try to motivate the features I set up and I will prefix my local functions with, well, my/ —this way it’s easy to see all my defined functions, and this way I cannot accidentally shadow existing utilities. Moreover, besides browsing the web, I do nearly everything in Emacs and so the start-up time is unimportant to me: Once begun, I have no intention of spawning another instance nor closing the current one. ( Upon an initial startup using this configuration, it takes a total of 121 seconds to install all the packages featured here. )

Enjoy!

Booting Up

Let’s decide on where we want to setup our declarations for personalising Emacs to our needs. Then, let’s bootstrap Emacs’ primitive packaging mechanism with a slick interface —which not only installs Emacs packages but also programs at the operating system level, all from inside Emacs! Finally, let’s declare who we are and use that to setup Emacs email service.

~/.emacs vs. init.org

Emacs is extenible: When Emacs is started, it tried to load a user’s Lisp program known as a initialisation file which specfies how Emacs should look and behave for you. Emacs looks for the init file using the filenames ~/.emacs.el, ~/.emacs,= or =~/.emacs.d/init.el —it looks for the first one that exists, in that order; at least it does so on my machine. Below we’ll avoid any confusion by ensuring that only one of them is in our system. Regardless, execute C-h o user-init-file to see the name of the init file loaded. Having no init file is tantamount to have an empty init file.

  • One can read about the various Emacs initialisation files online or within Emacs by the sequence C-h i m emacs RET i init file RET.
  • A friendly tutorial on ‘beginning a .emacs file’ can be read online or within Emacs by C-h i m emacs lisp intro RET i .emacs RET.
  • After inserting some lisp code and saving, such as (set-background-color "salmon"), one can load the changes with M-x eval-buffer.
  • In a terminal, use emacs -Q to open emacs without any initialisation files.

Besides writing Lisp in an init file, one may use Emacs’ customisation interface, M-x customize: Point and click to change Emacs to your needs. The resulting customisations are, by default, automatically thrown into your init file —=~/.emacs= is created for you if you have no init file. This interface is great for beginners, but one major drawback is that it’s a bit difficult to share settings since it’s not amicable to copy-pasting.

We shall use ~/.emacs.d/init.el as the initialisation file so that all of our Emacs related files live in the same directory: ~/.emacs.d/.

A raw code file is difficult to maintain, especially for a large system such as Emacs. Instead, we’re going with a ‘literate programming’ approach: The intialisation configuration is presented in an essay format, along with headings and subheadings, intended for consumption by humans such as myself, that, incidentally, can be ‘tangled’ into a raw code file that is comprehensible by a machine. We achieve this goal using org-mode —/Emacs’ killer app/— which is discussed in great detail later on.

Adventure time! “Honey, where’s my init?”

Let’s use the three possible locations for the initialisation files to explore how Emacs finds them. Make the following three files.

~/.emacs.el

;; Emacs looks for this first;
(set-background-color "chocolate3")
(message-box ".emacs.el says hello")

~/.emacs

;; else; looks for this one;
(set-background-color "plum4")
(message-box ".emacs says hello")

~/.emacs.d/init.el

;; Finally, if neither are found; it looks for this one.
(set-background-color "salmon")
(message-box ".emacs.d/init.el says hello")

Now restart your Emacs to see how there super tiny initilaisation files affect your editor. Delete some of these files in-order for others to take effect!

Adventure time! Using Emacs’ Easy Customisation Interface

We have chosen not to keep configurations in ~~/.emacs~ since Emacs may explicitly add, or alter, code in it.

Let’s see this in action!

Execute the following to see additions to the ~~/.emacs~ have been added by ‘custom’.

  1. M-x customize-variable RET line-number-mode RET
  2. Then press: toggle, state, then 1.
  3. Now take a look: C-x C-f ~/.emacs

Support for ‘Custom’

Let the Emacs customisation GUI insert configurations into its own file, not touching or altering my initialisation file. For example, I tend to have local variables to produce README.org’s and other matters, so Emacs’ Custom utility will remember to not prompt me each time for the safety of such local variables.

(setq custom-file "~/.emacs.d/custom.el")
(ignore-errors (load custom-file)) ;; It may not yet exist.

Speaking of local variables, let’s always ones we’ve already marked as safe —see the bottom of the source of this file for an example of local variables. ( At one point, all my files had locals! )

(setq enable-local-variables :safe)

use-package —The start of init.el

There are a few ways to install packages —run C-h C-e for a short overview. The easiest, for a beginner, is to use the command package-list-packages then find the desired package, press i to mark it for installation, then install all marked packages by pressing x.

  • Interactively: M-x list-packages to see all melpa packages that can install
    • Press Enter on a package to see its description.
  • Or more quickly, to install, say, the haskell mode: M-x package-install RET unicode-fonts RET.

“From rags to riches”: Recently I switched to Mac —first time trying the OS. I had to do a few package-install’s and it was annoying. I’m looking for the best way to package my Emacs installation —including my installed packages and configuration— so that I can quickly install it anywhere, say if I go to another machine. It seems use-package allows me to configure and auto install packages. On a new machine, when I clone my .emacs.d and start Emacs, on the first start it should automatically install and compile all of my packages through use-package when it detects they’re missing.

First we load package, the built-in package manager. It is by default only connected to the GNU ELPA (Emacs Lisp Package Archive) repository, so we extended it with other popular repositories; such as the much larger MELPA (Milkypostman’s ELPA) —it builds packages directly from the source-code reposistories of developers, rather than having all packages in one repository.

;; Make all commands of the “package” module present.
(require 'package)

;; Internet repositories for new packages.
(setq package-archives '(("org"       . "http://orgmode.org/elpa/")
                         ("gnu"       . "http://elpa.gnu.org/packages/")
                         ("melpa"     . "http://melpa.org/packages/")))

;; Actually get “package” to work.
(package-initialize)
(package-refresh-contents)
  • All installed packages are placed, by default, in ~/.emacs.d/elpa.
  • Neato: If one module requires others to run, they will be installed automatically.

The declarative configuration tool use-package is a macro/interface that manages other packages and the way they interact.

  • It allows us to tersely organise a package’s configuration.
    • By default, (use-package foo) only loads a package, if it’s on our system.
      • Use the standalone keyword :disabled to turn off loading a module that, say, you’re not using anymore.
  • It is not a package manger, but we can make it one by having it automatically install modules, via Emacs packing mechanism, when they’re not in our system.

    We achieve this by using the keyword option :ensure t.

  • Here are common keywords we will use, in super simplified terms.
    • :init f₁ … fₙ Always executes code forms fᵢ before loading a package.
    • :diminish str Uses optional string str in the modeline to indicate this module is active. Things we use often needn’t take real-estate down there and so no we provide no str.
    • :config f₁ … fₙ Only executes code forms fᵢ after loading a package.

      The remaining keywords only take affect after a module loads.

    • :bind ((k₁ . f₁) … (kₙ . fₙ) Lets us bind keys kᵢ, such as ~”M-s o”~, to functions, such as occur.
      • When n = 1, the extra outer parenthesis are not necessary.
    • :hook ((m₁ … mₙ) . f) Enables functionality f whenever we’re in one of the modes mᵢ, such as org-mode. The . f, along with the outermost parenthesis, is optional and defaults to the name of the package —Warning: Erroneous behaviour happens if the package’s name is not a function provided by the package; a common case is when package’s name does not end in -mode, leading to the invocation ((m₁ … mₙ) . <whatever-the-name-is>-mode) instead.

      Additionally, when n = 1, the extra outer parenthesis are not necessary.

      Outside of use-package, one normally uses a add-hook clause. Likewise, an ‘advice’ can be given to a function to make it behave differently —this is known as ‘decoration’ or an ‘attribute’ in other languages.

    • :custom (k₁ v₁ d₁) … (kₙ vₙ dₙ) Sets a package’s custom variables kᵢ to have values vᵢ, along with optional user documentation dᵢ to explain to yourself, in the future, why you’ve made this decision.

      This is essentially setq within :config.

We now bootstrap use-package.

(unless (package-installed-p 'use-package)
  (package-install 'use-package))
(require 'use-package)

We can now invoke (use-package XYZ :ensure t) which should check for the XYZ package and make sure it is accessible. If not, the :ensure t part tells use-package to download it —using the built-in package manager— and place it somewhere accessible, in ~/.emacs.d/elpa/ by default. By default we would like to download packages, since I do not plan on installing them manually by downloading Lisp files and placing them in the correct places on my system.

(setq use-package-always-ensure t)

The use of :ensure t only installs absent modules, but it does no updating. Let’s set up an auto-update mechanism.

(use-package auto-package-update
  :defer 10
  :config
  ;; Delete residual old versions
  (setq auto-package-update-delete-old-versions t)
  ;; Do not bother me when updates have taken place.
  (setq auto-package-update-hide-results t)
  ;; Update installed packages at startup if there is an update pending.
  (auto-package-update-maybe))

Here’s another example use of use-package. Later on, I have a “show recent files pop-up” command set to C-x C-r; but what if I forget? This mode shows me all key completions when I type C-x, for example. Moreover, I will be shown other commands I did not know about! Neato :-)

;; Making it easier to discover Emacs key presses.
(use-package which-key
  :diminish
  :defer 5
  :config (which-key-mode)
          (which-key-setup-side-window-bottom)
          (setq which-key-idle-delay 0.05))

⟨ Honestly, I seldom even acknowledge this pop-up; but it’s always nice to show to people when I’m promoting Emacs. ⟩

Above, the :diminish keyword indicates that we do not want the mode’s name to be shown to us in the modeline —the area near the bottom of Emacs. It does so by using the diminish package, so let’s install that.

(use-package diminish
  :defer 5
  :config ;; Let's hide some markers.
    (diminish  'org-indent-mode))

Here are other packages that I want to be installed onto my machine.

;; Efficient version control.
;;
;; Bottom of Emacs will show what branch you're on
;; and whether the local file is modified or not.
(use-package magit
  :config (global-set-key (kbd "C-x g") 'magit-status))

(use-package htmlize :defer t)
;; Main use: Org produced htmls are coloured.
;; Can be used to export a file into a coloured html.

;; Get org-headers to look pretty! E.g., * → ⊙, ** ↦ ◯, *** ↦ ★
;; https://github.com/emacsorphanage/org-bullets
(use-package org-bullets
  :hook (org-mode . org-bullets-mode))

;; Haskell's cool
(use-package haskell-mode :defer t)

;; Lisp libraries with Haskell-like naming.
(use-package dash)    ;; “A modern list library for Emacs”
(use-package s   )    ;; “The long lost Emacs string manipulation library”.

;; Library for working with system files;
;; e.g., f-delete, f-mkdir, f-move, f-exists?, f-hidden?
(use-package f)

Note:

  • dash: “A modern list library for Emacs”
    • E.g., (--filter (> it 10) (list 8 9 10 11 12))
  • s: “The long lost Emacs string manipulation library”.
    • E.g., s-trim, s-replace, s-join.

Remember that snippet for undo-tree in the introductory section? Let’s activate it now, after use-package has been setup.

<<undo-tree-setup>>

Finally, let’s try our best to have a useful & consistent commit log:

(defun my/git-commit-reminder ()
  (insert "\n\n# The commit subject line ought to finish the phrase:
# “If applied, this commit will ⟪your subject line here⟫.” ")
  (beginning-of-buffer))

(add-hook 'git-commit-setup-hook 'my/git-commit-reminder)

Super neat stuff!

README —From init.org to init.el

Rather than manually extracting the Lisp code from this literate document each time we alter it, let’s instead add a ‘hook’ —a method that is invoked on a particular event, in this case when we save the file. More precisely, in this case, C-x C-s is a normal save whereas C-u C-x C-s is a save after forming init.elc and README.md.

The my/make-init-el-and-README function

We ‘hook on’ the following function to the usual save method that is associated with this file only.

  (defun my/make-init-el-and-README ()
    "Tangle an el and a github README from my init.org."
    (interactive "P") ;; Places value of universal argument into: current-prefix-arg
    (when current-prefix-arg
      (let* ((time      (current-time))
             (_date     (format-time-string "_%Y-%m-%d"))
             (.emacs    "~/.emacs")
             (.emacs.el "~/.emacs.el"))
        ;; Make README.org
        (save-excursion
          (org-babel-goto-named-src-block "make-readme") ;; See next subsubsection.
          (org-babel-execute-src-block))

        ;; remove any other initialisation file candidates
        (ignore-errors
          (f-move .emacs    (concat .emacs _date))
          (f-move .emacs.el (concat .emacs.el _date)))

        ;; Make init.el
        (org-babel-tangle)
        ;; (byte-compile-file "~/.emacs.d/init.el")
        (load-file "~/.emacs.d/init.el")

        ;; Acknowledgement
        (message "Tangled, compiled, and loaded init.el; and made README.md … %.06f seconds"
                 (float-time (time-since time))))))

(add-hook 'after-save-hook 'my/make-init-el-and-README nil 'local-to-this-file-please)

The Org-block named make-readme

Where the following block has #+NAME: make-readme before it. This source block generates the README for the associated Github repository.

(save-buffer)
(with-temp-buffer
    (insert
    "#+EXPORT_FILE_NAME: README.org

     # Logos and birthday present painting
     #+HTML:" (s-collapse-whitespace (concat
    " <p align=\"center\">
       <img src=\"images/emacs-logo.png\" width=150 height=150/>
     </p>

     <p align=\"center\">
        <a href=\"https://www.gnu.org/software/emacs/\">
             <img src=\"https://img.shields.io/badge/GNU%20Emacs-" emacs-version "-b48ead.svg?style=plastic\"/></a>
        <a href=\"https://orgmode.org/\"><img src=\"https://img.shields.io/badge/org--mode-" org-version "-489a9f.svg?style=plastic\"/></a>
     </p>

     <p align=\"center\">
       <img src=\"images/emacs-birthday-present.png\" width=250 height=250/>
     </p>
    "))

   ;; My Literate Setup; need the empty new lines for the export
   "

     I enjoy reading others' /literate/ configuration files and
     incorporating what I learn into my own. The result is a
     sufficiently well-documented and accessible read that yields
     a stylish and functional system (•̀ᴗ•́)و

     This ~README.org~ has been automatically generated from my
     configuration and its contents below are accessible
     in (outdated) blog format, with /colour/, or as colourful
     PDF, [[https://alhassy.github.io/init/][here]]. Enjoy
     :smile:

     #+INCLUDE: init.org
    ")

    ;; No code execution on export
    ;; ⟪ For a particular block, we use “:eval never-export”. ⟫
    (let ((org-export-use-babel nil))
      (org-mode)
      (org-org-export-to-org)))

Alternatively, evaluate the above source block with C-c C-c to produce a README file.

For the ‘badges’, see https://shields.io/. The syntax above is structured:

https://img.shields.io/badge/<LABEL>-<MESSAGE>-<COLOR>.svg

‘Table of Contents’ for Org vs. Github

The above mentioned package toc-org, which creates an up-to-date table of contents in an org file, at any heading tagged :TOC:. It’s useful primarily for README files on Github. There is also org-make-toc, which is more flexible: The former provides only a top-level TOC; whereas this package allows TOCs at the sibling level, say, to produce a TOC of only the subsections of a particular heading, and other TOC features. Unlike toc-org, org-make-toc uses property drawers to designate TOC matter.

(use-package toc-org
  ;; Automatically update toc when saving an Org file.
  :hook (org-mode . toc-org-mode)
  ;; Use both “:ignore_N:” and ":export_N:” to exlude headings from the TOC.
  :custom (toc-org-noexport-regexp
           "\\(^*+\\)\s+.*:\\(ignore\\|noexport\\)\\([@_][0-9]\\)?:\\($\\|[^ ]*?:$\\)"))

However, toc-org produces broken links for numbered sections. That is, if we use #+OPTIONS: num:t then a section, say ** =~/.emacs= vs. =init.org= as the first subheading of the third heading, then it renders with the text preceeded by 3.1. On the left-most part of the heading, Github provides a a link option; clicking provides a link to this exact location in the README, changing the current URL to something like https://github.com/alhassy/emacs.d#31-emacs-vs-initorg. Now, toc-org produces Github-style anchors from Org headings, but does not account for numbers, and so gives us https://github.com/alhassy/emacs.d#emacs-vs-initorg, which is so close but missing the translated number, 31.

I’ve experimented with using toc-org links using org-style, instead of the default Github style, but it seems that the org-style completely breaks rendering the resulting readme. Likewise, it seems that headings that are links break the TOC link; whence my section on the Reveal slide-deck system has a broken link to it. Perhaps org-make-toc solves these issues —something to look into.

I’m not sure how I feel about actually having the Github-serving TOC in my source file. It’s nice to have around, from an essay-perspecive, but it breaks HTML export since its links are not well-behaved; e.g., :ignore:-ed headlines appear in the toc, but do not link to any visible heading in the HTML; likewise, headings with URLS in their names break. As such, below I’ve developed a way to erase it altogether —alternatively, one could mark the toc as :noexport:, but this would then, in my current approach, not result in a toc in the resulting README.

(cl-defun my/org-replace-tree-contents (heading &key (with "") (offset 0))
  "Replace the contents of org tree HEADING with WITH, starting at OFFSET.

Clear a subtree leaving first 3 lines untouched  ⇐  :offset 3
Deleting a tree & its contents                   ⇐  :offset -1, or any negative number.
Do nothing to a tree of 123456789 lines          ⇐  :offset 123456789

Precondition: offset < most-positive-fixnum; else we wrap to a negative number."
  (interactive)
  (save-excursion
    (beginning-of-buffer)
    (re-search-forward (format "^\\*+ %s" (regexp-quote heading)))
    ;; To avoid ‘forward-line’ from spilling onto other trees.
    (org-narrow-to-subtree)
    (org-mark-subtree)
    ;; The 1+ is to avoid the heading.
    (dotimes (_ (1+ offset)) (forward-line))
    (delete-region (region-beginning) (region-end))
    (insert with)
    (widen)))

;; Erase :TOC: body ---provided we're using toc-org.
;; (my/org-replace-tree-contents "Table of Contents")

Alternate approaches to generating a README

Github supports several markup languages, one of which is Org-mode.

  • It seems that Github uses org-ruby to convert org-mode to html.
  • Here is a repo demonstrating how Github interprets Org-mode files.
  • org-ruby supports inline #+HTML but not html blocks.

It seems coloured HTML does not render well:

(org-html-export-to-html)
(shell-command "mv README.html README.md")

JavaScript supported display of web pages with:

#+INFOJS_OPT: view:info toc:t buttons:t

This looks nice for standalone pages, but doesn’t incorporate nicely with github README.org.

Usually, Github readme files are in markdown, which we may obtain from an Org file with M-x org-md-export-to-markdown.

  • [ ] By default, this approach results in grey-coloured source blocks —eek!
  • [X] It allows strategic placement of a table of contents.

    Declare #+options: toc:nil at the top of the Org file, then have #+TOC: headlines 2 in a strategic position for a table of contents, say after a brief explanation of what the readme is for.

  • [X] It allows us to preview the readme locally before comitting, using grip.
;; grip looks for README.md
(system-packages-ensure "grip")
;; Next: (async-shell-command "cd ~/.emacs.d/; grip")

We can approximate this behaviour for the other approaches:

  1. Export to markdown.
  2. COMMENT-out any :TOC:-tagged sections —their links are not valid markdown links, since they don’t refer to any markdown labels.
  3. Rename the exported file to README.md.
  4. Run grip.

Installing Emacs packages directly from source

Quelpa allows us to build Emacs packages directly from source repositories. It derives its name from the German word Quelle, for souce [code], adjoined to ELPA. Its use-package interface allows us to use use-package like normal but when we want to install a file from souce we use the keyword :quelpa.

(use-package quelpa
  :defer 5
  :custom (quelpa-upgrade-p t "Always try to update packages")
  :config
  ;; Get ‘quelpa-use-package’ via ‘quelpa’
  (quelpa
   '(quelpa-use-package
     :fetcher git
     :url "https://github.com/quelpa/quelpa-use-package.git"))
  (require 'quelpa-use-package))

Let’s use this to obtain an improved info-mode from the EmacsWiki. [Disabled for now]

(use-package info+
  :disabled
  :quelpa (info+ :fetcher wiki :url "https://www.emacswiki.org/emacs/info%2b.el"))

magit —Emacs’ porcelain interface to gitq

Let’s setup an Emacs ‘porcelain’ interface to git —it makes working with version control tremendously convenient. Moreover, I add a little pop-up so that I don’t forget to commit often!

Why use magit as the interface to the git version control system? In magit buffer nearly everything can be acted upon: Press return, or space, to see details and tab to see children items, usually.

First, let’s setup our git credentials.

;; See here for a short & useful tutorial:
;; https://alvinalexander.com/git/git-show-change-username-email-address
(when (equal ""
(shell-command-to-string "git config user.name"))
  (shell-command "git config --global user.name \"Musa Al-hassy\"")
  (shell-command "git config --global user.email \"[email protected]\""))

Below is my personal quick guide to working with magit —for a full tutorial see jr0cket’s blog.

diredSee the contents of a particular directory. magit-initPut a project under version control. The mini-buffer will prompt you for the top level folder version. A .git folder will be created there. magit-status , C-x gSee status in another buffer. Press ? to see options, including: gRefresh the status buffer. TABSee collapsed items, such as what text has been changed. qQuit magit, or go to previous magit screen. sStage, i.e., add, a file to version control. Add all untracked files by selecting the Untracked files title.

The staging area is akin to a pet store; commiting is taking the pet home.

kKill, i.e., delete a file locally. KThis’ (magit-file-untrack) which does git rm --cached. iAdd a file to the project .gitignore file. Nice stuff =) uUnstage a specfif staged change highlighed by cursor. C-u s stages everything –tracked or not. cCommit a change.

  • A new buffer for the commit message appears, you write it then commit with C-c C-c or otherwise cancel with C-c C-k. These commands are mentioned to you in the minibuffer when you go to commit.
  • You can provide a commit to each altered chunk of text! This is super neat, you make a series of local such commits rather than one nebulous global commit for the file. The magit interface makes this far more accessible than a standard terminal approach!
  • You can look at the unstaged changes, select a region, using C-SPC as usual, and commit only that if you want!
  • When looking over a commit, M-p/n to efficiently go to previous or next altered sections.
  • Amend a commit by pressing a on HEAD.

dShow differences, another d or another option.

  • This is magit! Each hunk can be acted upon; e.g., s or c or k ;-)

vRevert a commit. xUndo last commit. Tantamount to git reset HEAD~ when cursor is on most recent commit; otherwise resets to whatever commit is under the cursor. lShow the log, another l for current branch; other options will be displayed.

  • Here space shows details in another buffer while cursour remains in current buffer and, moreover, continuing to press space scrolls through the other buffer! Neato.

PPush. FPull. :Execute a raw git command; e.g., enter whatchanged.

Notice that every time you press one of these commands, a ‘pop-up’ of realted git options appears! Thus not only is there no need to memorise many of them, but this approach makes discovering other commands easier.

Below are the git repos I’d like to clone —along with a function to do so quickly.

(use-package magit
  :defer t
  :custom ;; Do not ask about this variable when cloning.
          (magit-clone-set-remote.pushDefault t))

(cl-defun maybe-clone (remote &optional (local (concat "~/" (file-name-base remote))))
  "Clone a REMOTE repository if the LOCAL directory does not exist.

Yields ‘repo-already-exists’ when no cloning transpires,
otherwise yields ‘cloned-repo’.

LOCAL is optional and defaults to the base name; e.g.,
if REMOTE is https://github.com/X/Y then LOCAL becomes ~/Y."
  (if (file-directory-p local)
      'repo-already-exists
    (async-shell-command (concat "git clone " remote " " local))
    (add-to-list 'magit-repository-directories `(,local   . 0))
    'cloned-repo))

(maybe-clone "https://github.com/alhassy/emacs.d" "~/.emacs.d")
(maybe-clone "https://github.com/alhassy/alhassy.github.io")
(maybe-clone "https://github.com/alhassy/CheatSheet")
(maybe-clone "https://github.com/alhassy/ElispCheatSheet")
(maybe-clone "https://github.com/alhassy/CatsCheatSheet")
(maybe-clone "https://github.com/alhassy/islam")

;; For brevity, many more ‘maybe-clone’ clauses are hidden in the source file.

Let’s always notify ourselves of a file that has uncommited changes —we might have had to step away from the computer and forgotten to commit.

(require 'magit-git)

(defun my/magit-check-file-and-popup ()
  "If the file is version controlled with git
  and has uncommitted changes, open the magit status popup."
  (let ((file (buffer-file-name)))
    (when (and file (magit-anything-modified-p t file))
      (message "This file has uncommited changes!")
      (when nil ;; Became annyoying after some time.
      (split-window-below)
      (other-window 1)
      (magit-status)))))

;; I usually have local variables, so I want the message to show
;; after the locals have been loaded.
(add-hook 'find-file-hook
  '(lambda ()
      (add-hook 'hack-local-variables-hook 'my/magit-check-file-and-popup)))

Finally, one of the main points for using version control is to have access to historic versions of a file. The following utility allows us to M-x git-timemachine on a file and use p/n/g/q to look at previous, next, goto arbitrary historic versions, or quit.

(use-package git-timemachine :defer t)

If we want to roll back to a previous version, we just write-file or C-x C-s as usual! The power of text!

Syncing to the System’s $PATH

For one reason or another, on OS X it seems that an Emacs instance begun from the terminal may not inherit the terminal’s environment variables, thus making it difficult to use utilities like pdflatex when Org-mode attempts to produce a PDF.

(use-package exec-path-from-shell
  :init
  (when (memq window-system '(mac ns x))
    (exec-path-from-shell-initialize)))

See the exec-path-from-shell documentation for setting other environment variables.

Installing OS packages, and automatically keeping my system up to data, from within Emacs

Sometimes Emacs packages depend on existing system binaries, use-package let’s us ensure these exist using the :ensure-system-package keyword extension.

  • This is like :ensure t but operates at the OS level and uses your default OS package manager.

Let’s obtain the extension.

;; Auto installing OS system packages
(use-package use-package-ensure-system-package
  :defer 5
  :config (system-packages-update))

;; Ensure our operating system is always up to date.
;; This is run whenever we open Emacs & so wont take long if we're up to date.
;; It happens in the background ^_^
;;
;; After 5 seconds of being idle, after starting up.

After an update to Mac OS, one may need to restore file system access privileges to Emacs.

Here’s an example use for Emacs packages that require OS packages:

(shell-command-to-string "type rg") ;; ⇒ rg not found
(use-package rg
  :ensure-system-package rg) ;; ⇒ There's a buffer *system-packages*
                             ;;   installing this tool at the OS level!

If you look at the *Messages* buffer, via C-h e, on my machine it says brew install rg: finished —it uses brew which is my OS package manager!

The extension makes use of system-packages; see its documentation to learn more about managing installed OS packages from within Emacs. This is itself a powerful tool, however it’s interface M-x system-packages-install leaves much to be desired —namely, tab-compleition listing all available packages, seeing their descriptions, and visiting their webpages. This is remedied by M-x helm-system-packages then RET to see a system package’s description, or TAB for the other features! This is so cool!

;; An Emacs-based interface to the package manager of your operating system.
(use-package helm-system-packages :defer t)

The Helm counterpart is great for discovarability, whereas the plain system-packages is great for programmability.

It is tedious to arrange my program windows manually, and as such I love tiling window managers, which automatically arrange them. I had been using xmonad until recently when I obtained a Mac machine and now use Amethyst —“Tiling window manager for macOS along the lines of xmonad.”

;; Unlike the Helm variant, we need to specify our OS pacman.
(setq system-packages-package-manager 'brew)
;; Use “brew cask install” instead of “brew install” for installing programs.
(setf (nth 2 (assoc 'brew system-packages-supported-package-managers))
      '(install . "brew cask install"))

;; If the given system package doesn't exist; install it.
(system-packages-ensure "amethyst")

Neato! Now I can live in Emacs even more ^_^

“Being at the Helm” —Completion & Narrowing Framework

Whenever we have a choice to make from a list, Helm provides possible completions and narrows the list of choices as we type. This is extremely helpful for when switching between buffers, C-x b, and discovering & learning about other commands! E.g., press M-x to see recently executed commands and other possible commands! Press M-x and just start typing, methods mentioning what you’ve typed are suddenly listed!

Remembrance comes with time, until then ask Emacs!

Try and be grateful!

(use-package helm
 :diminish
 :init (helm-mode t)
 :bind (("M-x"     . helm-M-x)
        ("C-x C-f" . helm-find-files)
        ("C-x b"   . helm-mini)     ;; See buffers & recent files; more useful.
        ("C-x r b" . helm-filtered-bookmarks)
        ("C-x C-r" . helm-recentf)  ;; Search for recently edited files
        ("C-c i"   . helm-imenu)
        ("C-h a"   . helm-apropos)
        ;; Look at what was cut recently & paste it in.
        ("M-y" . helm-show-kill-ring)

        :map helm-map
        ;; We can list ‘actions’ on the currently selected item by C-z.
        ("C-z" . helm-select-action)
        ;; Let's keep tab-completetion anyhow.
        ("TAB"   . helm-execute-persistent-action)
        ("<tab>" . helm-execute-persistent-action)))

Helm provides generic functions for completions to replace tab-completion in Emacs with no loss of functionality.

  • The execute-extended-command, the default “M-x”, is replaced with helm-M-x which shows possible command completions.

    Likewise with apropos, which is helpful for looking up commands. It shows all meaningful Lisp symbols whose names match a given pattern.

  • The ‘Helm-mini’, C-x b, shows all buffers, recently opened files, bookmarks, and allows us to create new bookmarks and buffers!
  • The ‘Helm-imenu’, C-c i, yields a a menu of all “top-level items” in a file; e.g., functions and constants in source code or headers in an org-mode file.

    ⟳ Nifty way to familarise yourself with a new code base, or one from a while ago.

  • When Helm is active, C-x lists possible course of actions on the currently selected item.

When helm-mode is enabled, even help commands make use of it. E.g., C-h o runs describe-symbol for the symbol at point, and C-h w runs where-is to find the key binding of the symbol at point. Both show a pop-up of other possible commands.

Here’s a nifty tutorial: A package in a league of its own: Helm

Let’s ensure C-x b shows us: Current buffers, recent files, and bookmarks —as well as the ability to create bookmarks, which is via C-x r b manually. For example, I press C-x b then type any string and will have the option of making that a bookmark referring to the current location I’m working in, or jump to it if it’s an existing bookmark, or make a buffer with that name, or find a file with that name.

(setq helm-mini-default-sources '(helm-source-buffers-list
                                    helm-source-recentf
                                    helm-source-bookmarks
                                    helm-source-bookmark-set
                                    helm-source-buffer-not-found))

Incidentally, Helm even provides an interface for the top program via helm-top. It also serves as an interface to popular search engines and over 100 websites such as google, stackoverflow, ctan, and arxiv.

(system-packages-ensure "surfraw")
; ⇒  “M-x helm-surfraw” or “C-x c s”

If we want to perform a google search, with interactive suggestions, then invoke helm-google-suggest —which can be acted for other serves, such as Wikipedia or Youtube by C-z. For more google specific options, there is the google-this package.

Let’s switch to a powerful searching mechanism – helm-swoop. It allows us to not only search the current buffer but also the other buffers and to make live edits by pressing C-c C-e when a search buffer exists. Incidentally, executing C-s on a word, region, will search for that particular word, region; then make changes with C-c C-e and apply them by C-x C-s.

(use-package helm-swoop
  :bind  (("C-s"     . 'helm-swoop)           ;; search current buffer
          ("C-M-s"   . 'helm-multi-swoop-all) ;; Search all buffer
          ;; Go back to last position where ‘helm-swoop’ was called
          ("C-S-s" . 'helm-swoop-back-to-last-point)
          ;; swoop doesn't work with PDFs, use Emacs' default isearch instead.
          :map pdf-view-mode-map
          ("C-s" . isearch-forward))
  :custom (helm-swoop-speed-or-color nil "Give up colour for speed.")
          (helm-swoop-split-with-multiple-windows nil "Do not split window inside the current window."))
  • C-u 𝓃 C-s does a search but showing 𝓃 contextual lines!
  • helm-multi-swoop-all, C-M-s, lets us grep files anywhere!

Finally, note that there is now a M-x helm-info command to show documentation, possibly with examples, of the packages installed. For example, M-x helm-info RET dash RET -parition RET to see how the parition function from the dash library works via examples ;-)

Having a workspace manager in Emacs

I’ve loved using XMonad as a window tiling manager. I’ve enjoyed the ability to segregate my tasks according to what ‘project’ I’m working on; such as research, marking, Emacs play, etc. With perspective, I can do the same thing :-)

That is, I can have a million buffers, but only those that belong to a workspace will be visible when I’m switching between buffers, for example. ( The awesome-tab and centaur-tab, mentioned elsewhere here, can be used to achieve the same thing by ‘grouping buffers together’. )

(use-package perspective
  :defer t
  :config ;; Activate it.
          (persp-mode)
          ;; In the modeline, tell me which workspace I'm in.
          (persp-turn-on-modestring))

All commands are prefixed by C-x x; main commands:

s, n/→, p/←‘S’elect a workspace to go to or create it, or go to ‘n’ext one, or go to ‘p’revious one. cQuery a perspective to kill. rRename a perspective. AAdd buffer to current perspective & remove it from all others.

As always, since we’ve installed which-key, it suffices to press C-x x then look at the resulting menu smiley

Excellent PDF Viewer

Let’s install the pdf-tools library for viewing PDFs in Emacs.

(use-package pdf-tools
  :defer t
  ; :init   (system-packages-ensure "pdf-tools")
  :custom (pdf-tools-handle-upgrades nil)
          (pdf-info-epdfinfo-program "/usr/local/bin/epdfinfo")
  :config (pdf-tools-install))

;; Now PDFs opened in Emacs are in pdfview-mode.

Besides the expected PDF viewing utilities, such as search, annotation, and continuous scrolling; with a simple mouse right-click, we can even select a ‘midnight’ rendering mode which may be easier on the eyes. For more, see the brief pdf-tools-tourdeforce demo.

Who am I? —Using Gnus for Gmail

Let’s set the following personal Emacs-wide variables —to be used in other locations besides email.

(setq user-full-name    "Musa Al-hassy"
      user-mail-address "[email protected]")

For some fun, run this cute method.

(animate-birthday-present user-full-name)

By default, in Emacs, we may send mail: Write it in Emacs with C-x m, then press C-c C-c to have it sent via your OS’s default mailing system —mine appears to be Gmail via the browser. Or cancel sending mail with C-c C-k —the same commands for org-capturing, discussed below (•̀ᴗ•́)و

To send and read email in Emacs we use GNUS, which, like GNU itself, is a recursive acronym: GNUS Network User Service.

  1. Execute, rather place in your init:
    (setq message-send-mail-function 'smtpmail-send-it)
        

    Revert to the default OS mailing method by setting this variable to mailclient-send-it.

  2. Follow only the quickstart here; namely, make a file named ~~/.gnus~ containing:
         ;; user-full-name and user-mail-address should be defined
    
    (setq gnus-select-method
          '(nnimap "gmail"
                   (nnimap-address "imap.gmail.com")
                   (nnimap-server-port "imaps")
                   (nnimap-stream ssl)))
    
    (setq smtpmail-smtp-server "smtp.gmail.com"
          smtpmail-smtp-service 587
          gnus-ignored-newsgroups "^to\\.\\|^[0-9. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")
        
  3. Enable “2 step authentication” for Gmail following these instructions.
  4. You will then obtain a secret password, the x marks below, which you insert in a file named ~~/.authinfo~ as follows —using your email address.
    machine imap.gmail.com login [email protected] password xxxxxxxxxxxxxxxx port imaps
    machine smtp.gmail.com login [email protected] password xxxxxxxxxxxxxxxx port 587
        
  5. In Emacs, M-x gnus to see what’s there.

    Or compose mail with C-x m then send it with C-c C-c.

    • Press C-h m to learn more about message mode for mail composition; or read the Message Manual.
;; After startup, if Emacs is idle for 10 seconds, then start Gnus.
;; Gnus is slow upon startup since it fetches all mails upon startup.
(run-with-idle-timer 10 nil #'gnus)

Learn more by reading The Gnus Newsreader Manual; also available within Emacs by C-h i m gnus (•̀ᴗ•́)و

EmacsWiki has a less technical and more user friendly tutorial.

Prettifications

Let’s add the icon  near my mail groups ^_^

;; Fancy icons for Emacs
;; Only do this once:
(use-package all-the-icons :defer t)
  ; :config (all-the-icons-install-fonts 'install-without-asking)

;; Make mail look pretty
(use-package all-the-icons-gnus
  :defer t
  :config (all-the-icons-gnus-setup))

;; While we're at it: Make dired, ‘dir’ectory ‘ed’itor, look pretty
(use-package all-the-icons-dired
  :hook (dired-mode . all-the-icons-dired-mode))

Next, let’s paste in some eye-candy for Gnus:

(setq gnus-sum-thread-tree-vertical        "│"
      gnus-sum-thread-tree-leaf-with-other "├─► "
      gnus-sum-thread-tree-single-leaf     "╰─► "
      gnus-summary-line-format
      (concat
       "%0{%U%R%z%}"
       "%3{│%}" "%1{%d%}" "%3{│%}"
       "  "
       "%4{%-20,20f%}"
       "  "
       "%3{│%}"
       " "
       "%1{%B%}"
       "%s\n"))

Super Terse Tutorial

⟨ See the GNUS Reference Card! ⟩

In gnus, by default items you’ve looked at disappear —i.e., are archived. They can still be viewed in, say, your online browser if you like. In the Group view, R resets gnus, possibly retriving mail or alterations from other mail clients. q exits gnus in Group mode, q exits the particular view to go back to summary mode. Only after pressing q from within a group do changes take effect on articles —such as moves, reads, deletes, etc.

  • Expected keys: RET enter/open an item, q quit and return to previous view, g refresh view —i.e., ‘g’et new articles.
  • RET: Enter a group by pressing, well, the enter key.
    • Use SPC to open a group and automatically one first article there.
    • Use C-u RET to see all mail in a folder instead of just unread mail.
  • Only groups/folders with unread mail will be shown, use L/l to toggle between listing all groups.
  • SPC, DEL to scroll forward and backward; or C-v, M-v as always.
  • G G: Search mail at server side in the group buffer.
    • Limit search to particular folders/groups by marking them with #, or unmarking them with M-#.
  • / /,a: Filter mail according to subject or author; there are many other options, see §3.8 Limiting.
  • d: Mark an article as done, i.e., read it and it can be archived.
  • !: Mark an article as read, but to be kept around —e.g., you have not replied to it, or it requires more reading at a later time.

    This lets us read mail offline; cached mail is found at ~/News/cache/.

    (setq gnus-use-cache 'use-as-much-cache-as-possible)
        
  • B m: Move an article, in its current state, to another group —i.e., ‘label’ using Gmail parlance.
    • Something to consider doing when finished with an article.

    To delete an article, simply move it to ‘trash’ —of course this will delete it in other mail clients as well. There is no return from trash.

    Emails can always be archieved —never delete, maybe?

    Anyhow, B m Trash is too verbose, let’s just use t for “trash”:

    (with-eval-after-load 'gnus
      (bind-key "t"
              (lambda (N) (interactive "P") (gnus-summary-move-article N "[Gmail]/Trash"))
              gnus-summary-mode-map))
    
    ;; Orginally: t ⇒ gnus-summary-toggle-header
        
    • Select and deselect many articles before moving them by pressing # and M-#, respectively, anywhere on the entry.
    • As usual, you can mark a region, C-SPC, then move all entries therein.
  • R, r: Reply with sender’s quoted text in place, or without but still visible in an adjacent buffer.
    • Likewise S W or S w to reply all, ‘wide reply’, with or without quoted text.
    • C-c C-z Delete everything from current position till the end.
    • C-c C-e Replace selected region with ‘[…]’; when omitting parts of quoted text.
  • Press m to compose mail; or C-x m from anywhere in Emacs to do so.
    • C-c C-c to send the mail.
    • S D e to resend an article as new mail: Alter body, subject, etc, before
    • C-c C-f to forward mail. sending.
  • C-c C-a to attach a file; it’ll be embedded in the mail body as plaintext.
    • Press o on an attachment to save it locally.

Capturing Mail as Todo/Notes

Sometime mail contains useful reference material or may be a self-contained task. Rather than using our inbox as a todo-list, we can copy the content of the mail and store it away in our todos/notes files. Capturing, below, is a way to, well, capture ideas and notes without interrupting the current workflow. Below, in the section on capturing, we define my/org-capture-buffer which quickly captures the contents of the current buffer as notes to store away. We use that method in the article view of mail so that c captures mail content with the option to provide additional remarks, and C to silently do so without additional remarks.

(with-eval-after-load 'gnus

(bind-key "c" #'my/org-capture-buffer gnus-article-mode-map)
;; Orginally: c ⇒ gnus-summary-catchup-and-exit

(bind-key "C"
          (lambda (&optional keys)
            (interactive "P") (my/org-capture-buffer keys 'no-additional-remarks))
          gnus-article-mode-map))
;; Orginally: C ⇒ gnus-summary-cancel-article

Gnus’ default c only enables a bad habit: Subscribing to stuff that you don’t read, since you can mark all entries as read with one key. We now replace it with a ‘c’apturing mechanism that captures the current message as a todo or note for further processing. Likewise, the default C is to cancel posting an article; we replace it to be a silent capture: Squirrel away informative mail content without adding additional remarks.

Auto-completing mail addresses

In order to get going quickly, using gmail2bbdb, let’s convert our Gmail contacts into a BBDB file —the Insidious Big Brother Database is an address-book application that we’ll use for E-mail; if you want to use it as a address-book application to keep track of contacts, notes, their organisation, etc, then consider additionally installing helm-bbdb which gives a nice menu interface.

  • From the Gmail Contacts page, obtain a contacts.vcf file by clicking “More -> Export -> vCard format -> Export”.
  • Run command M-x gmail2bbdb-import-file and select contacts.vcf; a bbdb file will be created in my Dropbox folder.
  • Press C-x m then begin typing a contact’s name and you’ll be queried about setting up BBDB, say yes.
(use-package gmail2bbdb
  :defer t
  :custom (gmail2bbdb-bbdb-file "~/Dropbox/bbdb"))

(use-package bbdb
 :after company ;; The “com”plete “any”thig mode is set below in §Prose
 :hook   (message-mode . bbdb-insinuate-gnus)
         (gnus-startup-hook . bbdb-insinuate-gnus)
 :custom (bbdb-file gmail2bbdb-bbdb-file)
         (bbdb-use-pop-up t)                        ;; allow popups for addresses
 :config (add-to-list 'company-backends 'company-bbdb))

Here is an emacs-fu article on managing e-mail addressed with bbdb.

Feeds to Blogs

One can easily subscribe to an RSS feed in Gnus: Just press G R in the group buffer view, then follow the prompts. However, doing so programmatically is much harder. Below is my heartfelt attempt at doing so —if you want a feed reader in Emacs that “just works”, then elfeed is the way to go. When all is said and done, the code below had me reading Gnus implementations and led me to conclude that Gnus has a great key-based interface but a /poor programming interface —or maybe I need to actually read the manual instead of frantically consulting source code.

My homemade hack to getting tagged feeds programmatically into Gnus.

;; Always show Gnus items organised by topic.
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;; From Group view, press ^, then SPC on Gwene, then look for the site you want to follow.
;; If it's not there, add it via the web interface http://gwene.org/
(add-to-list 'gnus-secondary-select-methods '(nntp "news.gwene.org"))
;;
;; E.g., http://nullprogram.com/feed/ uses an Atom feed which Gnus does not
;; support natively.  But it can be found on Gwene.

(setq my/gnus-feeds
      ;; topic  title  url
      '(Emacs "C‘est La 𝒵" https://cestlaz.github.io/rss.xml
        Emacs "Marcin Borkowski's Blog" http://mbork.pl?action=rss
        Emacs "Howardism" http://www.howardism.org/rss.xml
        Islam "Shia Islam Blogspot" http://welcometoshiaislam.blogspot.com/feeds/posts/default?alt=rss
        Cats "Hedonistic Learning" http://www.hedonisticlearning.com/rss.xml
        Cats "Functorial Blog"  https://blog.functorial.com/feed.rss
        Programming "Joel on Software" http://www.joelonsoftware.com/rss.xml
        Haskell "Lysxia's Blog"  https://blog.poisson.chat/rss.xml))

;; If fubared, then:
;; (ignore-errors (f-delete "~/News/" 'force) (f-delete "~/.newsrc.eld"))

;; Execute this after a Gnus buffer has been opened.
(progn
(use-package with-simulated-input)
(loop for (topic title url)
      in (-partition 3 my/gnus-feeds)
      ;; url & topic are symbols, make them strings.
      for url′   = (symbol-name url)
      for topic′ = (symbol-name topic)
      ;; Avoid spacing issues by using a Unicode ghost space “ ”.
      for title′ = (gnus-newsgroup-savable-name (s-replace " " " " title))
      for input  = (format "C-SPC C-a %s RET RET" title′)
      do
      ; cl-letf* (((symbol-function 'insert) (lambda (x) nil))) ;; see the (undo) below.
      ;; Add the group
      (with-simulated-input input
        (gnus-group-make-rss-group url′))
      ;; Ensure it lives in the right topic category.
      (if (equal 'no-such-topic (alist-get topic gnus-topic-alist 'no-such-topic nil #'string=))
        (push (list topic′ title′) gnus-topic-alist) ;; make topic if it doesnt exist
      (setf (alist-get topic′ gnus-topic-alist 'no-such-topic nil #'string=)
            (cons title′ (alist-get topic gnus-topic-alist 'no-such-topic nil #'string=)))))
      ;; Acknowledgement
      (message "Now switch into the GNUS group buffer, and refresh the topics; i.e., t t."))

      ;; The previous command performs an insert, since it's intended to be interactively
      ;; used; let's undo the insert.
      ; (undo-only)

;; (setq gnus-permanently-visible-groups ".*")
;;
;; Show topic alphabetically? The topics list is rendered in reverse order.
;; (reverse (cl-sort gnus-topic-alist 'string-lessp :key 'car))

Ironically, I’ve decide that “no, I do not want to see my blogs in Emacs” for the same reasons I do not activelly use M-x eww to browse the web in Emacs: I like seeing the colours, fonts, and math symbols that the authours have labored over to producing quality content. Apparently, I’m shallow and I’m okay with it —but not that shallow, since I’m constantly pushing Emacs which looks ugly by default but it’s unreasonably powerful.

Jumping to extreme semantic units

Sometimes it’s unreasonable for M-< to take us to the actual start of a buffer; instead it’d be preferable to go to the first “semantic unit” in the buffer. For example, when directory editing with dired we should jump to the first file, with version control with magit we should jump to the first section, when composing mail we should jump to the first body line, and in the agenda we should jump to the first entry.

;; M-< and M-> jump to first and final semantic units.
;; If pressed twice, they go to physical first and last positions.
(use-package beginend
  :diminish 'beginend-global-mode
  :config (beginend-global-mode)
    (loop for (_ . m) in beginend-modes do (diminish m)))

Hydra: Supply a prefix only once

Sometimes we have keybindings that share a common prefix, say C-c j and C-c k, and we invoke them in an arbitrary sequence, it would be nice to invoke the shared prefix only once thereby having:

C-c j C-c j C-c k C-c k M-3 C-c j M-5 C-c kC-c jjkk3j5k
  • The “hydra-zoom” example from the documentation really showcases this utility.
  • After the prefix is supplied, all extensions are shown in a minibuffer.
;; Invoke all possible key extensions having a common prefix by
;; supplying the prefix only once.
(use-package hydra)

;; The standard syntax:
;; (defhydra hydra-example (global-map "C-c v") ;; Prefix
;;   ;; List of triples (extension method description) )

images/hydra.png

From the Hydra repository is a ‘description for poets’:

Once you summon the Hydra through the prefixed binding (the body + any one head), all heads can be called in succession with only a short extension.

The Hydra is vanquished once Hercules, any binding that isn’t the Hydra’s head, arrives. Note that Hercules, besides vanquishing the Hydra, will still serve his original purpose, calling his proper command. This makes the Hydra very seamless, it’s like a minor mode that disables itself auto-magically.

⇒ The Hydra Wiki has many example hydras for common uses cases ⇐

Below are two examples; one to simplify textual navigation and another for window navigation. Yet another possible hydra would be to avoid remembering word operations, such as copying a word, upcasing it, killing a word from anywhere within it —in contrast kill-word kills to the end of the word—, etc. Likewise for line operations, such as copying a line from anywhere in it. See Taking a tour of one’s edits below for another small and useful example.

When there are multiple actions, it’s nice to see such a menu displayed in the middle of the frame; so we use hydra-posframe. Moreover, it can be useful to group related actions under a common heading —e.g., textual navigation may occur at the line level or word level or screen level— we obtain a nice interface by declaraing hydras using pretty-hydra-define —this saves us the trouble of formating docstrings using classic hydra.

;; Show hydras overlyaed in the middle of the frame
(use-package hydra-posframe
  :quelpa (hydra-posframe :fetcher git :url
                          "https://github.com/Ladicle/hydra-posframe.git")
  :hook (after-init . hydra-posframe-mode)
  :custom (hydra-posframe-border-width 5))

;; Neato doc strings for hydras
(use-package pretty-hydra)

Declaration template:

(pretty-hydra-define 𝓃𝒶𝓂ℯ (:title ⋯ :quit-key ⋯)
  (title₀
   (⋯(key₀ᵢ command₀ᵢ optional-doc₀ᵢ)⋯)
   ⋮
   titleₙ
   (⋯(keyₙᵢ commandₙᵢ optional-docₙᵢ)⋯)))

Textual Navigation —“Look Ma, no CTRL key!”

Basic movement commands —without having to hold the control key!

C-n moves us to the next line, as it should; but it now also let’s us press n,p,f,… for other movement commands. Unlisted keys insert themselves, whereas q close the pop-up menu.

(global-set-key
 (kbd "C-n")
 (pretty-hydra-define hydra-move
   (:body-pre (next-line) :title "\t\t\t\t\tTextual Navigation" :quit-key "q")
   ("Line"
    (("n" next-line)
     ("p" previous-line)
     ("a" beginning-of-line)
     ("e" move-end-of-line)
     ("g" goto-line))

   "Word"
   (("f" forward-word "Next")
    ("b" backward-word "Previous")
    ("{" org-backward-element "Next Element")
    ("}" org-forward-element "Previous Element"))

   "Screen"
   (("v" scroll-up-command "Scroll Down")
    ("V" scroll-down-command "Scroll Up")
    ("l" recenter-top-bottom "Center Page")
    ("r" move-to-window-line-top-bottom "Relocate Point")
    ("m" helm-imenu "Textual Menu")))))

Window Navigation

It can be difficult to remember the incantations to adjust windows, so we can make a hydra to alleviate the trouble.

;; Use ijkl to denote ↑←↓→ arrows.
(defhydra hydra-windows (global-map    "C-c w"   )
  ("b" balance-windows                 "balance" )
  ("i" enlarge-window                  "heighten")
  ("j" shrink-window-horizontally      "narrow"  )
  ("k" shrink-window                   "lower"   )
  ("l" enlarge-window-horizontally     "widen"   )
  ("s" switch-window-then-swap-buffer  "swap" :color teal))

;; Provides a *visual* way to choose a window to switch to.
(use-package switch-window :defer t)
;; :bind (("C-x o" . switch-window)
;;        ("C-x w" . switch-window-then-swap-buffer))

;; Have a thick ruler between vertical windows
(window-divider-mode)

Quickly pop-up a terminal, run a command, close it —and zsh

Pop up a terminal, do some work, then close it using the same command.

Shell-pop uses only one key action to work: If the buffer exists, and we’re in it, then hide it; else jump to it; otherwise create it if it doesn’t exit. Use universal arguments, e.g., C-u 5 C-t, to have multiple shells and the same universal arguments to pop those shells up, but C-t to pop them away.

(use-package shell-pop
  :defer t
  :custom
    ;; This binding toggles popping up a shell, or moving cursour to the shell pop-up.
    (shell-pop-universal-key "C-t")

    ;; Percentage for shell-buffer window size.
    (shell-pop-window-size 30)

    ;; Position of the popped buffer: top, bottom, left, right, full.
    (shell-pop-window-position "bottom")

    ;; Please use an awesome shell.
    (shell-pop-term-shell "/bin/zsh"))

Now that we have access to quick pop-up for a shell, let’s get a pretty and practical shell: zsh along with the Oh My Zsh community configurations give us:

  1. brew install zsh
  2. ~sh -c “$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)”~

    This installs everything ^_^

;; Be default, Emacs please use zsh
;; E.g., M-x shell
(setq shell-file-name "/bin/zsh")

Out of the box, zsh comes with

  • git support; the left side indicates which branch we’re on and whether the repo is dirty, ✗.
  • Recursive path expansion; e.g., /u/lo/b TAB expands to /usr/local/bin/
  • Over 250+ Plugins and 125+ Themes that are enabled by simply mentioning their name in the .zshrc file.

The defaults have been good enough for me, for now —as all else is achieved via Emacs ;-)

Also, there’s tldr tool which aims to be like terse manuals for commandline-tools in the style of practical example uses cases: tldr 𝒳 yields a number of ways you’d actually use 𝒳.

(system-packages-ensure "tldr")

Restarting Emacs —Keeping buffers open across sessions?

Sometimes I wish to close then reopen Emacs; unsurprisingly someone’s thought of implementing that.

;; Provides only the command “restart-emacs”.
(use-package restart-emacs
  :defer t
  ;; Let's define an alias so there's no need to remember the order.
  :config (defalias 'emacs-restart #'restart-emacs))

The following is disabled. I found it a nuisance to have my files open across sessions —If I’m closing Emacs, it’s for a good reason.

;; Keep open files open across sessions.
(desktop-save-mode 1)
(setq desktop-restore-eager 10)

Instead, let’s try the following: When you visit a file, point goes to the last place where it was when you previously visited the same file.

(setq-default save-place  t)
(setq save-place-file "~/.emacs.d/etc/saveplace")

Automatic Backups

By default, Emacs saves backup files —those ending in ~— in the current directory, thereby cluttering it up. Let’s place them in ~~/.emacs.d/backups~, in case we need to look for a backup; moreover, let’s keep old versions since there’s disk space to go around —what am I going to do with 500gigs when nearly all my ‘software’ is textfiles interpreted within Emacs smirk_cat

;; New location for backups.
(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))

;; Silently delete execess backup versions
(setq delete-old-versions t)

;; Only keep the last 1000 backups of a file.
(setq kept-old-versions 1000)

;; Even version controlled files get to be backed up.
(setq vc-make-backup-files t)

;; Use version numbers for backup files.
(setq version-control t)

Why backups? Sometimes I may forget to submit a file, or edit, to my version control system, and it’d be nice to be able to see a local automatic backup. Whenever ‘I need space,’ then I simply empty the backup directory, if ever. That the backups are numbered is so sweet ^_^

Like package installations, my backups are not kept in any version control system, like git; only locally.

Let’s use an elementary diff system for backups.

(use-package backup-walker
  :commands backup-walker-start)

In a buffer that corresponds to a file, invoke backup-walker-start to see a visual diff of changes between versions. By default, you see the changes ‘backwards’: Red means delete these things to get to the older version; i.e., the red ‘-’ are newer items.

Emacs only makes a backup the very first time a buffer is saved; I’d prefer Emacs makes backups everytime I save! —If I saved, that means I’m at an important checkpoint, so please check what I have so far as a backup!

;; Make Emacs backup everytime I save

(defun my/force-backup-of-buffer ()
  "Lie to Emacs, telling it the curent buffer has yet to be backed up."
  (setq buffer-backed-up nil))

(add-hook 'before-save-hook  'my/force-backup-of-buffer)

It is intestesting to note that the above snippet could be modified to make our own backup system, were Emacs lacked one, by having our function simply save copies of our file —on each save— where the filename is augmented with a timestamp.

  • diff-backup compares a file with its backup or vice versa.

Screencapturing the Current Emacs Frame

Sometimes an image can be tremendously convincing, or at least sufficiently inviting. The following incantation is written for MacOS and uses it’s native screencapture utility, as well as magick.

(defun my/capture-emacs-frame (&optional prefix output)
"Insert a link to a screenshot of the current Emacs frame.

Unless the name of the OUTPUT file is provided, read it from the
user. If PREFIX is provided, let the user select a portion of the screen."
(interactive "p")
(defvar my/emacs-window-id
   (s-collapse-whitespace (shell-command-to-string "osascript -e 'tell app \"Emacs\" to id of window 1'"))
   "The window ID of the current Emacs frame.

    Takes a second to compute, whence a defvar.")

(let* ((screen  (if prefix "-i" (concat "-l" my/emacs-window-id)))
       (temp    (format "emacs_temp_%s.png" (random)))
       (default (format-time-string "emacs-%m-%d-%Y-%H:%M:%S.png")))
;; Get output file name
  (unless output
    (setq output (read-string (format "Emacs screenshot filename (%s): " default)))
    (when (s-blank-p output) (setq output default)))
;; Clear minibuffer before capturing screen or prompt user
(message (if prefix "Please select region for capture …" "♥‿♥"))
;; Capture current screen and resize
(thread-first
    (format "screencapture -T 2 %s %s" screen temp)
    (concat "; magick convert -resize 60% " temp " " output)
    (shell-command))
(f-delete temp)
;; Insert a link to the image and reload inline images.
(insert (concat "[[file:" output "]]")))
(org-display-inline-images nil t))

(bind-key* "C-c M-s" #'my/capture-emacs-frame)

Why this way? On MacOS, ImageMagick’s import doesn’t seem to work —not at all for me! Also, I dislike how large the resulting image is. As such, I’m using MacOS’s screencapture utility, which in-turn requires me to somehow obtain frame IDs. Hence, the amount of work needed to make this happen on my system was most simple if I just wrote it out myself rather than tweaking an existing system.

  • C-c C-x C-v ⇒ Toggle inline images!

Editor Documentation with Contextual Information

Emacs is an extensible self-documenting editor!

Let’s use a helpful Emacs documentation system that cleanly shows a lot of contextual information —then let’s extend that to work as we want it to: C-h o to describe the symbol at point.

(use-package helpful :defer t)

(defun my/describe-symbol (symbol)
  "A “C-h o” replacement using “helpful”:
   If there's a thing at point, offer that as default search item.

   If a prefix is provided, i.e., “C-u C-h o” then the built-in
   “describe-symbol” command is used.

   ⇨ Pretty docstrings, with links and highlighting.
   ⇨ Source code of symbol.
   ⇨ Callers of function symbol.
   ⇨ Key bindings for function symbol.
   ⇨ Aliases.
   ⇨ Options to enable tracing, dissable, and forget/unbind the symbol!
  "
  (interactive "p")
  (let* ((thing (symbol-at-point))
         (val (completing-read
               (format "Describe symbol (default %s): " thing)
               (vconcat (list thing) obarray)
               (lambda (vv)
                 (cl-some (lambda (x) (funcall (nth 1 x) vv))
                          describe-symbol-backends))
               t nil nil))
         (it (intern val)))
    (cond
     (current-prefix-arg (funcall #'describe-symbol it))
     ((or (functionp it) (macrop it) (commandp it)) (helpful-callable it))
     (t (helpful-symbol it)))))

;; Keybindings.
(global-set-key (kbd "C-h o") #'my/describe-symbol)
(global-set-key (kbd "C-h k") #'helpful-key)

I like helpful and wanted it to have the same behaviour as C-h o, which helpful-at-point does not achieve. The incantation above makes C-h o use helpful in that if the cursor is on a symbol, then it is offered to the user as a default search item for help, otherwise a plain search box for help appears. Using a universal argument lets us drop to the built-in help command.

Cosmetics

Upon startup, we want to be greeted with a useful, yet unobtrusive, message briefly detailing major system details. Moreover, the bottom-most area of the screen should display batter life, data, & time. Likewise, we may have a casual file explorer —primarily to show-off to newcomers, since great functionality is found with M-x dired.

Startup message: Emacs & Org versions

Let’s always welcome ourselves when Emacs begins with a helpful message. For example, which user account is running and what are the version numbers of our primary tools.

;; Silence the usual message: Get more info using the about page via C-h C-a.
(setq inhibit-startup-message t)

(defun display-startup-echo-area-message ()
  "The message that is shown after ‘user-init-file’ is loaded."
  (message
      (concat "Welcome "      user-full-name
              "! Emacs "      emacs-version
              "; Org-mode "   org-version
              "; System "     (symbol-name system-type)
              "/"             (system-name)
              "; Time "       (emacs-init-time))))

Now my startup message is,

;; Welcome Musa Al-hassy! Emacs 26.1; Org-mode 9.3; System alhassy-air.local

Let’s change the Emacs frame to mention the name of the buffer in focus, as well as a nice ‘motto’:

;; Keep self motivated!
(setq frame-title-format '("" "%b - Living The Dream (•̀ᴗ•́)و"))

My to-do list: The initial buffer when Emacs opens up

I almost always have Emacs open; I don’t need a dashboard, but would like to see my to-do list and my init file, side-by-side.

(find-file "~/Dropbox/todo.org")
(split-window-right)			  ;; C-x 3
(other-window 1)                              ;; C-x 0
(let ((enable-local-variables :all)           ;; Load *all* locals.
      (org-confirm-babel-evaluate nil))       ;; Eval *all* blocks.
  (find-file "~/.emacs.d/init.org"))

There is the neat-looking emacs-dashboard package that provides an extensbile yet minimalist splash screen showing recent files, projects, and bookmarks.

Exquisite Themes

Emacs’ default theme leaves much to be desired: It does not look sleek and shiny, which usually leaves first-timers with a poor, shallow, impression of the system.

Below we install a few themes that make Emacs look exquisite. We cycle between the chosen themes with C-x t.

  • M-x load-theme RET TAB shows all themes, including built-in ones, that may be loaded.
  • Loading multiple themes results in their pallets mixed.
    • M-x disable-theme to remove a theme from the current pallet.
;; Treat all themes as safe; no query before use.
(setf custom-safe-themes t)

;; Nice looking themes ^_^
(use-package solarized-theme :defer t)
(use-package doom-themes :defer t)
(use-package spacemacs-common
  :defer t
  :ensure spacemacs-theme)
  • The Doom Themes also look rather appealing.
  • A showcase of many themes can be found here.
;; Infinite list of my commonly used themes.
(setq my/themes '(doom-solarized-light doom-vibrant spacemacs-light))
(setcdr (last my/themes) my/themes)

“C-x t” to toggle between the personal themes.

(cl-defun my/disable-all-themes (&key (new-theme (pop my/themes)))
  "Disable all themes and load NEW-THEME, which defaults from ‘my/themes’."
  (interactive)
  (dolist (τ custom-enabled-themes)
    (disable-theme τ))
  (when new-theme (load-theme new-theme)))

(defalias 'my/toggle-theme #' my/disable-all-themes)
(global-set-key "\C-x\ t" 'my/toggle-theme)
(my/toggle-theme)

Apparently, there’s already a package that accomplishes these goals and more: theme-looper. I may switch to it, but for now my simple function above is slightly informative, to me at least, about how themes work and it does what I want.

A sleek & informative mode line

The ‘modeline’ is a part near the bottom of Emacs that gives information about the current mode, as well as other matters —such as time & date, for example.

Let’s have it also show remaining battery life, coloured green if charging and coloured yellow otherwise. It is important to note that this package is no longer maintained. It works on my machine.

(setq display-time-day-and-date t)
(display-time)
;; (display-battery-mode -1)
;; Nope; let's use a fancy indicator …
(use-package fancy-battery
  :diminish
  :custom (fancy-battery-show-percentage  t)
          (battery-update-interval       15)
  :config (fancy-battery-mode))

Likewise, let’s have the modeline display column numbers, but not line numbers. Instead, let’s have line numbers on the side of the buffer; moreover let’s have a uniform width for displaying line numbers, rather than having the width grow as necessary.

;; Following two taken care of in the spaceline package, below.
;; (column-number-mode                 t)
;; (line-number-mode                   t)
(setq display-line-numbers-width-start t)
(global-display-line-numbers-mode      t)

I may not use the spacemacs starter kit, since I find spacemacs to “hide things” from me —whereas Emacs “encourages” me to learn more—, however it is a configuration and I enjoy reading Emacs configs in order to improve my own setup. From Spacemacs I’ve adopted Helm for list completion, its sleek light & dark themes, and its modified powerline setup.

;; When using helm & info & default, mode line looks prettier.
(use-package spaceline
  :custom (spaceline-buffer-encoding-abbrev-p nil)
          ;; Use an arrow to seperate modeline information
          (powerline-default-separator 'arrow)
          ;; Show “line-number : column-number” in modeline.
          (spaceline-line-column-p t)
          ;; Use two colours to indicate whether a buffer is modified or not.
          (spaceline-highlight-face-func 'spaceline-highlight-face-modified)
  :config (custom-set-faces '(spaceline-unmodified ((t (:foreground "black" :background "gold")))))
          (custom-set-faces '(spaceline-modified   ((t (:foreground "black" :background "cyan")))))
          (require 'spaceline-config)
          (spaceline-helm-mode)
          (spaceline-info-mode)
          (spaceline-emacs-theme))

Other separators —of modeline information— that I’ve considered include ~’brace~ instead of an arrow, and ~’contour, ‘chamfer, ‘wave, ‘zigzag~ which look like browser tabs that are curved, boxed, wavy, or in the style of driftwood.

Powerful Directory Editing with dired

C-x C-v to open a file or directory in dired, using the current buffer. ⟩

As mentioned earlier, dired is Emacs’ built-in directory editor; it’s opened with C-x d. Dired let’s us treat directories as textual objects! In dired, press h to see the many actions available. Here’s a few:

  • ( toggles hiding entry details, such as modification date and ownership
  • s sort entries; modeline will display “Dired by date” or “Dired by name”.
  • o to open entry in anOther window; or RET to open in place.
  • + to create a new directory; or M-x make-directory.
  • / to filter entries; with which-key, possible completions pop-up.
    • E.g., / f shows only files or / . png to obtain all entries with extension png.
    • / i g to hide git-ignored items ^_^
    • / / to remove all filters.
  • TAB to navigate between different groupings of entries.
    • RET on a drawer heading toggles folding it ^_^

The dired-hacks family of packages lets us, say, get a dired buffer out of a shell incantation that lists files, or use dired to open files with external tools. Below we use three of its packages.

Pressing i inserts a directory’s children under it, indented, in the current buffer. Useful to see what’s there.

(use-package dired-subtree
  :bind (:map dired-mode-map
              ("i" . dired-subtree-toggle)))

When directory 𝒳 has only one child 𝒴, then in dired, instead of 𝒳, show me 𝒳/𝒴 with 𝒳 greyed out.

(use-package dired-collapse
  :hook (dired-mode . dired-collapse-mode))

Begin dired with certain entries grouped together, according to some filtering requirement; and with “garbage” files not shown —i.e., those ending in .aux, .out, etc.

(use-package dired-filter
  :hook (dired-mode . (lambda () (dired-filter-group-mode)
                                 (dired-filter-by-garbage)))
  :custom
    (dired-garbage-files-regexp
      "\\(?:\\.\\(?:aux\\|bak\\|dvi\\|log\\|orig\\|rej\\|toc\\|out\\)\\)\\'")
    (dired-filter-group-saved-groups
      '(("default"
         ("Org"    (extension "org"))
         ("Executables" (exexutable))
         ("Directories" (directory))
         ("PDF"    (extension "pdf"))
         ("LaTeX"  (extension "tex" "bib"))
         ("Images" (extension "png"))
         ("Code"   (extension "hs" "agda" "lagda"))
         ("Archives"(extension "zip" "rar" "gz" "bz2" "tar"))))))

Neotree: Traditional Directory Tree Navigation

⟨ Disabled ⟩

We open a nifty file manager upon startup.

;; Sidebar for project file navigation
(use-package neotree
  :defer t
  :disabled
  :config (global-set-key "\C-x\ d" 'neotree-toggle)
          (setq neo-theme 'icons)) ;; Uses all-the-icons from § Booting Up

;; Open it up upon startup.
;; (neotree-toggle)

By default C-x d invokes dired, but I prefer neotree for file management.

⟨ Edit: As a naive user, this is what I thought; yet a year later, I’ve almost never used neotree. ⟩

Useful navigational commands include

  • U to go up a directory.
  • C-c C-c to change directory focus; C-C c to type the directory out.
  • ? or h to get help and q to quit.

As always, to go to the neotree pane when it’s the only other window, execute C-x o.

I rarely make use of this feature; company mode & Helm together quickly provide an automatic replacement for nearly all of my uses.

  • Reminiscent of GUI file managers is ranger; e.g., it has multi-column display of parent directories along with a file preview mechanism.

Never lose the cursor

Let’s have the entire line containing the cursour be slightly highlighted.

;; Make it very easy to see the line with the cursor.
(global-hl-line-mode t)

Moreover, we reduce the mental strain of locating the cursour when navigation happens: When we switch windows or scroll, for example, we get a wave of light near the cursor.

(use-package beacon
  :diminish
  :config (setq beacon-color "#666600")
  :hook   ((org-mode text-mode) . beacon-mode))

Dimming Unused Windows

Let’s dim windows, and even the whole Emacs frame, when not in use.

(use-package dimmer
  :config (dimmer-mode))

A more ‘fine-grained’ tool dims all text except the ‘paragraph’ you’re working on. It’s nifty, but not for me.

Buffer names are necessarily injective

By default when multiple files sharing the same name are opened, say for comparison from different directories, their buffers are named uniquely by having the format “⟨file-name⟩ <𝓃>”, for numbers 𝓃. It’d be more helpful to have the buffer names reflect their location.

;; Note that ‘uniquify’ is builtin.
(require 'uniquify)
(setq uniquify-separator "/"               ;; The separator in buffer names.
      uniquify-buffer-name-style 'forward) ;; names/in/this/style

Note that this does not affect cloning buffers, C-x 4 c.

( A function f is injective precisely when it’s distinction-preserving; i.e., x ≠ y ≡ f x ≠ f y. We can tell whether two things are the same or not, by ‘zooming in’ on their particular property ‘f’, which may be easier to compare. E.g., object IDs, hashcodes, unique keys in database tables. )

( Why am I bringing this up? I like math and seldom get to use it; so why not! )

Flashing when something goes wrong —no blinking

Make top and bottom of screen flash when something unexpected happens thereby observing a warning message in the minibuffer. E.g., C-g, or calling an unbound key sequence, or misspelling a word.

(setq visible-bell 1)

Enable flashing mode-line on errors. On MacOS, this shows a caution symbol ^_^

A blinking cursor rushes me to type; let’s slow down. … Recentely I’m thinking that a blinking cursours prompts me to continue upwards and onwards.

(blink-cursor-mode 1)

Hiding Scrollbar, tool bar, and menu

As a laptop user, screen space is important, so let’s remove rarely used visual items.

(tool-bar-mode   -1)  ;; No large icons please
(scroll-bar-mode -1)  ;; No visual indicator please
(menu-bar-mode   -1)  ;; The Mac OS top pane has menu options

Highlight & complete parenthesis pair when cursor is near ;-)

Highlight matching ‘parenthesis’ when near one of them.

(setq show-paren-delay  0)
(setq show-paren-style 'mixed)
(show-paren-mode)

Colour parens, and other delimiters, depending on their depth. Very useful for parens heavy languages like Lisp.

(use-package rainbow-delimiters
  :disabled
  :hook ((org-mode prog-mode text-mode) . rainbow-delimiters-mode))

For example:

(blue (purple (forest (green (yellow (blue))))))

There is a powerful package called ‘smartparens’ for working with pair-able characters, but I’ve found it to be too much for my uses. Instead I’ll utilise the lightweight package electric, which Emacs provides out of the box.

(electric-pair-mode 1)

It supports, by default, ACSII pairs {}, [], () and Unicode ‘’, “”, ⟪⟫, ⟨⟩.

When writing Lisp, it is annoyong to have ‘<’ and ‘>’ be completed and considered as pairs. Let’s disassociate them from both notions.

;; The ‘<’ and ‘>’ are not ‘parenthesis’, so give them no compleition.
(setq electric-pair-inhibit-predicate
      (lambda (c)
        (or (member c '(?< ?> ?~)) (electric-pair-default-inhibit c))))

;; Treat ‘<’ and ‘>’ as if they were words, instead of ‘parenthesis’.
(modify-syntax-entry ?< "w<")
(modify-syntax-entry ?> "w>")

Adding Org-emphasise markers for pair completion —Disabled.

Let’s add the org-emphasises markers: If we select a word then press *, it becomes bold; likewise for / for emphasise.

(setq electric-pair-pairs
         '((?~ . ?~)
           (?* . ?*)
           (?/ . ?/)))

;; Let's also, for example, avoid obtaining double ‘~’ and ‘/’ when searching for a file.

;; Disable pairs when entering minibuffer
(add-hook 'minibuffer-setup-hook (lambda () (electric-pair-mode 0)))

;; Renable pairs when existing minibuffer
(add-hook 'minibuffer-exit-hook (lambda () (electric-pair-mode 1)))

I use ‘~’ and ‘/’ too much during file navigation, and ‘*’ when marking numerous Org headers, for which the ‘completed closing pair’ must tiresomely be deleted.

I really like my Helm-supported C-x b, but the visial appeal of a tab bar for Emacs is interesting. Let’s try it out and see how long this lasts —it may be like Neotree: Something cute to show to others, but not as fast as the keyboard.

(use-package awesome-tab
  :disabled
  :quelpa (awesome-tab :fetcher git :url "https://github.com/manateelazycat/awesome-tab.git")
  :config (awesome-tab-mode t))

;; Show me /all/ the tabs at once, in one group.
(defun awesome-tab-buffer-groups ()
  (list (awesome-tab-get-group-name (current-buffer))))

It’s been less than three days and I’ve found this utility to be unhelpful, to me anyhow.

An alternative is centaur-tabs.

Window resizing using the golden ratio

Let’s load the following package, which automatically resizes windows so that the window containing the cursor is the largest, according to the golden ratio. Consequently, the window we’re working with is nice and large yet the other windows are still readable.

(use-package golden-ratio
  :disabled
  :diminish golden-ratio-mode
  :init (golden-ratio-mode 1))

After some time this got a bit annoying and I’m no longer using this.

Persistent Scratch Buffer

The *scratch* buffer is a nice playground for temporary data or experiments.

However, by default its contents are not saved –which may be an issue if we have not relocated our playthings to their appropriate files. Whence let’s save & restore the scratch buffer by default.

(use-package persistent-scratch
  :defer t
  ;; In this mode, the usual save key saves to the underlying persistent file.
  :bind (:map persistent-scratch-mode-map
              ("C-x C-s" . persistent-scratch-save)))

We might accidentally close this buffer, so we could utilise the following.

(defun scratch ()
   "Recreate the scratch buffer, loading any persistent state."
   (interactive)
   (switch-to-buffer-other-window (get-buffer-create "*scratch*"))
   (condition-case nil (persistent-scratch-restore) (insert initial-scratch-message))
   (org-mode)
   (persistent-scratch-mode)
   (persistent-scratch-autosave-mode 1))

;; This doubles as a quick way to avoid the common formula: C-x b RET *scratch*

;; Upon startup, close the default scratch buffer and open one as specfied above
(ignore-errors (kill-buffer "*scratch*") (scratch))

I use Org-mode often, so that’s how I want things to appear.

(setq initial-scratch-message (concat
  "#+Title: Persistent Scratch Buffer"
  "\n#\n# Welcome! This’ a place for trying things out."
  "\n#\n# ⟨ ‘C-x C-s’ here saves to ~/.emacs.d/.persistent-scratch ⟩ \n\n"))

Prose

Emacs can be setup with a spellchecker and other expected features of a word processing tool —however these features apply Emacs-wide since nearly everything is essentially text (•̀ᴗ•́)و

Let’s start off by cleaning-up any accidental trailing whitespace and in other places upon save.

(add-hook 'before-save-hook 'whitespace-cleanup)
  • Org-mode is a writer’s best friend; it’s large enough to deserve its own sections.
  • See here for making whitespace visible; including spaces, tabs, and newlines

Fill-mode —Word Wrapping

In fill mode, when you type past the end of a line, Emacs automatically starts a new line, cleverly formatting paragraphs. This is a powerful form of “word wrap”.

(setq-default fill-column 80          ;; Let's avoid going over 80 columns
              truncate-lines nil      ;; I never want to scroll horizontally
              indent-tabs-mode nil)   ;; Use spaces instead of tabs

Certain variables are sensibly local to a buffer, and so setq only alters their value for one buffer. Using setq-default we change a variable’s default value, in every buffer.

;; Wrap long lines when editing text
(add-hook 'text-mode-hook 'turn-on-auto-fill)
(add-hook 'org-mode-hook 'turn-on-auto-fill)

;; Do not show the “Fill” indicator in the mode line.
(diminish 'auto-fill-function)

We may press M-q to cleverly redistribute the line breaks within any paragraph, thereby making it look better. With a prefix argument, it justifies it as well —i.e., pads extra white space to make the paragraph appear rectangular.

Note that M-o M-s centres a line of text ;-) Fun stuff!

Fill-mode is also known as “hard word wrapping”, which has the counterpart “soft word wrapping” …

Visual line mode is built-in and provides support for editing by visual lines: Lines off the screen are visually word wrapped, but logically remain one line. Moreover C-a,e,k operate on visual lines rather than logical lines.

;; Bent arrows at the end and start of long lines.
(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))
(diminish 'visual-line-mode)
(global-visual-line-mode 1)

Visual line mode is useful when I have way too many windows open or when using smaller frames.

Pretty Lists Markers

When writing, it’s common to use +,-,* to enumerate unordered lists —especially so in Org-mode wherein they denote structured text. Let’s render them visually as Unicode bullets.

;; (x y z) ≈ (existing-item replacement-item positivity-of-preceding-spaces)
(require 'cl)
(loop for (x y z) in '(("+" "◦" *)
                       ("-" "•" *)
                       ("*" "⋆" +))
      do (font-lock-add-keywords 'org-mode
                                 `((,(format "^ %s\\([%s]\\) " z x)
                                    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) ,y)))))))

Word Completion

Let’s enable “complete anything” mode —it ought to start in half a second and only need two characters to get going, which means word suggestions are provided and so I need only type partial words then tab to get the full word!

(use-package company
  :diminish
  :config
  (global-company-mode 1)
  (setq ;; Only 2 letters required for completion to activate.
   company-minimum-prefix-length 2

   ;; Search other buffers for compleition candidates
   company-dabbrev-other-buffers t
   company-dabbrev-code-other-buffers t

   ;; Show candidates according to importance, then case, then in-buffer frequency
   company-transformers '(company-sort-by-backend-importance
                          company-sort-prefer-same-case-prefix
                          company-sort-by-occurrence)

   ;; Flushright any annotations for a compleition;
   ;; e.g., the description of what a snippet template word expands into.
   company-tooltip-align-annotations t

   ;; Allow (lengthy) numbers to be eligible for completion.
   company-complete-number t

   ;; M-⟪num⟫ to select an option according to its number.
   company-show-numbers t

   ;; Show 10 items in a tooltip; scrollbar otherwise or C-s ^_^
   company-tooltip-limit 10

   ;; Edge of the completion list cycles around.
   company-selection-wrap-around t

   ;; Do not downcase completions by default.
   company-dabbrev-downcase nil

   ;; Even if I write something with the ‘wrong’ case,
   ;; provide the ‘correct’ casing.
   company-dabbrev-ignore-case nil

   ;; Immediately activate completion.
   company-idle-delay 0)

  ;; Use C-/ to manually start company mode at point. C-/ is used by undo-tree.
  ;; Override all minor modes that use C-/; bind-key* is discussed below.
  (bind-key* "C-/" #'company-manual-begin)

  ;; Bindings when the company list is active.
  :bind (:map company-active-map
              ("C-d" . company-show-doc-buffer) ;; In new temp buffer
              ("<tab>" . company-complete-selection)
              ;; Use C-n,p for navigation in addition to M-n,p
              ("C-n" . (lambda () (interactive) (company-complete-common-or-cycle 1)))
              ("C-p" . (lambda () (interactive) (company-complete-common-or-cycle -1)))))

;; It's so fast that we don't need a key-binding to start it!

Note that M-/ goes through a sequence of completions —and C-/ manually begins company mode at point. Besides the arrow keys, we can also use M- with n, p to navigate the options or use C-s to search the list of suggestions.

  • Company backends are available as separate packages.
  • Note that by default company mode does not support completion for phrases containing hyphens —this can be altered, if desired.

Besides boring word completion, let’s add support for emojis.

(use-package company-emoji
  :config (add-to-list 'company-backends 'company-emoji))

For example: pancakescomputermonkey_faceemailwinkdolphincactus.

arrow_rightOn a new line, write : then any letter to have a tool-tip appear. All emoji names are lowercase. arrow_backward

  • On MacOS, C-⌘-SPC brings up an emoji picker, where one drags desired emojis to textual areas.
  • Here is a list of emoji —all supported by Github.

The libraries emojify and emojify-logos provides cool items like =:haskell:

with org-mode, so I’m not using them.

Fix spelling as you type —thesaurus & dictionary too!

I would like to check spelling on the fly.

C-;Cycle through corrections for word at point. M-$Check and correct spelling of the word at point M-x ispell-change-dictionary RET TABTo see what dictionaries are available.

flyspell-prog-mode enables spell checking for programming by only considering comments and strings.

(use-package flyspell
  :diminish
  :hook ((prog-mode . flyspell-prog-mode)
         ((org-mode text-mode) . flyspell-mode)))

Enabling fly-spell for text-mode enables it for org and latex modes since they derive from text-mode.

Flyspell needs a spell checking tool, which is not included in Emacs. We install aspell spell checker using, say, homebrew via brew install aspell. Note that Emacs’ ispell is the interface to such a command line spelling utility.

(setq ispell-program-name "/usr/local/bin/aspell")
(setq ispell-dictionary "en_GB") ;; set the default dictionary

[Disabled] Allow spelling support for CamlCase words like “EmacsIsCool”.

(setq  ispell-extra-args '("--sug-mode=ultra"
                            "--run-together"
                            "--run-together-limit=5"
                            "--run-together-min=2"))

Let us select a correct spelling merely by clicking on a word —for the rare days I have a mouse.

(eval-after-load "flyspell"
  ' (progn
     (define-key flyspell-mouse-map [down-mouse-3] #'flyspell-correct-word)
     (define-key flyspell-mouse-map [mouse-3] #'undefined)))

Colour incorrect works; default is an underline.

(global-font-lock-mode t)
(custom-set-faces '(flyspell-incorrect ((t (:inverse-video t)))))

Finally, save to user dictionary without asking:

(setq ispell-silently-savep t)

Let’s keep track of my personal word set by having it be in my version controlled .emacs directory. Note that the default location is ~~/.[i|a]spell.DICT~ for a specified dictionary DICT.

(setq ispell-personal-dictionary "~/.emacs.d/.aspell.en.pws")

Nowadays, I very rarely write non-literate programs, but if I do I’d like to check spelling only in comments/strings. E.g.,

(add-hook          'c-mode-hook 'flyspell-prog-mode)
(add-hook 'emacs-lisp-mode-hook 'flyspell-prog-mode)

Use the thesaurus Emacs frontend Synosaurus to avoid unwarranted repetition.

(use-package synosaurus
  :diminish synosaurus-mode
  :init    (synosaurus-mode)
  :config  (setq synosaurus-choose-method 'popup) ;; 'ido is default.
           (global-set-key (kbd "M-#") 'synosaurus-choose-and-replace))

The thesaurus is powered by the Wordnet wn tool, which can be invoked without an internet connection!

;; (shell-command "brew cask install xquartz &") ;; Dependency
;; (shell-command "brew install wordnet &")

Let’s use Wordnet as a dictionary via the wordnut package.

(use-package wordnut
 :bind ("M-!" . wordnut-lookup-current-word))

;; Use M-& for async shell commands.

Use M-↑,↓ to navigate dictionary results, and wordnut-search for a new search.

An alternative to wordnut is to use the lightweight define-word package; which I think is not ideal since it provides way less information.

Touch Typing

Use this game to help you learn to spell words that you’re having trouble with; e.g., I have a file ~~/Dropbox/spelling.txt~ with words I have trouble spelling, which I open then run M-x typing-of-emacs in order to improve spelling said words.

;; The Typing Of Emacs, a game.
(use-package typing-of-emacs :defer t
  :quelpa (typing :fetcher wiki :url "https://www.emacswiki.org/emacs/typing.el"))

Practice touch typing using speed-type.

(use-package speed-type :defer t)

Running M-x speed-type-region on a region of text, or M-x speed-type-buffer on a whole buffer, or just M-x speed-type-text will produce the selected region, buffer, or random text for practice. The timer begins when the first key is pressed and stats are shown when the last letter is entered.

Other typing resources include:

  • Typing of Emacs —an Emacs alternative to speed type, possibly more engaging.
  • Klavaro —a GUI based yet language-independent typing tutor.
    • I’m enjoying this tool in getting started with Arabic typing.
  • Typing.io is a tutor for coders: Lessons are based on open source code, such some XMonad written in Haskell or Linux written in C.
  • GNU Typist —which is interactive in the terminal, so not ideal in Emacs–,

To assist in language learning, it may be nice to have an Emacs interface to Google translate —e.g., invoke google-translate-at-point.

(use-package google-translate
 :defer t
 :config
   (global-set-key "\C-ct" 'google-translate-at-point))

Select the following then C-c t,

Hey buddy, what’re you up to?

Then detect language then Arabic to obtain:

مرحباً يا صديقي ، ماذا تفعل؟

Neato astonished

Using a Grammar & Style Checker

Let’s install a grammar and style checker. We get the offline tool from the bottom of the LanguageTool website, then relocate it as follows.

(use-package langtool
 :defer t
 :custom
  (langtool-language-tool-jar
   "~/Applications/LanguageTool-4.5/languagetool-commandline.jar"))

Now we can run langtool-check on the subsequent grammatically incorrect text —which is from the LanguageTool website— which colours errors in red, when we click on them we get the reason why; then we may invoke langtool-correct-buffer to quickly use the suggestions to fix each correction, and finally invoke langtool-check-done to stop any remaining red colouring.

LanguageTool offers spell and grammar checking. Just paste your text here
and click the 'Check Text' button. Click the colored phrases for details
on potential errors. or use this text too see an few of of the problems
that LanguageTool can detecd. What do you thinks of grammar checkers?
Please not that they are not perfect. Style issues get a blue marker:
It's 5 P.M. in the afternoon. The weather was nice on Thursday, 27 June 2017
--uh oh, that's the wrong date ;-)

By looking around the source code, I can do all three stages smoothly (•̀ᴗ•́)و

;; Quickly check, correct, then clean up /region/ with M-^
(eval-after-load 'langtool
(progn
(add-hook 'langtool-error-exists-hook
  (lambda ()
     (langtool-correct-buffer)
     (langtool-check-done)))

(global-set-key "\M-^"
                (lambda ()
                  (interactive)
                  (message "Grammar checking begun ...")
                  (langtool-check)))))

The checking command is silent, we added a bit of comforting acknowledgement to the user.

Lightweight Prose Proofchecking

Let’s write good!

(use-package writegood-mode
  ;; Load this whenver I'm composing prose.
  :hook (text-mode org-mode)
  ;; Don't show me the “Wg” marker in the mode line
  :diminish
  ;; Some additional weasel words.
  :config
  (--map (push it writegood-weasel-words)
         '("some" "simple" "simply" "easy" "often" "easily" "probably"
           "clearly"               ;; Is the premise undeniably true?
           "experience shows"      ;; Whose? What kind? How does it do so?
           "may have"              ;; It may also have not!
           "it turns out that")))  ;; How does it turn out so?
           ;; ↯ What is the evidence of highighted phrase? ↯

Inspired by Matt Might’s 3 shell scripts to improve your writing, or “My Ph.D. advisor rewrote himself in bash”, this Emacs interface emphasises, via underline, the following weaknesses in writing —so that I can fix them or decide that they are appropriate for the scenario.

Sentences that cut out the following problems may become stronger —by being more terse or precise.

Weasel Words Phrases that sound good without conveying information; such as vague precision or subjective phrases.

E.g., a number of, surprisingly, very close.

It’s okay not to have exact details, but rather than “I don’t know” explain why not and what the next steps will be.

Passive Voice Phrases wherein interest is in the object experiencing an action, rather than the subject that performs the action.

  • Bad: The house was built by my father.
  • Good: My father built this house.

Likewise, including relevant or explanatory information as in “X guarantees Y” is an improvement over “Y is guaranteed”.

Sometimes the subject really is irrelevant, such as “We did X” whereas “X happened” suffices.

+1 If the relevant subject is unclear and, also, the text reads better in the active, then change a phrase.

Duplicated WordsOccurrences of, say, “the the”.

Harder to catch manually, but easier mechanically ;-)

Placeholder Text —For Learning & Experimenting

When learning about Emacs formatting commands, such as zap-to-char M-z or transpose M-t, it’s best to have filler text —even better when it’s automatically generated instead of typing it out ourselves. The following will give us a series of commands lorem-ipsum-insert-⋯ for inserting lists, sentences, paragraphs and using a prefix argument, with C-u, we can request to generate any number of them.

(use-package lorem-ipsum :defer t)

‘Lorem’ is not a word itself, but it comes from the Latin ‘Dolorem Ipsum’ which means “pain in and of itself”.

See this Emacs Cheat Sheet to try out the textual navigation and formatting bindings on lorem ipsum, gibberish text.

Some text to make us smile

The dad-joke queries https://icanhazdadjoke.com to bring us some funny.

(use-package dad-joke
  :defer t
  :config (defun dad-joke () (interactive) (insert (dad-joke-get))))

For example, M-x dad-joke now inserts:

What are the strongest days of the week? Saturday and Sunday…the rest are weekdays.

Unicode Input via Agda Input

Agda is one of my favourite languages, it’s like Haskell on steroids. Let’s set it up for the main sake of its Unicode input —you may do likewise using TeX input. ( The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) )

Executing agda-mode setup appends the following text to the .emacs file. Let’s put it here ourselves.

(load-file (let ((coding-system-for-read 'utf-8))
                (shell-command-to-string "/usr/local/bin/agda-mode locate")))

I almost always want the agda-mode input method —it’s like the TeX method, but better.

(use-package agda-input
  :ensure nil ;; I have it locally.
  :demand t
  :hook ((text-mode prog-mode) . (lambda () (set-input-method "Agda")))
  :custom (default-input-method "Agda"))
  ;; Now C-\ or M-x toggle-input-method turn it on and offers

Unicode doesn’t intend to cover things that are achievable with markup, so only a limited subset of the alphabet is available as subscript; but all is available as superscript, except ‘q’.

ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓ ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₊ ₋ ₌ ₍ ₎ ᵃ ᵇ ᶜ ᵈ ᵉ ᶠ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ᵛ ʷ ˣ ʸ ᶻ ᴬ ᴮ ᴰ ᴱ ᴳ ᴴ ᴵ ᴶ ᴷ ᴸ ᴹ ᴺ ᴼ ᴾ ᴿ ᵀ ᵁ ⱽ ᵂ ᵅ ᵝ ᵞ ᵟ ᵋ ᶿ ᶥ ᶲ ᵠ ᵡ ᵦ ᵧ ᵨ ᵩ ᵪ

brew cask install font-symbola ⇒ Includes fonts for subscripts; e.g., ₐₙₑₕᵢⱼₖₗₘₙₒₚₜₛ

Below are my personal Agda input symbol translations; e.g., \set → 𝒮ℯ𝓉. Note that we could give a symbol new Agda TeX binding interactively: M-x customize-variable agda-input-user-translations then INS then for key sequence type set then INS and for string paste 𝒮ℯ𝓉.

(add-to-list 'agda-input-user-translations '("set" "𝒮ℯ𝓉"))

Better yet, as a loop:

(loop for item
      in '(;; categorial ;;
           ("alg" "𝒜𝓁ℊ")
           ("split" "▵")
           ("join" "▿")
           ("adj" "⊣")
           (";;" "﹔")
           (";;" "⨾")
           (";;" "∘")
           ;; lattices ;;
           ("meet" "⊓")
           ("join" "⊔")
           ;; residuals
           ("syq"  "╳")
           ("over" "╱")
           ("under" "╲")
           ;; Z-quantification range notation ;;
           ;; e.g., “∀ x ❙ R • P” ;;
           ("|"    "❙")
           ("with" "❙")
           ;; adjunction isomorphism pair ;;
           ("floor"  "⌊⌋")
           ("lower"  "⌊⌋")
           ("lad"    "⌊⌋")
           ("ceil"   "⌈⌉")
           ("raise"  "⌈⌉")
           ("rad"    "⌈⌉")
           ;; Arrows
           ("<=" "⇐")
        ;; more (key value) pairs here
        )
      do (add-to-list 'agda-input-user-translations item))

Also some silly stuff:

;; Add to the list of translations using “emot” and the given, more specfic, name.
;; Whence, \emot shows all possible emotions.
(loop for emot
      in `(;; angry, cry, why-you-no
           ("whyme" "ლ(ಠ益ಠ)ლ" "ヽ༼ಢ_ಢ༽ノ☂" "щ(゜ロ゜щ)")
           ;; confused, disapprove, dead, shrug
           ("what" "「(°ヘ°)" "(ಠ_ಠ)" "(✖╭╮✖)" "¯\\_(ツ)_/¯")
           ;; dance, csi
           ("cool" "┏(-_-)┓┏(-_-)┛┗(-_- )┓"
            ,(s-collapse-whitespace "•_•)
                                      ( •_•)>⌐■-■
                                      (⌐■_■)"))
           ;; love, pleased, success, yesss
           ("smile" "♥‿♥" "(─‿‿─)" "(•̀ᴗ•́)و" "(งಠ_ಠ)ง"))
      do
      (add-to-list 'agda-input-user-translations emot)
      (add-to-list 'agda-input-user-translations (cons "emot" (cdr emot))))

Finally let’s effect such translations.

;; activate translations
(agda-input-setup)

Note that the effect of Emacs unicode input could be approximated using abbrev-mode.

Increase/decrease text size

The ‘usual’ text zoom keys C-±

(global-set-key (kbd "C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
;; C-x C-0 restores the default font size

If thou knowst the ELisp, forgive this shadowing of the negative-argument … we’ve still got M-- though.

Curious, this is one of the very first things I did when began using Emacs; yet, perhaps I would not have done it if I was simply told the defaults:

  • C-x C-=,+ increases text size
  • C-x C-- decreases test size
  • C-x C-0 restores it to the default size

So, the above snippet seems to save us of the prefix C-x and we lose on using ‘=’ for text increase and worse we need the shift-key to get access to the ‘+’.

I suppose this is just a habit inherited from using other tools. Fortunately, I did not inherit the need for the common user access bindings C-x kill, C-c copy, C-v paste, nor C-z undo of other applications. If you’re interested, M-x cua-mode to enable CUA Bindings.

Moving Text Around

This extends Org-mode’s M-↑,↓ to other modes, such as when coding.

;; M-↑,↓ moves line, or marked region; prefix is how many lines.
(use-package move-text
  :config (move-text-default-bindings))

Enabling CamelCase Aware Editing Operations

Subword movement lets us treat “EmacsIsAwesome” as three words ─“Emacs”, “Is”, and “Awesome”─ which is desirable since such naming is common among coders. Now, for example, M-f moves along each subword.

(global-subword-mode 1)
(diminish 'subword-mode)

Mouse Editing Support

Text selected with the mouse is automatically copied to clipboard.

(setq mouse-drag-copy-region t)

Delete Selection Mode

Delete Selection mode lets you treat an Emacs region much like a typical text selection outside of Emacs: You can replace the active region. We can delete selected text just by hitting the backspace key.

(delete-selection-mode 1)

M-n,p: Word-at-Point Navigation

Let’s mimic the C-n,p constructs from line to word, so that unoccupied M-n,p now serve to take us to the next or previous instance of the word under the cursor. This is less intrusive than searching C-s or listing all occurrences M-s o.

(use-package smartscan
  :defer t
  :config
    (global-set-key (kbd "M-n") 'smartscan-symbol-go-forward)
    (global-set-key (kbd "M-p") 'smartscan-symbol-go-backward)
    (global-set-key (kbd "M-'") 'my/symbol-replace))

Unfortunately, as it currently is, there is no universal argument support: C-u 2 M-p does not take you to the second previous instance of a word —the prefix is instead ignored.

The default symbol replacement is over-zealous in that it replaces sub-terms occurring as parts of larger words. Let’s do something about that.

(defun my/symbol-replace (replacement)
  "Replace all standalone symbols in the buffer matching the one at point."
  (interactive  (list (read-from-minibuffer "Replacement for thing at point: " nil)))
  (save-excursion
    (let ((symbol (or (thing-at-point 'symbol) (error "No symbol at point!"))))
      (beginning-of-buffer)
      ;; (query-replace-regexp symbol replacement)
      (replace-regexp (format "\\b%s\\b" (regexp-quote symbol)) replacement))))

Also …

;; C-n, next line, inserts newlines when at the end of the buffer
(setq next-line-add-newlines t)

Letter-based Navigation

At a glance of possible positions, across windows, and a key to jump there is a feature provided to us by ace-jump —here is an emacs-rocks 2-minute video.

For example, C-c SPC m greys our all windows and places a red letter at the start of any word that begins with m, then I may press a letter to jump to the associated position in the associated window. Using C-u C-c SPC and C-u C-u C-c SPC let me jump to any character or to any visible line.

➩ Super simple use case: Fix your eyes on an occurence of a word, then C-c SPC to quickly jump to it so as to edit the sentence in which it occurs.

  • It’s like C-s but more lightweight.
(use-package ace-jump-mode
  :defer t
  :config (bind-key* "C-c SPC" 'ace-jump-mode))

;; See ace-jump issues to configure for use of home row keys.

There is a newer and somewhat more powerful package, avy, which accompishes the same goal. It uses a tree style to jumipng: Locations are given two letter combinations, one presses one letter to jump to a group of text, then another letter to jump somewhere in that grouping. I prefer ace-jump since it greys everthing out, whereas avy surrounds jump locations with a box. Here is an emacs-doom 6-minute video for avy.

There is also ace-isearch for bridinging different navgiational methods —one begins incremental search, s-f, then according to a pause and length of input, one of the navgiational methods, such as isearch or avy or helm-swoop, will be begun. I’m okay with using C-s for helm-swoop and C-c SPC for ace-jump, and still have s-f for incremental search, which I hardly use.

What is bind-keys*?

Major modes provide specfic use and so their bindings always take precedence over global bindings —e.g., the major mode binding may do what the global does but with extra mode-specfic behaviour, such as indentation. Other times, a major mode’s binding simply uses the same key presses with completely unrelated behaviour. If we want to avoid having our global keybindings shadowed by a major mode, we may use the bind-key* macro of use-package, or the bind-keys* macro when there are multiple keys; these are macros, not clauses. —These essentially creates a dedicated minor mode behind the scenes, which saves us the work of doing it ourselves.

(bind-keys* (k₁ . f₁) … (kₙ . fₙ))
These keybindings override all minor modes that use keys kᵢ.

C-c e n,p: Taking a tour of one’s edits

This package allows us to move around the edit points of a buffer without actually undoing anything. We even obtain a brief description of what happend at each edit point. This seems useful for when I get interrupted or lose my train of thought: Just press C-c e p to see what I did recently and where —the “e” is for “e”dit.

;; Give me a description of the change made at a particular stop.
(use-package goto-chg
  :defer t
  :custom (glc-default-span 0))

(defhydra hydra-edits (global-map "C-c e")
  ("p" goto-last-change "Goto nᵗʰ last change")
  ("n" goto-last-change-reverse "Goto more recent change"))

Compare this with C-x u, or undo-tree-visualise, wherein undos are actually performed.

Notice, as a hydra, I can use C-c e followed by any combination of p and n to navigate my recent edits without having to supply the prefix each time.

Org-Mode Administrivia

Let’s get Org-mode setup so that we can quickly move between headings and org-blocks —~n,p~ on heading starts and s-n,p on blocks—, then let’s prettify the leading stars of headings, Org’s formatting delimiters, and even its blocks delimiters by making them less intrusive thereby ‘fading into the background’ and drawing minimal attention. This has been useful when promoting Org-mode by sharing my screen with others. Let’s obtain Org-mode along with the extras that allow us to ignore heading names, but still utilise their contents —e.g., such as a heading named ‘preamble’ that contains org-mode setup for a file.

(use-package org
  :ensure org-plus-contrib
  :config (require 'ox-extra)
          (ox-extras-activate '(ignore-headlines)))

org-plus-contrib contain the files that are included with Emacs plus all contributions from the org-mode repoistory.

  • Use the :ignore: tag on headlines you’d like to have ignored, while not ignoring their content.
  • Use the :noexport: tag to omit a headline and its contents.
;; Replace the content marker, “⋯”, with a nice unicode arrow.
(setq org-ellipsis " ⤵")

;; Fold all source blocks on startup.
(setq org-hide-block-startup t)

;; Lists may be labelled with letters.
(setq org-list-allow-alphabetical t)

;; Avoid accidentally editing folded regions, say by adding text after an Org “⋯”.
(setq org-catch-invisible-edits 'show)

;; I use indentation-sensitive programming languages.
;; Tangling should preserve my indentation.
(setq org-src-preserve-indentation t)

;; Tab should do indent in code blocks
(setq org-src-tab-acts-natively t)

;; Give quote and verse blocks a nice look.
(setq org-fontify-quote-and-verse-blocks t)

;; Pressing ENTER on a link should follow it.
(setq org-return-follows-link t)

I rarely use tables, but here is a useful Org-Mode Table Editing Cheatsheet and a friendly tutorial.

Moreover, since I end up using org-mode most of the time, let’s make that the default mode.

(setq initial-major-mode 'org-mode)

Executing code from src blocks

For example, to execute a shell command in Emacs, write a src with a shell command, then C-c c-c to see the results. Emacs will generally query you to ensure you’re confident about executing the (possibly dangerous) code block; let’s stop that:

;; Seamless use of babel: No confirmation upon execution.
;; Downside: Could accidentally evaluate harmful code.
(setq org-confirm-babel-evaluate nil)

A worked out example can be obtained as follows: <g TAB then C-c C-C to make a nice simple graph —the code for this is in the next section.

Some initial languages we want org-babel to support:

 (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (shell      . t)
     (python     . t)
     (haskell    . t)
     (ruby       . t)
     (ocaml      . t)
     (C          . t)  ;; Captial “C” gives access to C, C++, D
     (dot        . t)
     (latex      . t)
     (org        . t)
     (makefile   . t)))

;; Preserve my indentation for source code during export.
(setq org-src-preserve-indentation t)

;; The export process hangs Emacs, let's avoid this.
;; MA: For one reason or another, this crashes more than I'd like.
;; (setq org-export-in-background t)

More languages can be added using add-to-list.

High Speed Literate Programming

Manipulating Sections

Let’s enable the Org Speed Keys so that when the cursor is at the beginning of a headline, we can perform fast manipulation & navigation using the standard Emacs movement controls, such as:

  • # toggle COMMENT-ing for an org-header.
  • s toggles “narrowing” to a subtree; i.e., hide the rest of the document.

    If you narrow to a subtree then any export, C-c C-e, will only consider the narrowed detail.

  • I/O clock In/Out to the task defined by the current heading.
    • Keep track of your work times!
    • v view agenda.
  • c for cycling structure below current heading, or C for cycling global structure.
  • i insert a new same-level heading below current heading.
  • w refile current heading; options list pops-up to select which heading to move it to. Neato!
    • g to go to another heading, without refiling anything.
    ;; Refile anywhere 1-level deep in current file,
    ;; or anywhere in my agenda files 2-levels deep
    (setq org-refile-targets '((nil . (:maxlevel . 1))))
          ;; (org-agenda-files . (:maxlevel . 2))  ;; ← Not useful right now.
    
    ; Use full outline paths for refile targets - we file directly with IDO
    ;; When refiling, using Helm, show me the hierarchy paths
    (setq org-outline-path-complete-in-steps nil)
    (setq org-refile-use-outline-path 'file-path)
        
  • t/,/:/e to add a TODO state, priority level, tag, or effort estimate
  • ^ sort children of current subtree; brings up a list of sorting options.
  • n/p for next/previous visible heading.
  • f/b for jumping forward/backward to the next/previous same-level heading.
  • u for going to upwards to parent heading
  • D/U move a heading down/up.
  • L/R recursively promote (move leftwards) or demote (more rightwards) a heading.
  • 1/2/3 to mark a heading with priority, highest to lowest.
  • k/@/a to kill or mark or archive the current subtree
  • o to open a link mentioned in the subtree then go to the link; a pop-up of links appears.

We can add our own speed keys by altering the org-speed-commands-user association list variable.

⇒ Moreover, ? to see a complete list of keys available. ⇐

(setq org-use-speed-commands t)

Seamless Navigation Between Source Blocks

The “super key” —aka the command or windows key— can be used to jump to the previous, next, or toggle editing org-mode source blocks.

;; Overriding keys for printing buffer, duplicating gui frame, and isearch-yank-kill.
;;
(use-package org
  :bind (:map org-mode-map
              ("s-p" . org-babel-previous-src-block)
              ("s-n" . org-babel-next-src-block)
              ("s-e" . org-edit-src-code)
         :map org-src-mode-map
              ("s-e" . org-edit-src-exit)))

Interestingly, s-l is “goto line”.

Modifying <return>

  • C-RET, C-S-RET make a new heading where the latter marks it as a TODO.
  • By default M-RET makes it easy to work with existing list items, headings, tables, etc by creating a new item, heading, etc.

Usually we want a newline then we indent, let’s make that the default.

(add-hook 'org-mode-hook '(lambda ()
   (local-set-key (kbd "<return>") 'org-return-indent))
   (local-set-key (kbd "C-M-<return>") 'electric-indent-just-newline))

Notice that I’ve also added another kind of return, for when I want to break-out of the indentation approach and start working at the beginning of the line.

In summary:

keymethodbehaviour
<return>org-return-indentNewline with indentation
M-<return>org-meta-returnNewline with new org item
C-M-<return>electric-indent-just-newlineNewline, cursor at start
C-<return>org-insert-heading-respect-contentNew heading after current content
C-S-<return>org-insert-todo-heading-respect-contentDitto, but with a TODO marker

C-a,e,k and Yanking of sections

On an org-heading, C-a goes to after the star, heading markers. To use speed keys, run C-a C-a to get to the star markers.

C-e goes to the end of the heading, not including the tags.

(setq org-special-ctrl-a/e t)

C-k no longer removes tags, if activated in the middle of a heading’s name.

(setq org-special-ctrl-k t) ;; MA: Does not work …!

When you yank a subtree and paste it alongside a subtree of depth ‘d’, then the yanked tree’s depth is adjusted to become depth ‘d’ as well. If you don’t want this, then refile instead of copy-pasting.

(setq org-yank-adjusted-subtrees t)

Hiding Emphasise Markers & Inlining Images

Let’s make some things prettier than they appear by default.

;; org-mode math is now highlighted ;-)
(setq org-highlight-latex-and-related '(latex))

;; Hide the *,=,/ markers
(setq org-hide-emphasis-markers t)

;; (setq org-pretty-entities t)
;; to have \alpha, \to and others display as utf8
;; http://orgmode.org/manual/Special-symbols.html

Org pretty entities seems rather impressive —=M-x org-entities-help= to see all possibilities, or add your own. I’m already using the Agda input method, so I wont use Org’s —Agda’s gives me a tiny menu narrowing possibilities as I type.

The following is now disabled —it makes my system slower than I’d like.

;; Let's set inline images.
(setq org-display-inline-images t)
(setq org-redisplay-inline-images t)
(setq org-startup-with-inline-images "inlineimages")

;; Automatically convert LaTeX fragments to inline images.
(setq org-startup-with-latex-preview t)

Org-Emphasise for Parts of Words

From stackoverflow, the following incantation allows us to have parts of works emphasied with org-mode; e.g., /half/ed, ~half~ed, and right in the m*idd*le! Super cool stuff!

(setcar org-emphasis-regexp-components " \t('\"{[:alpha:]")
(setcar (nthcdr 1 org-emphasis-regexp-components) "[:alpha:]- \t.,:!?;'\")}\\")
(org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)

I’ve disabled this feature since multiple occurrences of an emphasise marker are sometimes treated as one lengthy phrase being emphasised.

Proportional fonts for Headlines

Let’s have headings stick out a bit.

  • The larger headings are cute and reminicint of word processors, but having headings coloured is enough —the larger size is too much.
(set-face-attribute 'org-document-title nil :height 2.0)
;; (set-face-attribute 'org-level-1 nil :height 1.0)
;; Remaining org-level-𝒾 have default height 1.0, for 𝒾 : 1..8.
;;
;; E.g., reset org-level-1 to default.
;; (custom-set-faces '(org-level-1 nil))

Remember you can always use Emacs’ Custom utility to get Lisp incantations ;-) —See notes on Custom above.

Show off-screen heading at the top of the window

In case we forgot which heading we’re under, let’s keep the current heading stuck at the top of the window.

(use-package org-sticky-header
 :hook (org-mode . org-sticky-header-mode)
 :config
 (setq-default
  org-sticky-header-full-path 'full
  ;; Child and parent headings are seperated by a /.
  org-sticky-header-outline-path-separator " / "))

Jumping without hassle

(defun my/org-goto-line (line)
  "Go to the indicated line, unfolding the parent Org header.

   Implementation: Go to the line, then look at the 1st previous
   org header, now we can unfold it whence we do so, then we go
   back to the line we want to be at.
  "
  (interactive "nEnter line: ")
  (goto-line line)
  (org-previous-visible-heading 1)
  (org-cycle)
  (goto-line line))

Folding within a subtree

(defun my/org-fold-current-subtree-anywhere-in-it ()
  "Hide the current heading, while being anywhere inside it."
  (interactive)
  (save-excursion
    (org-narrow-to-subtree)
    (org-shifttab)
    (widen)))

(add-hook 'org-mode-hook '(lambda ()
  (local-set-key (kbd "C-c C-h") 'my/org-fold-current-subtree-anywhere-in-it)))

Making Block Delimiters Less Intrusive

Let us render Org-mode’s #+begin_src and #+end_src less obtrusively by, e.g., having the former render as a pencil marker ✎ and the latter as a tombstone □ —reminiscent of Halmos’ QED end-of-proof marker. His setup also accounts for quotes.

⟪ Incantation Omitted —Visit Rasmus Roulund’s site & copy-paste it, if you wish ⟫

(add-hook 'org-mode-hook #'rasmus/org-prettify-symbols)
(org-mode-restart)

His development relies on built-in prettify-symbols-mode, which disguises strings in a buffer for the sake of readability or aesthetics. Following the example in the documentation, C-h f prettify-symbols-mode, we can quickly approximate his efforts for example blocks as follows, however a main issue is that source blocks have busybodied headers which his setup disguises as ‘≡’.

(global-prettify-symbols-mode)

(defvar my/prettify-alist nil
  "Musa's personal prettifications.")

(loop for pair in '(;; Example of how pairs like this to beautify org block delimiters
                    ("#+begin_example" . (?ℰ (Br . Bl) ?⇒)) ;; ℰ⇒
                    ("#+end_example"   . ?⇐)                 ;; ⇐
                    ;; Actuall beautifications
                    ("<=" . ?≤) (">=" . ?≥)
                    ("->" . ?→) ("-->". ?⟶) ;; threading operators
                    ("[ ]" . ?□) ("[X]" . ?☑) ("[-]" . ?◐)) ;; Org checkbox symbols

      do (push pair my/prettify-alist))

(loop for hk in '(text-mode-hook prog-mode-hook org-mode-hook)
      do (add-hook hk (lambda ()
                        (setq prettify-symbols-alist
                              (append my/prettify-alist prettify-symbols-alist)))))

See “Mathematical Notation in Emacs” for how such prettifications can make verbose (Python) scripts much more readable by employing more economical disguises.

A nice sanity:

;; Un-disguise a symbol when cursour is inside it or at the right-edge of it.
(setq prettify-symbols-unprettify-at-point 'right-edge)

Org-mode’s <𝒳 Block Expansions

In org-mode we type <X TAB to obtain environment templates, such as <s for source blocks or <q for quote blocks. It seems recent changes to the org-mode structure template expansion necessitate explicitly loading org-tempo.

(require 'org-tempo)

To insert source blocks with the assistance of a pop-up: C-c C-v d ;-) Perhaps more usefully, invoking within a source block splits it up into two separate blocks! Moreover, if invoked on a selected region, it puts the region into a new code block! Wow!

  • C-c C-,~ refers to ~org-insert-structure-template, which provides non-source blocks, such as quote <q, comment <C, center <c, notes <n, examples <e, and <l and <h and <a for LaTeX and HTML and ASCII export blocks.
    • <X allows you to obtain the org-block assigned to shortcut X.
    • The contents of comment blocks are ignored upon export.
  • C-c C-v C-d and C-c C-v d refer to the org-babel-demarcate-block, which provides source blocks.
We shall improve upon this system below using snippets.

E.g., s_em TAB to obtain an org-src block marked with emacs-lisp as the language. This saves us a few key strokes.

Executing all #+name: startup-code for local configurations

Sometimes my Org-files contain configurations that are local to the file, so I name all such src blocks #+name: startup-code and place #-*- eval: (my/execute-startup-blocks) -*- at the top of the file so that such blocks are evaluated when the file opens up.

  • The -*- ... -*- notation is for making local configurations.
  • Use M-x add-file-local-variable-prop-line to have them inserted interactively.
(defun my/execute-startup-blocks ()
  "Execute all startup blocks, those named ‘startup-code’."
  (interactive)
  (save-excursion
    (goto-char 0)
    (while (ignore-errors (re-search-forward "^\\#\\+name: startup-code"))
      (org-babel-execute-src-block))))

The following setup enables this feature in a safe fashion —e.g., we do not want to avoid evaluating a random person’s potentially dangerous code when we only want to look at it.

;; Please ask me on a file by file basis whether its local variables are ‘safe’
;; or not. Use ‘!’ to mark them as permanently ‘safe’ to avoid being queried
;; again for the same file.
(setq enable-local-variables t)

I have been using a combination of (org-babel-goto-named-src-block ⋯) in multi-line local-variable declarations —=M-x add-file-local-variable-prop=— for a while in many files using a dedicated * footer :noexport: section, but this new approach frees from having such sections and instead to having a single line at the top of the file. Moreover, being at the top of the file, such a line is a nice ‘in your face’ reminder that there is local configuration that should have been loaded.

  • E.g., this init file has local configuration for making the corresponding init.el file and generating the README.org file.

Org-Mode ⇒ PDF & HTML

In this section we consider the Org-mode exporters for PDFs and HTMLs. For example, we account for LaTeX citations and reliable HTML anchors.

Working with Citations

An exquisite system for handling references.

The following entity will display useful data when the mouse hovers over it (•̀ᴗ•́)و If you click on it, then you’re in for a lot of super neat stuff, such as searching for the pdf online!

cite:agda_overview

(use-package org-ref
  :custom ;; Files to look at when no “╲bibliography{⋯}” is not present in a file.
          ;; Most useful for non-LaTeX files.
        (reftex-default-bibliography '("~/thesis-proposal/papers/References.bib"))
        (bibtex-completion-bibliography (car reftex-default-bibliography))
        (org-ref-default-bibliography reftex-default-bibliography))

;; Quick BibTeX references, sometimes.
(use-package helm-bibtex)
(use-package biblio)

Execute M-x helm-bibtex or C-c ] and, say, enter emacs and you will be presented with all the entries in the bib database that mention ‘emacs’. Super cool stuff. Moreover, if no such entries exist, then we can look some up using the interface!

Read the manual online or better yet as an org-file with M-x org-ref-help.

This is an Org-mode application since the citations have tooltips and export nicely to LaTeX & HTML via the Org-mode exporter.

Bibliography & Coloured LaTeX using Minted

Execute the following for bibliography references as well as minted Org-mode uses the Minted package for source code highlighting in PDF/LaTeX —which in turn requires the pygmentize system tool.

(setq org-latex-listings 'minted
      org-latex-packages-alist '(("" "minted"))
      org-latex-pdf-process
      '("pdflatex -shell-escape -output-directory %o %f"
        "biber %b"
        "pdflatex -shell-escape -output-directory %o %f"
        "pdflatex -shell-escape -output-directory %o %f"))

For faster pdf generation, possibly with errors, consider invoking:

(setq org-latex-pdf-process
      '("pdflatex -interaction nonstopmode -output-directory %o %f"))

By default, Org exports LaTeX using the nonstopmode option, which tries its best to produce a PDF —which ignores typesetting errors altogether, which is not necessary ideal when using LaTeX.

Ensuring Useful HTML Anchors

Upon HTML export, each tree heading is assigned an ID to be used for hyperlinks. Default IDs are something like org1957a9d, which does not endure the test of time: Re-export will produce a different id. Here’s a rough snippet to generate IDs from headings, by replacing spaces with hyphens, for headings without IDs.

(defun my/ensure-headline-ids (&rest _)
  "Org trees without a

All non-alphanumeric characters are cleverly replaced with ‘-’.

If multiple trees end-up with the same id property, issue a
message and undo any property insertion thus far.

E.g., ↯ We'll go on a ∀∃⇅ adventure
   ↦  We'll-go-on-a-adventure
"
  (interactive)
  (let ((ids))
    (org-map-entries
     (lambda ()
       (org-with-point-at (point)
         (let ((id (org-entry-get nil "CUSTOM_ID")))
           (unless id
             (thread-last (nth 4 (org-heading-components))
               (s-replace-regexp "[^[:alnum:]']" "-")
               (s-replace-regexp "-+" "-")
               (s-chop-prefix "-")
               (s-chop-suffix "-")
               (setq id))
             (if (not (member id ids))
                 (push id ids)
               (message-box "Oh no, a repeated id!\n\n\t%s" id)
               (undo)
               (setq quit-flag t))
             (org-entry-put nil "CUSTOM_ID" id))))))))

;; Whenever html & md export happens, ensure we have headline ids.
(advice-add 'org-html-export-to-html   :before 'my/ensure-headline-ids)
(advice-add 'org-md-export-to-markdown :before 'my/ensure-headline-ids)

One may then use [[#my-custom-id]] to link to the entry with CUSTOM_ID property my-custom-id.

Interestingly, org-set-property, C-c C-x p, lets us insert a property from a selection of available ones, then we’ll be prompted for a value for it from a list of values you’ve used elsewhere. This is useful for remaining consistent for when trees share similar properties.

Clickable Headlines

By default, HTML export generates ID’s to headlines so they may be referenced to, but there is no convenient way to get at them to refer to a particular heading. The following spell fixes this issue: Headlines are now clickable, resulting in a link to the headline itself.

;; Src: https://writepermission.com/org-blogging-clickable-headlines.html
(setq org-html-format-headline-function
(lambda (todo todo-type priority text tags info)
  "Format a headline with a link to itself."
  (let* ((headline (get-text-property 0 :parent text))
         (id (or (org-element-property :CUSTOM_ID headline)
                 (org-export-get-reference headline info)
                 (org-element-property :ID headline)))
         (link (if id
                   (format "<a href=\"#%s\">%s</a>" id text)
                 text)))
     (org-html-format-headline-default-function todo todo-type priority link tags info))))

HTML “Folded Drawers”

(defun my/org-drawer-format (name contents)
  "Export to HTML the drawers named with prefix ‘fold_’, ignoring case.

The resulting drawer is a ‘code-details’ and so appears folded;
the user clicks it to see the information therein.
Henceforth, these are called ‘fold drawers’.

Drawers without such a prefix may be nonetheless exported if their
body contains ‘:export: t’ ---this switch does not appear in the output.
Thus, we are biased to generally not exporting non-fold drawers.

One may suspend export of fold drawers by having ‘:export: nil’
in their body definition.

Fold drawers naturally come with a title.
Either it is specfied in the drawer body by ‘:title: ⋯’,
or otherwise the drawer's name is used with all underscores replaced
by spaces.
"
  (let* ((contents′ (replace-regexp-in-string ":export:.*\n?" "" contents))
         (fold? (s-prefix? "fold_" name 'ignore-case))
         (export? (string-match ":export:\s+t" contents))
         (not-export? (string-match ":export:\s+nil" contents))
         (title′ (and (string-match ":title:\\(.*\\)\n" contents)
                      (match-string 1 contents))))

    ;; Ensure we have a title.
    (unless title′ (setq title′ (s-join " " (cdr (s-split "_" name)))))

    ;; Output
    (cond
     ((and export? (not fold?)) contents′)
     (not-export? nil)
     (fold?
      (thread-last contents′
        (replace-regexp-in-string ":title:.*\n" "")
        (format "<details class=\"code-details\"> <summary> <strong>
            <font face=\"Courier\" size=\"3\" color=\"green\"> %s
            </font> </strong> </summary> %s </details>" title′))))))

(setq org-html-format-drawer-function 'my/org-drawer-format)

With the following invocations we only see the odd indexed ‘hello’s, where the latter two are folded up.

:this-drawer-is-exported:
:export: t
hello 1
:End:

:this-drawer-is-NOT-exported:
hello 2
:End:

:fold_This_drawer_has_a_title_in_the_body:
:title: I am the drawer title 0

hello 3
:End:

:fold_This_drawer_is_NOT_exported:
:title: Why are we here?
:export: nil

hello 4
:End:

:fold_I_am_the_drawer_title_1:

hello 5
:End:

I doubt I could show an example in the Github README, since no HTML export is happening using my setup. In case you’re reading this on my blog, which has exported HTML. Here’s the example: Now that I’ve written this, I’m thinking it may have been preferably to use an org-block…?

Reveal.JS – The HTML Presentation Framework

Org-mode documents can be transformed into beautiful slide decks with org-reveal with the following two simple lines.

(use-package ox-reveal :defer t
  :custom (org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"))

For example, execute, C-x C-e after the closing parenthesis of, the following block to see an example slide-deck (─‿‿─)

(progn (shell-command "curl https://raw.githubusercontent.com/yjwen/org-reveal/696613edef0fe17a9c53146f79933fe7c4101100/Readme.org >> Trying_out_reveal.org")
       (switch-to-buffer (find-file "Trying_out_reveal.org"))
       (org-reveal-export-to-html-and-browse))

Org-mode exporting, C-c C-e, now includes an option R for such reveal slide decks.

Two dimensional slides may be a bit new to some people, so I like to give viewers an option, in tiny font, to view the slide-deck continuously and remind them that ? provides useful shortcuts.

(setq org-reveal-title-slide "<h1>%t</h1> <h3>%a</h3>
<font size=\"1\">
<a href=\"?print-pdf&showNotes=true\">
⟪ Flattened View ; Press <code>?</code> for Help ⟫
</a>
</font>")

One should remove the &showNotes=true if they do not want to include speaker notes in the flattened view.

Within the flatenned view, one may wish to CTRL/CMD+P then save the resulting PDF locally.

Org-mode ⇐ HTML

The following let’s us copy htlm into org format using eww, Emacs’ built-in web browser.

;; See: https://emacs.stackexchange.com/questions/7171/paste-html-into-org-mode
(use-package org-eww
 :quelpa (org-eww :fetcher git :url "https://github.com/Fuco1/org-mode.git"))

It does not work as I’d like, but may prove useful to have around.

  • Possibly useful: Open a webpage with M-x eww then toggle M-x read-only-mode to edit the text, say for notes or deletions, as you read! No need to copy-paste.

Life within Org-mode

It’s hard to estimate how long a task takes if you don’t keep ‘clock-in and clock-out’ of tasks. We can ‘capture’ todos right in the middle of a task without context-switching; e.g., no opening a todos file! After some reflection on the relative importance of the tasks, we can schedule them into our ‘agenda’.

Let’s do this!

Using Org-Mode as a Day Planner

⟪ This section is based on a dated, yet delightful, tutorial of the same title by John Wiegley. ⟫

We want a day-planner with the following use:

  1. “Mindlessly” & rapidly create new tasks.
  2. Schedule and archive tasks at the end, or start, of the work day.
  3. Glance at a week’s tasks, shuffle if need be.
  4. Prioritise the day’s tasks. Aim for ≤15 tasks.
  5. Progress towards completion of A tasks by documenting work completed.
  6. Repeat! During the day, if anything comes up, capture it and intentionally forget about it.

Capturing ideas & notes without interrupting the current workflow

Capture lets me quickly make notes & capture ideas, with associated reference material, without any interruption to the current work flow. Without losing focus on what you’re doing, quickly jot down a note of something important that just came up.

E.g., I have a task, or something I wish to note down, rather than opening some file, then making a heading, then writing it; instead, I press C-c c t and a pop-up appears, I make my note, and it disappears —with my notes file(s) now being altered! Moreover, by default it provides a timestamp and a link to the file location where I made the note —helpful for tasks, tickets, to be tackled later on.

;; Location of my todos/notes file
(setq org-default-notes-file "~/Dropbox/todo.org")

;; “C-c c” to quickly capture a task/note
(define-key global-map "\C-cc" #'my/org-capture) ;; See below.

⇒ Org capture actually lets us add any type of entry, ‘programmable template’, to any type of file! ⇐

( For now, I’m only using it to add entries to my tasks lists. )

By default we only get a ‘tasks’ form of capture, let’s add some more.

(cl-defun my/make/org-capture-template
   (shortcut heading &optional (no-todo nil) (description heading) (scheduled nil))
  "Quickly produce an org-capture-template.

  After adding the result of this function to ‘org-capture-templates’,
  we will be able perform a capture with “C-c c ‘shortcut’”
  which will have description ‘description’.
  It will be added to the tasks file under heading ‘heading’.

  ‘no-todo’ omits the ‘TODO’ tag from the resulting item; e.g.,
  when it's merely an interesting note that needn't be acted upon.

  Default for ‘description’ is ‘heading’. Default for ‘no-todo’ is ‘nil’.

  Scheduled items appear in the agenda; true by default.

  The target is ‘file+headline’ and the type is ‘entry’; to see
  other possibilities invoke: C-h o RET org-capture-templates.
  The “%?” indicates the location of the Cursor, in the template,
  when forming the entry.
  "
  `(,shortcut ,description entry
      (file+headline org-default-notes-file ,heading)
         ,(concat "*" (unless no-todo " TODO") " %?\n"
                (when nil ;; this turned out to be a teribble idea.
                  ":PROPERTIES:\n:"
                (if scheduled
                    "SCHEDULED: %^{Any time ≈ no time! Please schedule this task!}t"
                  "CREATED: %U")
                "\n:END:") "\n\n ")
      :empty-lines 1 :time-prompt t))

(setq org-capture-templates
      (loop for (shortcut heading)
            in (-partition 2 '("t" "Tasks, Getting Things Done"
                               "r" "Research"
                               "2" "2FA3"
                               "m" "Email"
                               "e" "Emacs (•̀ᴗ•́)و"
                               "i" "Islam"
                               "b" "Blog"
                               "a" "Arbitrary Reading and Learning"
                               "l" "Programming Languages"
                               "p" "Personal Matters"))
            collect  (my/make/org-capture-template shortcut heading)))

;; Update: Let's schedule tasks during the GTD processing phase.
;;
;; For now, let's automatically schedule items a week in advance.
;; TODO: FIXME: This overwrites any scheduling I may have performed.
;; (defun my/org-capture-schedule ()
;;   (org-schedule nil "+7d"))
;;
;; (add-hook 'org-capture-before-finalize-hook 'my/org-capture-schedule)

For now I capture everything into a single file. One would ideally keep separate client, project, information in its own org file.

Rather than adding notes to particular Org headings in my todo.org file, I could defer such a choice by having only one template and have C-c a automatically use it. Then I could ‘refile’ tasks to their appropriate parent headings with w. This allows us to seperate the concerns of capturing ideas from doing any form of processing. Something to consider.

  • Again: Looking at my/make/org-capture-template, one notices that capture actually lets you add any type of item to any file.

Let’s also ensure TODO-s respect hierarchical structure.

;; Cannot mark an item DONE if it has a  TODO child.
;; Conversely, all children must be DONE in-order for a parent to be DONE.
(setq org-enforce-todo-dependencies t)

Where am I currently capturing?

  • During meetings, when a nifty idea pops into my mind, I quickly capture it.
    • I’ve found taking my laptop to meetings makes me an active listener and I get much more out of my meetings since I’m taking notes.
  • Through out the day, as I browse the web, read, and work; random ideas pop-up, and I capture them indiscriminately.
  • I envision that for a phone call, I would open up a capture to make note of what the call entailed so I can review it later.
  • Anywhere you simply want to make a note, for the current heading, just press C-c C-z. The notes are just your remarks along with a timestamp; they are collected at the top of the tree, under the heading.
    ;; Ensure notes are stored at the top of a tree.
    (setq org-reverse-note-order nil)
        

Yet another place to capture content is from mail, such as for reference material, or self-contained tasks. See above for this discussion.

(cl-defun my/org-capture-buffer (&optional keys no-additional-remarks
                                           (heading-regexp "Subject: \\(.*\\)"))
  "Capture the current [narrowed] buffer as a todo/note.

This is mostly intended for capturing mail as todo tasks ^_^

When NO-ADDITIONAL-REMARKS is provided, and a heading is found,
then make and store the note without showing a pop-up.
This is useful for when we capture self-contained mail.

The HEADING-REGEXP must have a regexp parenthesis construction
which is used to obtain a suitable heading for the resulting todo/note."
  (interactive "P")
  (let* ((current-content (substring-no-properties (buffer-string)))
         (heading         (progn (string-match heading-regexp current-content)
                                 (or (match-string 1 current-content) ""))))
    (org-capture keys)
    (insert heading "\n\n\n\n" (s-repeat 80 "-") "\n\n\n" current-content)

    ;; The overtly verbose conditions are for the sake of clarity.
    ;; Moreover, even though the final could have “t”, being explicit
    ;; communicates exactly the necessary conditions.
    ;; Being so verbose leads to mutual exclusive clauses, whence order is irrelevant.
    (cond
     ((s-blank? heading)
        (beginning-of-buffer) (end-of-line))
     ((and no-additional-remarks (not (s-blank? heading)))
        (org-capture-finalize))
     ((not (or no-additional-remarks (s-blank? heading)))
        (beginning-of-buffer) (forward-line 2) (indent-for-tab-command)))))

With that in-hand, we use a wrapper to org-capture to make use of it.

(defun my/org-capture (&optional prefix keys)
  "Capture something!

      C-c c   ⇒ Capture something; likewise for “C-uⁿ C-c c” where n ≥ 3.
C-u   C-c c   ⇒ Capture current [narrowed] buffer.
C-u 5 C-c c   ⇒ Capture current [narrowed] buffer without adding additional remarks.
C-u C-u C-c c ⇒ Goto last note stored."
  (interactive "p")
  (case prefix
    (4     (my/org-capture-buffer keys))
    (5     (my/org-capture-buffer keys :no-additional-remarks))
    (t     (org-capture prefix keys))))
  • Org-protocol is a way to create capture notes in org-mode from other applications.

Anyhow…

Step 1: When new tasks come up

Isn’t it great that we can squirrel away info into some default location then immediately return to what we were doing before —with speed & minimal distraction! heartshearts Indeed, if our system for task management were slow then we may not produce tasks and so forget them altogether! щ(゜ロ゜щ)

  • Entering tasks is a desirably impulsive act; do not make any further scheduling considerations.

    The next step, the review stage occurring at the end or the start of the workday, is for processing.

The reason for this is that entering new tasks should be impulsive, not reasoned. Your reasoning skills are required for the task at hand, not every new tidbit. You may even find that during the few hours that transpire between creating a task and categorizing it, you’ve either already done it or discovered it doesn’t need to be done at all! —John Wiegley

When my computer isn’t handy, I’ll make a note on my phone then transfer it later.

Step 2: Filing your tasks

At a later time, a time of reflection, we go to our tasks list and actually schedule time to get them done by C-c C-s then pick a date by entering a number in the form +𝓃 to mean that task is due 𝓃 days from now.

  • Tasks with no due date are ones that “could happen anytime”, most likely no time at all.
  • At least schedule tasks reasonably far off in the future, then reassess when the time comes.
  • An uncompleted task is by default rescheduled to the current day, each day, along with how overdue it is.
    • Aim to consciously reschedule such tasks!

    With time, it will become clear what is an unreasonable day verses what is an achievable day.

Repeat tasks by a repeater such as ‘+1m’ or ‘+7d’ in their timestamps; e.g., DEADLINE: <2005-10-01 Sat +1m>.

A ‘project’ is a task that has multiple steps, each as a checkbox item. It can be given a percentage marker to show progress: Place [%] after its name, then press C-c # on the name to see a completion percentage —press C-c C-c on a checkbox item to toggle its completion state.

Let’s keep track of how many times, and when, we have pushed events to other dates.

;; Add a note whenever a task's deadline or scheduled date is changed.
(setq org-log-redeadline 'time)
(setq org-log-reschedule 'time)

Step 3: Quickly review the upcoming week

The next day we begin our work, we press C-c a a to see the scheduled tasks for this week —~C-c C-s~ to re-schedule the task under the cursor and r to refresh the agenda.

(define-key global-map "\C-ca" 'org-agenda)
  • Show the next 𝓃 days schedule ⇐ C-u 𝓃 C-c a a.

The next section, Super Agenda, will discuss acting on entries in the agenda buffer.

Step 4: Getting ready for the day

After having seen our tasks for the week, we press d to enter daily view for the current day. Now we decide whether the items for today are A: of high urgency & important; B: of moderate urgency & importance; or C: Pretty much optional, or very quick or fun to do.

  • A tasks should be both important and urgently done on the day they were scheduled.
    • Such tasks should be relatively rare!
    • If you have too many, you’re anxious about priorities and rendering priorities useless.
  • C tasks can always be scheduled for another day without much worry.
    • Act! If the thought of rescheduling causes you to worry, upgrade it to a B or A.
  • As such, most tasks will generally be priority B: Tasks that need to be done, but the exact day isn’t as critical as with an A task. These are the “bread and butter” tasks that make up your day to day life.

On a task item, or any org-heading, press ~,~ then one of A, B, C to set its priority. Then r to refresh.

Step 5: Doing the work

Since A tasks are the important and urgent ones, if you do all of the A tasks and nothing else today, no one would suffer. It’s a good day (─‿‿─).

There should be no scheduling nor prioritising at this stage. You should not be touching your tasks file until your next review session: Either at the end of the day or the start of the next.

  • Leverage priorities! E.g., When a full day has several C tasks, reschedule them for later in the week without a second thought.
    • You’ve already provided consideration when assigning priorities.

Step 6: Moving a task toward completion

My workflow states are described in the section Workflow States and contain states: TODO, STARTED, WAITING, ON_HOLD, CANCELLED, DONE.

  • Tasks marked WAITING are ones for which we are awaiting some event, like someone to reply to our query. As such, these tasks can be rescheduled until I give up or the awaited event happens —in which case I go to STARTED and document the reply to my query.
  • The task may be put off indefinitely with ON_HOLD, or I may choose never to do it with CANCELLED. Along with DONE, these three mark a task as completed and so it needn’t appear in any agenda view.

I personally clock-in and clock-out of tasks —keep reading—, where upon clocking-out I’m prompted for a note about what I’ve accomplished so far. Entering a comment about what I’ve done, even if it’s very little, feels like I’m getting something done. It’s an explicit marker of progress.

In the past, I would make a “captain’s log” at the end of the day, but that’s like commenting code after it’s written, I didn’t always feel like doing it and it wasn’t that important after the fact. The continuous approach of noting after every clock-out is much more practical, for me at least.

Step 7: Archiving Tasks

During the review state, when a task is completed, ‘archive’ it with C-c C-x C-s: This marks it as done, adds a time stamp, and moves it to a local *.org_archive file. What was our ‘to do’ list becomes a ‘ta da’ list showcasing all we have done (•̀ᴗ•́)و

Archiving keeps task lists clutter free, but unlike deletion it allows us, possibly rarely, to look up details of a task or what tasks were completed in a certain time frame —which may be a motivational act, to see that you have actually completed more than you thought, provided you make and archive tasks regularly. We can use M-x org-search-view to search an org file and the archive file too, if we enable it so.

;; C-c a s ➩ Search feature also looks into archived files.
;; Helpful when need to dig stuff up from the past.
(setq org-agenda-text-search-extra-files '(agenda-archives))
;; Invoking the agenda command shows the agenda and enables
;; the org-agenda variables.
;; ➩ Show my agenda upon Emacs startup.
(org-agenda "a" "a") ;; Need this to have “org-agenda-custom-commands” defined.

Let’s install some helpful views for our agenda.

  • C-c a c: See completed tasks at the end of the day and archive them.
    ;; Pressing ‘c’ in the org-agenda view shows all completed tasks,
    ;; which should be archived.
    (add-to-list 'org-agenda-custom-commands
      '("c" todo "DONE|ON_HOLD|CANCELLED" nil))
        
  • C-c a u: See unscheduled, undeadlined, and undated tasks in my todo files. Which should then be scheduled or archived.
    (add-to-list 'org-agenda-custom-commands
      '("u" alltodo ""
         ((org-agenda-skip-function
            (lambda ()
                  (org-agenda-skip-entry-if 'scheduled 'deadline 'regexp  "\n]+>")))
                  (org-agenda-overriding-header "Unscheduled TODO entries: "))))
        

At the end of the day, let’s schedule at least 3 things that must be done the next day; i.e., have priority =A=.

Tag! You’re it!

Even when items are categorised under their own parent headings, they may be related in some way and that can made explicit by adding a :tag: to their headings; e.g., two entries both have the :jasim:@work: tags, then looking for the :@work: tag shows me all entries that are tagged as “at work”.

Tags provide a cross-section of one’s entries.

Tags let us find related stuff quickly, even though they’re differently categorised.

After calling ~org-agenda~, we may select ~m~ to match for tags, or use ~org-tags-view~ to search for tags.

What to tag? Common tags are :@laptop:, :@work:, :@home: to identify the location where tasks take place —Use: When I’m at a particular place, I need only consider tasks that apply to that place ;-) Other tags I use are :𝑭𝑳: to identify remarks or email or request from person 𝑭irstname 𝑳astname; or something that might be interesting to that person. I also use ~:video:, book,

:project_name: to identify notes that may be of interest to a particular project, but are more appropriately categorised elsewhere —e.g., when learning about an Emacs feature, I may tag my notes with another project’s name to consider whether that feature could be useful there.

How to tag?

You can just add a :tag₁:⋯:tagₙ: after a heading. If you press space, before the tags, then they are automatically indented flushright to column 77; postive numbers do not flushright but use exact column number.

(setq org-tags-column -77) ;; the default

Use C-c C-q, or org-set-tags-command, on a heading or just the speed key : on the asterisks of a heading to set the tags of an item —as usual, with Helm we obtain a window of all existing tags to select from. Unfortunatley, this only supports having one tag; for more, you can add them in manually or …

(use-package helm-org) ;; Helm for org headlines and keywords completion.
(add-to-list 'helm-completing-read-handlers-alist
             '(org-set-tags-command . helm-org-completing-read-tags))

;; Also provides: helm-org-capture-templates

Now : or C-c C-q will show existing tags for the current heading, press TAB to obtain a list of all exisiting tags, press C-SPC to select the desired tags, then TAB or RET to confirm the resulting tag list, and RET to finish or TAB to select more tags.

Let’s render tags by Unicode symbols.

(use-package org-pretty-tags
  :diminish org-pretty-tags-mode
  :demand t
  :config
   (setq org-pretty-tags-surrogate-strings
         '(("Neato"    . "💡")
           ("Blog"     . "✍")
           ("Audio"    . "♬")
           ("Video"    . "📺")
           ("Book"     . "📚")
           ("Running"  . "🏃")
           ("Question" . "❓")
           ("Wife"     . "💕")
           ("Text"     . "💬") ; 📨 📧
           ("Friends"  . "👪")
           ("Self"     . "🍂")
           ("Finances" . "💰")
           ("Car"      . "🚗") ; 🚙 🚗 🚘
           ("Urgent"   . "🔥"))) ;; 📥 📤 📬
   (org-pretty-tags-global-mode 1))

Pretty Prioritisation Markers

Let’s set four priority levels and their colours: The more intense colours are for more urgent tasks.

(setq org-lowest-priority ?D) ;; Now org-speed-eky ‘,’ gives 4 options
(setq org-priority-faces
'((?A :foreground "red" :weight bold)
  (?B . "orange")
  (?C . "yellow")
  (?D . "green")))
  • ~C-c ,~ anywhere to set the priority of the current heading.
    • We may press A-D or SPC to an remove existing priority.

Priority markers are of the form [#𝒳], the fancy priorities package visually renders them as words or icons.

(use-package org-fancy-priorities
  :diminish t
  :hook   (org-mode . org-fancy-priorities-mode)
  :custom (org-fancy-priorities-list '("HIGH" "MID" "LOW" "OPTIONAL")))

Super Agenda

Org agenda is an interactive tool for generating summary reports from Org data —e.g., commonly, the weekly task list is generated from todo tasks.

The agenda dispatch menu, C-c a, has options for displaying tasks —e.g., C-c a m generates a list of entries having the same tags. new ways to view tasks by altering the org-agenda-custom-commands variable —e.g., above we added two, one for completed tasks and one for unscheduled tasks.

Let’s setup the basics of our agenda.

;; List of all the files & directories where todo items can be found. Only one
;; for now: My default notes file.
(setq org-agenda-files (list org-default-notes-file))

;; Display tags really close to their tasks.
(setq org-agenda-tags-column -10)

;; How many days ahead the default agenda view should look
(setq org-agenda-span 'day)
;; May be any number; the larger the slower it takes to generate the view.
;; One day is thus the fastest ^_^

;; How many days early a deadline item will begin showing up in your agenda list.
(setq org-deadline-warning-days 14)

;; In the agenda view, days that have no associated tasks will still have a line showing the date.
(setq org-agenda-show-all-dates t)

;; Scheduled items marked as complete will not show up in your agenda view.
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-deadline-if-done  t)

The agenda view, like nearly all Emacs entities, is interactive:

  • 𝓃 f,b ⇒ Look forward at next week’s agenda, or backward to a previous week.
    • The optional $𝓃$ means do the action 𝓃-many times; it defaults to 1.
  • w, d ⇒ toggle week view, or day view; use v to see possible views.
    • E.g., C-u 2017 v y shows us the specific year 2017.
  • 𝓃 n,p to navigate to next and previous entries.
  • t ⇒ cycle TODO state of the current entry.
  • ± ⇒ cycle priority state.
  • 𝓃 S-⇆ ⇒ Shift date time by $𝓃$ days; 1 day by default.
  • C-c C-s ⇒ Reschedule an entry; prefix it with C-u to remove a scheduled entry.

    in their timestamps; e.g., DEADLINE: <2005-10-01 Sat +1m>.

  • s ⇒ save all agenda buffers; i.e., save the org-files where the agenda items live.
  • g ⇒ Rebuild agenda according to any changes made thus far.
  • F ⇒ Toggle ‘follow mode’: As you go up/down entries, you can see their details in an adjacent window.
    • SPC ⇒ Show details of a single entry in other window; stay in Agenda.
  • RET, TAB ⇒ Go to the current entry in the current window or in a new adjacent window, so as to alter task details.

The agenda view ––even in the 7-days-at-a-time view–– will always begin on the current day. This is important, since while using org-mode as a day planner, you never want to think of days gone past. That’s something you do in other ways, such as when reviewing completed tasks.

(setq org-agenda-start-on-weekday nil)

Instead of having the day’s tasks all in one field, org-super-agenda allows us to use predicates to group entries together; e.g., by considering an entry’s :tags: or its priority level. Since I’m placing all my tasks in a single file, under appropriate parent headings, I want entries to be shown according to their parent heading. Of-course, the top-most grouping, the important tasks, should be pulled out of their group and placed at the top.

(use-package org-super-agenda
  :hook (org-agenda-mode . origami-mode) ;; Easily fold groups via TAB.
  :bind (:map org-super-agenda-header-map ("<tab>" . origami-toggle-node))
  :config
  (org-super-agenda-mode)
  (setq org-super-agenda-groups
        '((:name "Important" :priority "A")
          (:name "Personal" :habit t)
          ;; For everything else, nicely display their heading hierarchy list.
          (:auto-map (lambda (e) (org-format-outline-path (org-get-outline-path)))))))

;; MA: No noticable effect when using org-super-agenda :/
;;
;; Leave new line at the end of an entry.
;; (setq org-blank-before-new-entry '((heading . t) (plain-list-item . t)))
  • Origami mode —see below in Text Folding with Origami-mode— works well with super-agenda. Just M-x origami-mode then C-c f to enable the folding hydra.

The org-super-agenda homepage shows complex configurations and pleasant screenshots contrasting with and without the system. E.g., you can change how entries in particular headings are displayed and coloured.

Automating Pomodoro —“Commit for only 25 minutes!”

Effort estimates are for an entire task. Yet, sometimes it’s hard to even get started on some tasks.

  • The code below ensures a 25 minute timer is started whenever clocking in happens.
    • The timer is in the lower right of the modeline.
  • When the timer runs out, we get a notification.
  • We may have the momentum to continue on the difficult task, or clock-out and take a break after documenting what was accomplished.
;; Tasks get a 25 minute count down timer
(setq org-timer-default-timer 25)

;; Use the timer we set when clocking in happens.
(add-hook 'org-clock-in-hook
  (lambda () (org-timer-set-timer '(16))))

;; unless we clocked-out with less than a minute left,
;; show disappointment message.
(add-hook 'org-clock-out-hook
  (lambda ()
  (unless (s-prefix? "0:00" (org-timer-value-string))
     (message-box "The basic 25 minutes on this difficult task are not up; it's a shame to see you leave."))
     (org-timer-stop)))

Note that this does not conflict with the total effort estimate for the task.

⟨ I’m told there’s a package already made for this —maybe I need to stop writing good, and do more searches; then again, I’ve learned a lot by writing code. ⟩

Journaling

Thus far I’ve made it easy to quickly capture ideas and tasks, not so much on the analysis phase:

  • What was accomplished today?
  • What are some notably bad habits? Good habits?
  • What are some future steps?

Rather than overloading the capture mechanism for such thoughts, let’s employ org-journal —journal entries are stored in files such as journal/20190407, where the file name is simply the date, or only one file per year as I’ve set it up below. Each entry is the week day, along with the date, then each child tree is an actual entry with a personal title preceded by the time the entry was made. Unlike capture and its agenda support, journal ensures entries are maintained in chronological order with calendar support.

Since org files are plain text files, an entry can be written anywhere and later ported to the journal. Or, written directly in the journal file if we add the necessary Org-header: Asterisks and time.

The separation of concerns is to emphasise the capture stage as being quick and relatively mindless, whereas the journaling stage as being mindful. Even though we may utilise capture to provide quick support for including journal entries, I have set my journal to be on a yearly basis —one file per year— since I want to be able to look at previous entries when making the current entry; after all, it’s hard to compare and contrast easily unless there’s multiple entries opened already.

As such, ideally at the end of the day, I can review what has happened, and what has not, and why this is the case, and what I intend to do about it, and what problems were encountered and how they were solved —in case the problem is encountered again in the future. *Consequently, if I encounter previously confronted situations, problems,* all I have to do is reread my journal to get an idea of how to progress. Read more about the importance of reviewing your day on a daily basis.

Moreover, by journaling with Org on a daily basis, it can be relatively easy to produce a report on what has been happening recently, at work for example. I’d like to have multiple journals, for work and for personal life, as such I will utilise a prefix argument to obtain my work specific entries.

The Setup

Anyhow, the setup:

(defun my/org-journal-new-entry (prefix)
  "Open today’s journal file and start a new entry.

  With a prefix, we use the work journal; otherwise the personal journal."
  (interactive "P")
  (-let [org-journal-file-format (if prefix "Work-%Y-%m-%d" org-journal-file-format)]
    (org-journal-new-entry nil)
    (org-mode)
    (org-show-all)))

(use-package org-journal
  ;; C-u C-c j ⇒ Work journal ;; C-c C-j ⇒ Personal journal
  :bind (("C-c j" . my/org-journal-new-entry))
  :config
  (setq org-journal-dir         "~/Dropbox/journal/"
        org-journal-file-type   'yearly
        org-journal-file-format "Personal-%Y-%m-%d"))

Super Terse Tutorial

Bindings available in org-journal-mode, when journaling:

  • C-c C-j: Insert a new entry into the current journal file.
    • Note that keys for org-journal-new-entry shadow those for org-goto.
  • C-c C-s: Search the journal for a string.
    • Note that keys for org-journal-search shadow those for org-schedule.

All journal entries are registered in the Emacs Calendar. To see available journal entries do M-x calendar. Bindings available in the calendar-mode:

  • j: View an entry in a new buffer.
  • i j: ‘I’nsert a new ‘j’ournal entry into the day’s file.
  • f w/m/y/f/F: ‘F’ind, search, in all entries of the current week, month, year, all of time, of in all entries in the future.

Guided Journaling

Sometimes it can be tough to journal, but filling in a template can be a way to get started. Later on, we will setup Snippets —Template Expansion which will allow us to write journal_guided then TAB to obtain the template below. Each $𝓃 indicates a position that we may input text, after which we TAB to move to next location.

Just like the undo-tree setup at the start of this read, we use a noweb-ref to present this template in a natural position; then later when template expansion it setup, we request it to be tangled.

** journal_guided: Introspection & Growth
I'm writing from ${1:location}.

Gut answer, today I feel ${2:scale}/10.
⇒ ${3:Few words or paragraphs to explain what's on your mind.}

${4: All things which cause us to groan or recoil are part of the tax of
life. These things you should never hope or seek to escape.  Life is a battle,
and to live is to fight.

⟨ Press TAB once you've read this mantra. ⟩
$(when yas-moving-away-p "")
}
`(progn
  (eww "https://www.dailyinspirationalquotes.in/")
  (sit-for 2) (when nil let eww load)
  (read-only-mode -1)
  (goto-line 52)
  (kill-line)
  (kill-buffer)
  (yank))`
${7:
Self Beliefs:
+ I am working on a healthier lifestyle, including a low-carb diet.

  - I’m also investing in a healthy, long-lasting relationship.

  ➩ These are what I want and are important to me. ⇦

+ I will not use any substances to avoid real issues in my life. I must own them.

+ Everything I’m searching for is already inside of me.

+ Progress is more important than perfection.

⟨ Press TAB once you've read these beliefs. ⟩
$(when yas-moving-away-p "")
}

*Three things I'm grateful for:*
1. ${8:??? … e.g., old relationship, something great yesterday, an opportunity I
   have today, something simple near me within sight}
2. ${9:??? … e.g., old relationship, something great yesterday, an opportunity I
   have today, something simple near me within sight}
3. ${10:??? … e.g., old relationship, something great yesterday, an opportunity I
   have today, something simple near me within sight}

*Three things that would make today great:*
1. ${11:???}
2. ${12:???}
3. ${13:???}

*What one thing is top of mind today?*
${14:???}

*What’s one opportunity I want to go after?*
${15:???}

*What’s one thing I’m really proud of OR I’m amazed and in awe of?*
${16:???}

$0

Besides a bit of webscraping to obtain a daily inspirational quote image, and the necessary yasnippet code, this template was taken from a discussion on Hacker news: “I find journaling indispensable”. In time, I will likely alter it to meet my needs, but I like it as it is right now (•̀ᴗ•́)و

Workflow States

Here are some of my common workflow states, —the ‘X/Y’ indicates to do action ‘X’ when entering a state and ‘Y’ when leaving it, with ‘!’ denoting a timestamp should be generated and ‘@’ denoting a user note should be made.

(setq org-todo-keywords
      '((sequence "TODO(t)" "STARTED(s@/!)" "|" "DONE(d/!)")
        (sequence "WAITING(w@/!)" "ON_HOLD(h@/!)" "|" "CANCELLED(c@/!)")))

;; Since DONE is a terminal state, it has no exit-action.
;; Let's explicitly indicate time should be noted.
(setq org-log-done 'time)

The @ brings up a pop-up to make a local note about why the state changed. Super cool stuff!

In particular, we transition from TODO to STARTED once 15 minutes, or a reasonable amount, of work has transpired. Since all but one state are marked for logging, we could use the lognotestate logging facility of org-mode, which prompts for a note every time a task’s state is changed.

Entering a comment about what I’ve done, even if it’s very little, feels like I’m getting something done. It’s an explicit marker of progress and motivates me to want to change my task’s states more often until I see it marked DONE.

Here’s how they are coloured,

(setq org-todo-keyword-faces
      '(("TODO"      :foreground "red"          :weight bold)
        ("STARTED"   :foreground "blue"         :weight bold)
        ("DONE"      :foreground "forest green" :weight bold)
        ("WAITING"   :foreground "orange"       :weight bold)
        ("ON_HOLD"   :foreground "magenta"      :weight bold)
        ("CANCELLED" :foreground "forest green" :weight bold)))

Now we press C-c C-t then the letter shortcut to actually make the state of an org heading.

(setq org-use-fast-todo-selection t)

We can also change through states using Shift- left, or right.

Let’s draw a state diagram to show what such a workflow looks like.

PlantUML supports drawing diagrams in a tremendously simple format —it even supports Graphviz/DOT directly and many other formats. Super simple setup instructions can be found here; below are a bit more involved instructions. Read the manual here.

;; Install the tool
; (async-shell-command "brew cask install java") ;; Dependency
; (async-shell-command "brew install plantuml")

;; Tell emacs where it is.
;; E.g., (async-shell-command "find / -name plantuml.jar")
(setq org-plantuml-jar-path
      "/usr/local/Cellar/plantuml/1.2019.13/libexec/plantuml.jar")

;; Enable C-c C-c to generate diagrams from plantuml src blocks.
(add-to-list 'org-babel-load-languages '(plantuml . t) )
(require 'ob-plantuml)

; Use fundamental mode when editing plantuml blocks with C-c '
(add-to-list 'org-src-lang-modes '("plantuml" . fundamental))

Let’s use this!

skinparam defaultTextAlignment center  /' Text alignment '/

skinparam titleBorderRoundCorner 15
skinparam titleBorderThickness 2
skinparam titleBorderColor red
skinparam titleBackgroundColor Aqua-CadetBlue
title My Personal Task States

[*] -> Todo          /' This is my starting state '/
Done -right-> [*]    /' This is an end state      '/
Cancelled -up-> [*]  /' This is an end state      '/

/'A task is “Todo”, then it's “started”, then finally it's “done”. '/
Todo    -right-> Started
Started -down->  Waiting
Waiting -up->    Started
Started -right-> Done

/'Along the way, I may pause the task for some reason then
  return to it. This may be since I'm “Blocked” since I need
  something, or the task has been put on “hold” since it may not
  be important right now, and it may be “cancelled” eventually.
'/

Todo    -down-> Waiting
Waiting -up-> Todo
Waiting -up-> Done

Todo -down-> On_Hold
On_Hold -> Todo

On_Hold -down-> Cancelled
Waiting -down-> Cancelled
Todo    -down-> Cancelled

/' The Org-mode shortcuts for these states are as follows. '/
Todo      : t
On_Hold   : h
Started   : s
Waiting   : w
Cancelled : c
Done      : d

/' If a task is paused, we should document why this is the case. '/
note right  of Waiting:   Note what is\nblocking us.
note right  of Cancelled: Note reason\nfor cancellation.
note bottom of On_Hold:   Note reason\nfor reduced priority.

center footer  ♥‿♥ Org-mode is so cool (•̀ᴗ•́)و
/' Note that we could omit the “center, left, right” if we wished,
   or used a “header” instead.'/

images/workflow.png

Of note:

  • Multiline comments are with /' comment here '/, single quote starts a one-line comment.
  • Nodes don’t need to be declared, and their names may contain spaces if they are enclosed in double-quotes.
  • One forms an arrow between two nodes by writing a line with x ->[label here] y or y <- x; or using --> and <-- for dashed lines. The label is optional.

    To enforce a particular layout, use -X-> where X ∈ {up, down, right, left}.

  • To declare that a node x has fields d, f we make two new lines having x : f and x : d.
  • One adds a note near a node x as follows: note right of x: words then newline\nthen more words.

    Likewise for notes on the left, top, bottom.

    • A note can be on several lines. It’s terminated by end note.
  • Interesting sprites and many other things can be done with PlantUML. Read the docs.

This particular workflow is inspired by Bernt Hansen —while quickly searching through the PlantUML manual: The above is known as an “activity diagram” and it’s covered in §4.

Org-mode may be used with PlantUML:

  • See §11,12 for using Org-mode notation to form ‘mindmaps’ and ‘work breakdown structures’.
  • Org-mode text formatters are also acknowledged but the delimiters must be doubled; see §16.1.

You can quickly write and see the resulting UMLs using https://liveuml.com/, for the most part.

Clocking Work Time

Let’s keep track of the time we spend working on tasks that we may have captured for ourselves the previous day. Such statistics provides a good idea of how long it actually takes me to accomplish a certain task in the future and it lets me know where my time has gone.

Clock inon a heading with I, or in the subtree with C-c C-x C-i. Clock outof a heading with O, or in the subtree with C-c C-x C-o. Clock reportSee clocked times with C-c C-x C-r.

After clocking out, the start and end times, as well as the elapsed time, are added to a drawer to the heading. We can punch in and out of tasks as many times as desired, say we took a break or switched to another task, and they will all be recorded into the drawer.

;; Record a note on what was accomplished when clocking out of an item.
(setq org-log-note-clock-out t)

To get started, we could estimate how long a task will take and clock-in; then clock-out and see how long it actually took.

Sometimes, at the beginning at least, I would accidentally invoke the transposed command C-x C-c, which saves all buffers and quits Emacs. So here’s a helpful way to ensure I don’t quit Emacs accidentally.

(setq confirm-kill-emacs 'yes-or-no-p)

A few more settings:

;; Resume clocking task when emacs is restarted
(org-clock-persistence-insinuate)

;; Show lot of clocking history
(setq org-clock-history-length 23)

;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)

;; Sometimes I change tasks I'm clocking quickly ---this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)

;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)

;; Save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist t)

;; Do not prompt to resume an active clock
(setq org-clock-persist-query-resume nil)

;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)

Finding tasks to clock in

Use one of the following options, with the top-most being the first to be tried.

  • From anywhere, C-u C-c C-x C-i yields a pop-up for recently clocked in tasks.
  • Pick something off today’s agenda scheduled items.
  • Pick a Started task from the agenda view, work on this unfinished task.
  • Pick something from the TODO tasks list in the agenda view.

C-c C-x C-d also provides a quick summary of clocked time for the current org file.

Estimates versus actual time

Before clocking into a task, add to the properties drawer :Effort: 1:25 or C-c C-x C-e, for a task that you estimate will take an hour and twenty-five minutes, for example. Now the modeline will mention the time elapsed alongside the task name. Woah!

(push '("Effort_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00")
      org-global-properties)

Use speed keys e/E to insert an effort estimate, with the above being provided options, or to increment the current effort to the next one in the above list.

This is also useful when you simply want to put a time limit on a task that wont be completed anytime soon, say writing a thesis or a long article, but you still want to work on it for an hour a day and be warned when you exceed such a time constraint.

When you’ve gone above your estimate time, the modeline colours it red.

Habit Formation

The reason to use habits is that they come with a graph indicating consistency by colour, and the goal of the game is to have the longest possible chain —no red days!

A ‘habit’ is a usual (recurring) todo task marked as a habit: Use C-c C-x p to set the STYLE property to habit on a task to set it as a habit.

;; Show habits for every day in the agenda.
(setq org-habit-show-habits t)
(setq org-habit-show-habits-only-for-today nil)

;; This shows the ‘Seinfeld consistency’ graph closer to the habit heading.
(setq org-habit-graph-column 90)

;; In order to see the habit graphs, which I've placed rightwards, let's
;; always open org-agenda in ‘full screen’.
;; (setq org-agenda-window-setup 'only-window)
inch by inch anything’s a cinch!

! means today and means a task has been done on that day; intuitively green means you’re on track, yellow is warning sign of overdue, red is overdue, and blue is an acceptable break day.

Here’s an example habit from the Org-mode manual, where .+𝒳d/𝒴d reads perform the habit once every 𝒳 days, but never let me go 𝒴 days without doing it.

** TODO Shave
   SCHEDULED: <2020-01-08 Wed .+2d/4d>
   :PROPERTIES:
   :STYLE:    habit
   :END:

Shave every 2 days, but we can take a 3-day break; however, on the 4th day, gotta shave!

Remember that in the agenda view if you alter a task, say with t to mark it done, then you need to use s to save the underlying todo/notes files; otherwise, any g will revert the change in the agenda buffer.

Programming

Herein we configure utilites for version control, function and variable lookup, and template expansion for inescapably repetitive scenarios.

Which function are we writing?

In the modeline, show the name of the function we’re currently writing.

(add-hook 'prog-mode-hook #'which-function-mode)
(add-hook 'org-mode-hook  #'which-function-mode)

In Org-mode, this places the current heading in the modeline.

In Lisp mode, ensure we always have matching parens.

(add-hook 'emacs-lisp-mode-hook #'check-parens)

Highlight defined Lisp symbols

Usually Emacs only highlights macro names, the following incantation makes it highlight all defined names —as long as we’re in Lisp mode, whence in org-src blocks we use ~C-c ‘~.

;; Emacs Lisp specific
(use-package highlight-defined
  :hook (emacs-lisp-mode . highlight-defined-mode))

Super helpful in making my Emacs configuration: If a name is not highlighted, then I’ve misspelled it or it doesn’t exist! smile

Eldoc for Lisp and Haskell

In emacs-lisp-mode we can enable eldoc-mode —“Elisp Live Documentation”— to display information about a function or a variable in the echo area. Likewise for Haskell.

(use-package eldoc
  :diminish eldoc-mode
  :hook (emacs-lisp-mode . turn-on-eldoc-mode)
        (lisp-interaction-mode . turn-on-eldoc-mode)
        (haskell-mode . turn-on-haskell-doc-mode)
        (haskell-mode . turn-on-haskell-indent))

The less casual Haskeller would likely want to use intero to obtain more support; e.g., obtain suggestions from GHC about redundant imports or type signatures.

Jumping to definitions & references

Out-of-the-box Emacs has ‘xref’ utilities M-. and C-u M-. to Find Identifier References; however, tags to source definitions need to be generated using the etags program. Nonetheless, the xref utilites are impressive and some just work: For example, M-? cleverly finds all references for an identifier in ‘near by’ files; whereas C-u M-. RET my/.*, for example, uses the given regular expression to list all identifiers with prefix my/, thereby listing my personally defined names ^_^

C-M-. 𝓇𝓮ℊ𝓮𝓍Find all identifiers whose name matches the given pattern

Let’s get dumb-jump, where the ‘dumb’ is possibly due to the fact that it works by brute-force regular-expression lookup of pre-defined ‘definitional template’ rules. It “just works” ^_^

(use-package dumb-jump
  :bind (("M-g q"     . dumb-jump-quick-look) ;; Show me in a tooltip.
         ("M-g ."     . dumb-jump-go-other-window)
         ("M-g b"     . dumb-jump-back)
         ("M-g p"     . dumb-jump-go-prompt)
         ("M-g a"     . xref-find-apropos)) ;; aka C-M-.
  :config
  ;; If source file is visible, just shift focus to it.
  (setq dumb-jump-use-visible-window t))

In Lisp, for binding macros, it lists all possible mentions of the bound variable —the first is likely what is desired. Alternatively, one could just add the necessary rule to the variable dumb-jump-find-rules. Otherwise, it works fine even for locally bound definitions. It works depending on the extension of a file.

Version Control with SVN —Using Magit!

Let’s use git as an interface to subversion repositories so that we can continue to use magit as our version control interface. The utility to do so is called git svn —note git 𝒳 on a MacOS is the same as git-𝒳 on other systems.

(use-package magit-svn
  :hook (magit-mode . magit-svn-mode))

Here’s an example. The following command checksout an SVN repo; afterwhich we may open a file there and do M-x magit-status to get the expected porcelain git interface ^_^

(async-shell-command "mkdir ~/2fa3; git svn clone --username alhassm https://websvn.mcmaster.ca/csse2fa3/2019-2020_Term2 ~/2fa3/")

In the magit buffer, we may now use the N key which wraps the git svn subcommands fetch, rebase, dcommit, branch, tag. For example:

  1. Make changes to a file.
  2. ‘Stage’ them with s and ‘commit’ them with c.
  3. ‘Push’ changes with N c.

We get to pretend we’re using git even though the underlying mechanism is svn!

For move on git svn, see A simple guide to git-svn or Effectively using Git with Subversion.

⟨ If I need to work with svn repos often enough, I’d extend my maybe-clone utility above to account for them. ⟩

What’s changed & who’s to blame?

Let’s have, in a fringe, an indicator for altered regions in a version controlled file. The symbols “+, =” appear in a fringe by default for alterations —we may change these if we like.

;; Hunk navigation and commiting.
(use-package git-gutter
  :diminish
  :config (global-git-gutter-mode))
;; Diff updates happen in real time according when user is idle.

Let’s set a hydra so we can press C-x v n n p n to move the next two altered hunks, move back one, then move to the next. This saves me having to supply the prefix C-x v each time I navigate among my alterations. At any point we may also press u 𝕩 to denote C-u ⟪prefix⟫ 𝕩.

(defhydra hydra-version-control (global-map "C-x v")
  "Version control"
  ;; Syntax: (extension method description)
  ("n" git-gutter:next-hunk      "Next hunk")
  ("p" git-gutter:previous-hunk  "Previous hunk")
  ("d" git-gutter:popup-hunk     "Show hunk diff")
  ("r" git-gutter:revert-hunk    "Revert hunk\n")
  ("c" git-gutter:stage-hunk     "Stage hunk")
  ("s" git-gutter:statistic      "How many added & deleted lines"))

Commiting with C-x v c let’s us use C-c C-k to cancel and C-c C-c to submit the given message; C-c C-a to amend the previous commit.

Alternatively, we may use diff-hl:

;; Colour fringe to indicate alterations.
;; (use-package diff-hl)
;; (global-diff-hl-mode)

A few more helpful version control features:

;; Popup for who's to blame for alterations.
(use-package git-messenger
  :custom ;; Always show who authored the commit and when.
          (git-messenger:show-detail t)
          ;; Message menu let's us use magit diff to see the commit change.
          (git-messenger:use-magit-popup t))

;; View current file in browser on github.
;; More generic is “browse-at-remote”.
(use-package github-browse-file :defer t)

;; Add these to the version control hydra.
;;
(defhydra hydra-version-control (global-map "C-x v")
  ("b" git-messenger:popup-message "Who's to blame?")
  ;; C-u C-x b ╱ u b ∷ Also show who authored the change and when.
  ("g" github-browse-file-blame "Show file in browser in github")
  ("s" magit-status "Git status of current buffer"))

Perhaps C-x v b will motivate smaller, frequent, commits.

Obtaining URL links to the current location of a file —URLs are added to the kill ring. Usefully, if git-timemachine-mode is active, the generated link points to the version of the file being visited.

(use-package git-link :defer t)

(defhydra hydra-version-control (global-map "C-x v")
  ("l" git-link "Git URL for current location"))

Read here for more about version control in general.

Highlighting TODO-s & Showing them in Magit

Basic support todos. By default these include: TODO NEXT THEM PROG OKAY DONT FAIL DONE NOTE KLUDGE HACK TEMP FIXME and any sequence of X’s or ?’s of length at least 3: XXX, XXXX, XXXXX, …, ???, ????, ????, ….

;; NOTE that the highlighting works even in comments.
(use-package hl-todo
  ;; I want todo-words highlighted in prose, not just in code fragements.
  ;; :hook (org-mode . hl-todo-mode)
  :config
    ;; Adding new keywords
    (loop for kw in '("TEST" "MA" "WK" "JC")
          do (add-to-list 'hl-todo-keyword-faces (cons kw "#dc8cc3")))
    (global-hl-todo-mode))   ;; Enable it everywhere.

Lest these get buried in mountains of text, let’s have them become mentioned in a magit status buffer —which uses the keywords from hl-todo.

;; MA: The todo keywords work in code too!
(use-package magit-todos
  :after magit
  :after hl-todo
  :hook (org-mode . magit-todos-mode)
  :config
  ;; For some reason cannot use :custom with this package.
  (custom-set-variables
    '(magit-todos-keywords (list "TODO" "FIXME" "MA" "WK" "JC")))
  ;; Ignore TODOs mentioned in exported HTML files; they're duplicated from org src.
  (setq magit-todos-exclude-globs '("*.html"))
  (magit-todos-mode))

Note that such TODO keywords are not propagated from sections that are COMMENT-ed out in org-mode.

Open a Magit status buffer, or run magit-todos-list to show a dedicated to-do list buffer. You can then peek at items with space, or jump to them with enter.

Seeing the TODO list with each commit is an incentive to actually tackle the items there (•̀ᴗ•́)و

  • Ensure you exclude generated files, such as the Emacs backups directory, from being consulte. Using magit, press i to mark items to be ignored.
  • This feature also works outside of git repos.

Add these to the version control hydra.

(defhydra hydra-version-control (global-map "C-x v")
  ("t" helm-magit-todos "Show TODOs lists for this repo."))

Being Generous with Whitespace

The following minor mode automatically adds spacing around operators.

(use-package electric-operator
  :diminish
  :hook (c-mode . electric-operator-mode))

I dislike it when users write x=y+1 —whitespace is free and helpful. ⟨ Also, languages with arbitrary identifiers, like Lisp and Agda, would accept x=y+1 as an identifier, not an expression! ⟩

On the fly syntax checking

Flycheck is a on-the-fly syntax checker that relies on external programs to check buffers; which must be installed separately.

  • E.g., ghc is required for Haskell; whereas Emacs Lisp is checked by Emacs’ own byte compiler, emacs-lisp.
  • Sometimes more than one checking tool applies, use C-c ! s to select a different checker.
  • C-c ! n,p,l takes you to the ‘n’ext or ‘p’revious error, or ‘l’ist all errors in another buffer.

    C-c ! c to explicitly recheck the buffer.

(use-package flycheck
  :diminish
  :init (global-flycheck-mode)
  :config ;; There may be multiple tools; I have GHC not Stack, so let's avoid that.
  (setq-default flycheck-disabled-checkers '(haskell-stack-ghc emacs-lisp-checkdoc))
  :custom (flycheck-display-errors-delay .3))

In an org-src block, we press ~C-c ‘~ to get into the language’s mode where flycheck will provide warnings.

module Main where

main :: IO ()
main = putStrLn $ "nice" ++ f 0

f :: Int -> String
f x = x -- show x
-- type error

In-general, flycheck is intended for self-contained raw code —not for source blocks in Org-mode. Whence, the above example is a complete Haskell program, with a named module and main method.

I think the built-in flymake syntax checker is better for Emacs Lisp, so let’s use that for ELisp.

(use-package flymake
  :hook ((emacs-lisp-mode . (lambda () (flycheck-mode -1)))
         (emacs-lisp-mode . flymake-mode))
  :bind (:map flymake-mode-map
              ("C-c ! n" . flymake-goto-next-error)
              ("C-c ! p" . flymake-goto-prev-error)))

Try it out:

(setq 1 2) ;; Error: ‘1’ is not a variable.

Coding with a Fruit Salad: Semantic Highlighting

What should be highlighted when we write code? Static keywords with fixed uses, or dynamic user-defined names?

  • Syntax highlighting ⇨ Specific words are highlighted in strong colours so that the structure can be easily gleaned.
    • Generally this only includes a language’s keywords, such as if, loop, begin, end, cond.
    • User defined names generally share one colour; usually black.
    • Hence, an if block may be seen as one coloured keyword followed by a blob of black text.

    Obvious keywords are highlighted while the rest remains in black!

  • Semantic highlighting ⇨ Identifiers obtain unique colouring.
    • This makes it much easier to visually spot dependencies with a quick glance.
      • One can see how data flows through a function.
    • In dynamic languages, this is a visual form of typing: Different colours are for different names.
      • Especially helpful for (library) names that are almost the same.
      • This can be accomplished anywhere in Emacs by pressing M-s h . on a selected phrase.

For Emacs, Color Identifiers Mode gives unique highlighting to identifiers.

  • It comes with support for a bunch of languages, and one can add support for others.
  • It picks colours adaptively to fit the theme; one uses M-x color-identifiers:regenerate-colors after a theme change.
(use-package color-identifiers-mode
  :config (global-color-identifiers-mode))

;; Sometimes just invoke: M-x color-identifiers:refresh

When writing a new name, after about ~5 seconds it obtains a colour which is then propagated immediately to any new occurrences. This timeout before recolouring is to avoid any lag from multithreading and can be changed by altering the following line (#64) in the source file, changing the 5 to a smaller number.

(run-with-idle-timer 5 t 'color-identifiers:refresh)

Here are further reads:

Text Folding with Origami-mode

Literate programming within Org-mode is not always ideal, so we use a programming mode directly and then may want to have arbitrary ‘sections’ of text folded up. Let’s describe how to accomplish this goal.

We use a feature-full folding mode, Origami-mode.

(use-package origami
  ;; In Lisp languages, by default only function definitions are folded.
  :hook ((agda2-mode lisp-mode c-mode) . origami-mode)
  :config
  ;; With basic support for one of my languages.
  (push '(agda2-mode . (origami-markers-parser "{-" "-}"))
         origami-parser-alist))

With expected support for searching.

(defun my/search-hook-function ()
  (when origami-mode (origami-toggle-node (current-buffer) (point))))

;; Open folded nodes if a search stops there.
(add-hook 'helm-swoop-after-goto-line-action-hook #'my/search-hook-function)
;;
;; Likewise for incremental search, isearch, users.
;; (add-hook 'isearch-mode-end-hook #'my/search-hook-function)

Along with a hydra for super quick navigation and easily folding, unfolding blocks! Love this one ^_^

(defhydra folding-with-origami-mode (global-map "C-c f")
  ("h" origami-close-node-recursively "Hide")
  ("o" origami-open-node-recursively  "Open")
  ("t" origami-toggle-all-nodes  "Toggle buffer")
  ("n" origami-next-fold "Next")
  ("p" origami-previous-fold "Previous"))

Jump between windows using Cmd+Arrow & between recent buffers with Meta-Tab

We can use C-x o to switch to the ‘o’ther window, and C-u 𝓃 C-x o to switch to the 𝓃-th next clockwise window, but using s-↑,↓,←,→ may be faster.

(use-package windmove
  :config ;; use command key on Mac
          (windmove-default-keybindings 'super)
          ;; wrap around at edges
          (setq windmove-wrap-around t))

The docs, for the following, have usage examples.

(use-package buffer-flip
  :bind
   (:map buffer-flip-map
    ("M-<tab>"   . buffer-flip-forward)
    ("M-S-<tab>" . buffer-flip-backward)
    ("C-g"       . buffer-flip-abort))
  :config
    (setq buffer-flip-skip-patterns
        '("^\\*helm\\b")))
;; key to begin cycling buffers.
(global-set-key (kbd "M-<tab>") 'buffer-flip)

See buffer-move if you’re interested in moving the buffers, and their windows, into new configurations.

Snippets —Template Expansion

It is common that there is a sequence of text that we tend to repeat often, possibly with a name or some other parameter altered. Such a ‘snippet’ could be written once then provided by a simple Lisp insert command with the parameters being queried. Luckily, others have written such pleasant utilities. Yasnippet is a pleasant utility for template expansion with the alluring feature to allow arbitrary Lisp code to be executed during expansion. The declaration of templates is verbose, requiring a particular file hierarchy, as such I utilise Yankpad which allows me to employ an Org-mode approach: Each template corresponds to an org heading of the form Key:Words:For:Expansion:Here: name of snippet here and the template body is then the body of the org heading. Any of Key, Words, For, Expansion, Here will rewrite into the body of the org tree. This is much more terse, and I even don’t bother with that; instead preferring to tangle my templates using yankpad as a mere interface. It is important to note that Yankpad also provides features that are not in Yassnippet, such as allowing arbitrary language code to be executed —one simply uses an org-src block!

There are only be one major completion backend for any mode, but other backends can serve as secondary ones. Here’s a function to make company-yankpad a secondary of all existing backends.

;; Add yasnippet support for all company backends
;;
(cl-defun my/company-backend-with-yankpad (backend)
  "There can only be one main completition backend, so let's
   enable yasnippet/yankpad as a secondary for all completion
   backends.

   Src: https://emacs.stackexchange.com/a/10520/10352"

  (if (and (listp backend) (member 'company-yankpad backend))
      backend
    (append (if (consp backend) backend (list backend))
            '(:with company-yankpad))))
;; Yet another snippet extension program
(use-package yasnippet
  :diminish yas-minor-mode
  :config
    (yas-global-mode 1) ;; Always have this on for when using yasnippet syntax within yankpad
    ;; respect the spacing in my snippet declarations
    (setq yas-indent-line 'fixed))

;; Alternative, Org-based extension program
(use-package yankpad
  :diminish
  :config
    ;; Location of templates
    (setq yankpad-file "~/.emacs.d/yankpad.org")

    ;; Ignore major mode, always use defaults.
    ;; Yankpad will freeze if no org heading has the name of the given category.
    (setq yankpad-category "Default")

    ;; Load the snippet templates ---useful after yankpad is altered
    (yankpad-reload)

    ;; Set company-backend as a secondary completion backend to all existing backends.
    (setq company-backends (mapcar #'my/company-backend-with-yankpad company-backends)))

With these settings, along with the company backend, I may type a keyword then “tab” it into expansion.

Yankpad requires we have an org file that contains our templates, so we tangle such a file ~~/.emacs.d/yankpad.org~, and have all of our templates be globally accessible.

#+Description: This is file is generated from my init.org; do not edit.

* Default                                           :global:

Here’s an example of a common template I perform by hand —no more! I have the expected habit of copying a URL from someplace then forming a link to it by writing [[URL] [description]], since the URL & syntax are already known, let’s expand those and place the cursour at the only unknown —the description.

** my_org_insert_link: cleverly insert a link copied to clipboard
 [[${1:`(clipboard-yank)`}][$2]] $0

What’s going on here?

  1. This template is expanded with the keyword my-org-insert-link, then “tab”.
  2. The cursour lands at position $1, which has default text being the result of evaluating (clipboard-yank).

    We may evaluate Lisp code anywhere by enclosing it in backticks.

  3. If we’re satisfied with the current field, we simply tab to the next field. Otherwise, we simply write text –which overwrites the default text.
  4. After enough tabbing we complete the template and the cursour lands at position $0.

⟪ Having default or mirrored text for $2 would not allow me to see the URL field, lest I wish to change it or at least confirm it’s what I want. Hence, the $2 field has no default. ⟫

Let’s overwrite the usual way to insert such links, via C-c C-l.

(cl-defun org-insert-link ()
  "Makes an org link by inserting the URL copied to clipboard and
  prompting for the link description only.

  Type over the shown link to change it, or tab to move to the
  description field.

  This overrides Org-mode's built-in ‘org-insert-link’ utility;
  whence C-c C-l uses the snippet."
  (interactive)
  (insert "my_org_insert_link")
  (yankpad-expand))

Warning! Snippet names cannot have hypens in them —in this setup at least.

The Yasnippet manual is an accessible read, as is the Yankpad manual, and showcases many other utilities; such as having certain snippets being enabled only in particular modes or on demand. Of note is that field $n can be accessed in code with the invocation (yas-field-value n).

Incidentally, I used this snippet setup to demo the idea of repetitious code in grouping constructs within dependently-typed languages, which was accepted and led to my doctoral research on a ‘do it yourself module system’.

The rest of this section is other templates, not much for now, concluding with actually loading this snippet mechanism globally.

The remaining subsections discuss contents of my yankpad file.

Org-mode Templates —A reason I “generate” templates ;)

This produces a pop-up list of org-mode block types, if src is selected, then a list of my commonly used languages pops-up. Alternatively, ignore the pop-up menu and write any block or language name.

** begin: produce an org-mode block
#+begin_${1:environment$(let*
    ((block '("src" "example" "quote" "verse" "center" "latex" "html" "ascii"))
     (langs '("c" "emacs-lisp" "lisp" "latex" "python" "sh" "haskell" "plantuml" "prolog"))
     (type (yas-choose-value block)))
     (concat type (when (equal type "src") (concat " " (yas-choose-value langs)))))}
 $0
#+end_${1:$(car (split-string yas-text))}

In this case, yas-text is equivalent to (yas-field-value 1); it generally refers to the value of the field being mirrored with ${n: ⋯yas-text⋯}.

However, going through pop-ups takes precious time —besides being slightly annyoing. Let’s introduce a template for my most utilised kind of language blocks.

** s_org: src block for org
#+begin_src org
$0
#+end_src

However, doing this for each language I want is a waste of time and textual space. Why? The purpose of templates is to reduce repetition, yet the above block would be repeated with only 3 parts ‘unknown’: The expansion keyword, the description, and the org-mode source block name. Whence, the template text is generated by the following basic loop —whose source block is named my-org-lang-templates.

;; We make an org BLOCK snippet template for each LANG the user has declared.
;;
(loop for (shortcut . block) in '(("s_" . "src")
                                  ("e_" . "example")
                                  ("q_" . "quote")
                                  ("v_" . "verse")
                                  ("c_" . "center")
                                  ("ex_" . "export"))
      concat (loop for lang in (-cons* "org" "agda2" "any" ;; Extra ‘languages’
                                       ;; Also include whatever languages we've loaded for literate programming.
                                       (--map (symbol-name (car it)) org-babel-load-languages))
                   for key         = (concat shortcut lang)
                   for description = (concat block " block for " lang)
                   concat (concat "\n** " key ": " description
                                  "\n#+begin_" block " " lang
                                  "\n$0"
                                  "\n#+end_" block "\n")))

The resulting text of this block, generated below, is tangled to our yankpad by utilising a noweb source block invocation. An example of the resulting text is the above “s_org” block. The result is 83 template expansions —that would have been a bit much to write by hand.

#+begin_src org :tangle "~/.emacs.d/yankpad.org" :noweb yes
<<my-org-lang-templates()>>
#+end_src

Now s_, due to company mode, brings up a list of languages that I can then scroll down through, then “enter” upon to expand. Moreover, the prefix s_ means that the key is mostly irrelevant, since I needn’t remember it because company-mode immediately lists possible completions along with the descriptions for the snippets. Likewise for examples with e_ or quotes with q_. Super neat stuff :-)

Ain’t this reminiscent of meta-programming ;-)

Using noweb invocations, any time the tangling is performed, the yankpad is kept up to date –no personal intervention from myself.

Elisp Templates

The following snippets were rather useful as I began learning Lisp to construct my editor of choice —I love Emacs so much. Admittedly, I still need the first one below and usually beat around the bush by using (loop for ⋯ do ⋯), which is ‘noisier’ but easier to remember and to read for non-Lispers.

** loop:  Elisp's for each loop
(dolist (${1:var} ${2:list-form})
        ${3:body})

** defun: Lisp functions
(cl-defun ${1:fun-name} (${2:arguments})
  "${3:documentation}"
  $0
)

** cond: Elisp conditionals
(cond (${1:scenario₁} ${2:response₁})
      (${3:scenario₂} ${4:response₂})
)

Equational Templates

To show ℒ = ℛ, one starts at the complicated side, say , then, with the aim of simplification, tries to end at the simpler side, 𝓡. Along the way, one justifies each step of the calculation. This approach is popular in the proof assistant Agda; Examples. Read more about informal calculational proofs.

** fun: Function declaration with type signature

${1:fun-name} : ${2:arguments}
$1 ${3:args} = ?$0

** eqn_begin: Start a ≡-Reasoning block in Agda

begin
  ${1:complicated-side}
$0≡⟨ ${3:reason-for-the-equality} ⟩
 ${2:simpler-side}
∎

** eqn_step: Insert a step in a ≡-Reasoning block in Agda
≡⟨ ${2:reason-for-the-equality} ⟩
  ${1:new-expression}
$0

One expands eqn_begin, tabs to fill in the three main locations, then immediately types eqn_step to produce a new step in a calculational proof.

my_⋯ Templates to obtain User Information

Let’s add templates for links to common user information ^_^

** my_name: User's name
`user-full-name`

** my_email: User's email address
`user-mail-address`

** my_github: User's Github repoistory link
https://github.com/alhassy/

** my_emacsdrepo: User's version controlled Emacs init file
https://github.com/alhassy/emacs.d

** my_blog: User's blog website
https://alhassy.github.io/

** my_webpage: User's organisation website
http://www.cas.mcmaster.ca/~alhassm/

** my_twitter: User's Twitter profile
https://twitter.com/musa314

** my_masters_thesis
A Mechanisation of Internal Galois Connections In Order Theory Formalised Without Meets
https://macsphere.mcmaster.ca/bitstream/11375/17276/2/thesis.pdf

It may be useful to also have Org-link variants of these …

Templates from other places in my init

In this setup, I have some templates appear elsewhere, tagged with :noweb-ref templates-from-other-places-in-my-init. They are presented in natural positions, but can only occur to the machine after template expansion is setup. Using org-mode, we are able to present code in any order and tangle it to the order the compilers need it to be!

Let’s activate all such templates, now after template expansion has been setup.

<<templates-from-other-places-in-my-init>>

Note: Since I’ve insisted that Org blocks are space sensative, any whitespace before the <<⋯>> will propogate to the resulting extracted code.

Re-Enabling Templates

After our yankpad templates are generated, we need to load it.

;; After init hook; see above near use-package install.
(yankpad-reload)

Helpful Utilities & Shortcuts

Here is a collection of Emacs-lisp functions that I have come to use in other files.

Disclaimer: I wrote much of the following before I learned any lisp; everything below is probably terrible.

Let’s save a few precious seconds,

;; change all prompts to y or n
(fset 'yes-or-no-p 'y-or-n-p)

;; Enable all ‘possibly confusing commands’ such as helpful but
;; initially-worrisome “narrow-to-region”, C-x n n.
(setq-default disabled-command-function nil)

Documentation Pop-Ups

Let documentation pop-up when we pause on a completion. This is very useful when editing in a particular coding language, say via ~C-c ‘~ for org-src blocks.

(use-package company-quickhelp
 :config
   (setq company-quickhelp-delay 0.1)
   (company-quickhelp-mode))

Emacs keybindings for my browser

⟨ I was a bit too Emacs-happy at one-point; this’ cool, but I rarely use it; except C-x b: A buffer approach is far superior to a tab-based one. ⟩

I’ve downloaded the Vimium extension for Google Chrome, and have copy-pasted these Emacs key bindings into it. Now C-h in my browser shows which Emacs-like bindings can be used to navigate my browser ^_^

Using Emacs in any text area on my OS

⟨ I was a bit too Emacs-happy at one-point; this’ cool, but I rarely use it. ⟩

Using the Emacs-Anywhere tool, I can press Cmd Shift e to have an Emacs frame appear, produce text with Emacs editing capabilities, then C-x 5 0 to have the resulting text dumped into the text area I was working in.

This way I can use Emacs literally anywhere for textual input!

For my Mac OSX:

(shell-command "curl -fsSL https://raw.github.com/zachcurry/emacs-anywhere/master/install | bash")

(server-start)

The tools that use emacs-anywhere —such as my web browser— and emacs-anywhere itself need to be given sufficient OS permissions:

System Preferences → Security & Privacy → Accessibility

Then check the emacs-anywhere box from the following gui and provide a keyboard shortcut:

System Preferences → Keyboard → Shortcuts → Services

(•̀ᴗ•́)و

I always want to be in Org-mode and input unicode:

(add-hook 'ea-popup-hook
  (lambda (app-name window-title x y w h)
    (org-mode)
    (set-input-method "Agda")))

Reload buffer with f5

I do this so often it’s not even funny.

(global-set-key [f5] '(lambda () (interactive) (revert-buffer nil t nil)))

In Mac OS, one uses Cmd-r to reload a page and Emacs binds buffer reversion to Cmd-u –in Emacs, Mac’s Cmd is referred to as the ‘super key’ and denoted s.

Moreover, since I use Org-mode to generate code blocks and occasionally inspect them, it would be nice if they automatically reverted when they were regenerated –Emacs should also prompt me if I make any changes!

;; Auto update buffers that change on disk.
;; Will be prompted if there are changes that could be lost.
(global-auto-revert-mode 1)

;; Don't show me the “ARev” marker in the mode line
(diminish 'auto-revert-mode)

Kill to start of line

Dual to C-k,

;; M-k kills to the left
(global-set-key "\M-k" '(lambda () (interactive) (kill-line 0)) )

Killing buffers & windows: C-x k has a family

Let’s extend the standard C-x k with prefix support, so that we can invoke variations: Kill this buffer, kill other buffer, or kill all other buffers.

By default C-x k prompts to select which buffer should be selected. I almost always want to kill the current buffer, so let’s not waste time making such a tedious decision. Moreover, if I’ve killed a buffer, I usually also don’t want the residual window, so let’s get rid of it.

(global-set-key (kbd "C-x k")
  (lambda (&optional prefix)
"C-x k     ⇒ Kill current buffer & window
C-u C-x k ⇒ Kill OTHER window and its buffer
C-u C-u C-x C-k ⇒ Kill all other buffers and windows

Prompt only if there are unsaved changes."
     (interactive "P")
     (pcase (or (car prefix) 0)
       ;; C-x k     ⇒ Kill current buffer & window
       (0  (kill-this-buffer)
           (unless (one-window-p) (delete-window)))
       ;; C-u C-x k ⇒ Kill OTHER window and its buffer
       (4  (other-window 1)
           (kill-this-buffer)
           (unless (one-window-p) (delete-window)))
       ;; C-u C-u C-x C-k ⇒ Kill all other buffers and windows
       (16   (mapc 'kill-buffer (delq (current-buffer) (buffer-list)))
             (delete-other-windows)))))

The incantation C-u C-x k will reduce the noise of all the documentation buffers I tend to consult.

Switching from 2 horizontal windows to 2 vertical windows

I often find myself switching from a horizontal view of two windows in Emacs to a vertical view. This requires a variation of C-x 1 RET C-x 3 RET C-x o C-x b RET. Instead I now only need to type C-| to make this switch.

(defun my/ensure-two-vertical-windows ()
  "I used this method often when programming in Coq.

When there are two vertical windows, this method ensures the left-most
window contains the buffer with the cursour in it."
  (interactive)
  (let ((otherBuffer (buffer-name)))
    (other-window 1)                ;; C-x 0
    (delete-window)                 ;; C-x 0
    (split-window-right)			;; C-x 3
    (other-window 1)                ;; C-x 0
    (switch-to-buffer otherBuffer)	;; C-x b RET
    (other-window 1)))

(global-set-key (kbd "C-|") 'my/ensure-two-vertical-windows)

Obtaining Values of #+KEYWORD Annotations

Org-mode settings are, for the most part, in the form #+KEYWORD: VALUE. Of notable interest are the TITLE and NAME keywords. We use the following org-keywords function to obtain the values of arbitrary #+THIS : THAT pairs, which may not necessarily be supported by native Org-mode –we do so for the case, for example, of the CATEGORIES and IMAGE tags associated with an article.

;; Src: http://kitchingroup.cheme.cmu.edu/blog/2013/05/05/Getting-keyword-options-in-org-files/
(defun org-keywords ()
  "Parse the buffer and return a cons list of (property . value) from lines like: #+PROPERTY: value"
  (org-element-map (org-element-parse-buffer 'element) 'keyword
                   (lambda (keyword) (cons (org-element-property :key keyword)
                                           (org-element-property :value keyword)))))

(defun org-keyword (KEYWORD)
  "Get the value of a KEYWORD in the form of #+KEYWORD: value"
  (cdr (assoc KEYWORD (org-keywords))))

Note that capitalisation in a ”#+KeyWord” is irrelevant.

See here on how to see the abstract syntax tree of an org file and how to manipulate it.

Publishing articles to my personal blog

I try to blog occasionally, so here’s a helpful function to quickly publish the current article to my blog.

(define-key global-map "\C-cb" 'my/publish-to-blog)

(cl-defun my/publish-to-blog (&optional (draft nil) (local nil))
  "
  Using ‘AlBasmala’ setup to publish current article to my blog.
  Details of AlBasmala can be found here:
  https://alhassy.github.io/AlBasmala/

  Locally: ~/alhassy.github.io/content/AlBasmala.org

  A ‘draft’ will be produced in about ~7 seconds, but does not re-produce
  a PDF and the article has a draft marker near the top. Otherwise,
  it will generally take ~30 seconds due to PDF production, which is normal.
  The default is not a draft and it takes ~20 seconds for the live
  github.io page to update.

  The ‘local’ optiona indicates whether the resulting article should be
  viewed using the local server or the live webpage. Live page is default.

  When ‘draft’ and ‘local’ are both set, the resulting page may momentarily
  show a page-not-found error, simply refresh.
  "

  (load-file "~/alhassy.github.io/content/AlBasmala.el")

  ;; --MOVE ME TO ALBASMALA--
  ;; Sometimes the file I'm working with is not a .org file, so:
  (setq file.org (buffer-name))

  (preview-article :draft draft)
  (unless draft (publish))
  (let ((server (if local "http://localhost:4000/" "https://alhassy.github.io/")))
    (async-shell-command (concat "open " server NAME "/") "*blog-post-in-browser*"))
)

Conclusion —Why Configuration Files Should be Literate

A configuration file sets up various features for a tool —and serves as an essential learning point. In order to remember them, what they do, and possibly where you learned about them —which may include additional resources— it is pertinent to document such facts. Benefits of documentating features include:

  • A list of the features with human readable names! —In case you forget what you invested time on!
  • Personal documentation! —Reduce wasting time Googling things that you knew in the past!
  • Convincing Need
    • Making notes with decriptive text, as suggested below, will make it clear whether you actually need the feature or “just threw it becuase it looks cool” —which leads to ‘init bankruptcy’.

      Moreover, actually documenting a feature may make it more to recall that you have the feature and have notes for it.

Programs are meant to be read by humans and only incidentally for computers to execute. —Donald Knuth

Alongside a feature’s installation, I’ve tried to provide the following:

  • Why would I want this? Motivation!
    • Example scenerios and use-cases.
  • How do I actually use it? Super terse usage details to “get going”!
  • Where is the offical documentation page, or repository? Discovarability!
  • Comparisions: Are there other similar features, builtin or otherwise? How do they compare? Why have I decided for this one instead of another one?
  • Additional comments and reminders related to the feature.
    • E.g., why the feature is now disabled, ‘commented out’, when before it was useful.

Programs without documentation have little value; it’s like a claim without evidence! —Me

Here are some benefits of having a tool’s configurations written literately as an Org-mode file, then tangeling as appropriate.

  • Modularity! —or “In Praise of the Monolith”

    It may not be feasible, or practical, to split a tool’s configuration file into multiple file hierarchy. Yet, with Org-mode we may reify the hierarchical structure as ‘sections’ and have the resulting configuration read more like a novel, easily folding and navigating, between sections.

    • Section headers provide organisation and they’re collapsable.

    Even if you can make multiple files, using one monolithic file allows:

    • Really easy to quickly re-organise code!
      • Use w to move content almost instanteously!
      • In contrast, it’s harder to review an entire project, when it’s in pieces.
    • Many files requires coming up with descriptive file names; instead prefer descriptive org headings ^_^
    • Easily navigatable hierarchy with a nested directory/org-heading structure.
      • Have headings with an introducttory paragraph that explains the kind of features being considered —or, lazily, look at the outlined view of subheadings to see what’s there.
    • Easy search & review of features since they’re in one file.
      • Multiple files makes it harder to remember which features live where.
    • One file is easy to distribute & share!

    Many small files are great for collobaration —there’ll likely be less merge conflicts. However, configuration files are usually a one-person project.

  • Toggle feature selection without altering any code!

    With a single # key press, we can comment out a section, thereby disabling the features it provides. The features are neither deleted nor forgotten, but we can experiment with having them there or not without altering any code! Alternatively, one mays use the :noexport: tag on a section header.

    In contrast, an illiterate setup would have us commenting out large chunks of code, which is not as easy to manage.

  • Really easy to delete content!

    After a while, I come back and realise I’ve implemented something silly or that is available via some external package, I can quickly delete it.

  • Can quickly export to different mediums!

    If you want to share your configuration with others, then an HTML rendition with a table of contents and text sprinkled everywhere is more likely to attract onlookers since they can easily jump to the sections they’re interested in.

  • Easily digestible chunks of code!

    With a literate approach, one is empowered to have short source blocks; e.g., not exceeding 30 lines —read more here. This is more likely to ensure (possibly by extracting code into its own functions): The listing fits on one screen, avoiding deeply nested control structures, non-repeating common logical patterns, increased confidence that the implementation meets the stated purpose.

The only reason I would use multiple files or raw code for setting up a tool would be if I did not have a literate programming environment; i.e., Org-mode.


Emacs is fun ^_^


Being replaced at the office

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK