Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/alhassy/emacs.d

My Emacs configuration, literately :smile:
https://github.com/alhassy/emacs.d

dotfiles emacs literate-programming

Last synced: 4 days ago
JSON representation

My Emacs configuration, literately :smile:

Awesome Lists containing this project

README

        

Updated, /pretty/, version: https://alhassy.github.io/emacs.d/index.html

#+html:


#+html:
#+html: LifeMacs CI Status Badge
#+html:

--------------------------------------------------------------------------------

# Created 2020-09-16 Wed 10:04
#+OPTIONS: html-postamble:nil toc:nil d:nil num:nil :results nil
#+TITLE: A Life Configuring Emacs
#+DATE: 2018-07-25
#+AUTHOR: Musa Al-hassy
#+export_file_name: README.org

#+html:

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:

#+description: My Emacs Initialisation File, Written in Org-mode.
#+startup: indent lognoteclock-out
#+property: header-args :tangle init.el :comments link :results none

#+sourcefile: https://github.com/alhassy/emacs.d/blob/master/init.org
#+image: ../assets/img/emacs_logo.png
#+categories: Emacs Lisp

#+begin_src emacs-lisp :exports none :tangle no
(defun go ())
#+end_src

* Abstract :ignore:
#+html:


#+begin_center
*Abstract*
#+end_center
#+html:

Herein I document the configurations I utilise with [[https://gnu.org/s/emacs][Emacs]].

As a [[https://www.offerzen.com/blog/literate-programming-empower-your-writing-with-emacs-org-mode][literate program]] file with [[http://orgmode.org/][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 [[https://github.com/alhassy/ElispCheatSheet][here]] and here is a 2-page 3-column [[https://github.com/alhassy/emacs.d/blob/master/CheatSheet.pdf][Emacs Cheat Sheet]] of
the bindings in ~“this”~ configuration.
- ~C-h o~ ⇒ *What's this thing?*
- ~C-h e~ ⇒ *What'd /Emacs/ do?*
- ~C-h l~ ⇒ *What'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 :Github:TOC_4:
- [[#abstract][Abstract]]
- [[#booting-up][Booting Up]]
- [[#emacs-vs-initorg][=~/.emacs= vs. =init.org=]]
- [[#adventure-time-honey-wheres-my-init][/Adventure time!/ “Honey, where's my init?”]]
- [[#adventure-time-using-emacs-easy-customisation-interface][/Adventure time!/ Using Emacs' Easy Customisation Interface]]
- [[#support-for-custom][Support for ‘Custom’]]
- [[#use-package----the-start-of-initel][=use-package= ---The start of =init.el=]]
- [[#readme----from-initorg-to-initel][=README= ---From =init.org= to =init.el=]]
- [[#the-mymake-init-el-and-readme-function][The =my/make-init-el-and-README= function]]
- [[#the-org-block-named-make-readme][The Org-block named =make-readme=]]
- [[#table-of-contents-for-org-vs-github][‘Table of Contents’ for Org vs. Github]]
- [[#alternate-approaches-to-generating-a-readme][Alternate approaches to generating a README]]
- [[#installing-emacs-packages-directly-from-source][Installing Emacs packages directly from source]]
- [[#magit----emacs-porcelain-interface-to-gitq][=magit= ---Emacs' porcelain interface to gitq]]
- [[#syncing-to-the-systems-path][Syncing to the System's =$PATH=]]
- [[#installing-os-packages-and-automatically-keeping-my-system-up-to-data-from-within-emacs][Installing OS packages, and automatically keeping my system up to data, from within Emacs]]
- [[#being-at-the-helm----completion--narrowing-framework][“Being at the Helm” ---Completion & Narrowing Framework]]
- [[#having-a-workspace-manager-in-emacs][Having a workspace manager in Emacs]]
- [[#excellent-pdf-viewer][Excellent PDF Viewer]]
- [[#who-am-i----using-gnus-for-gmail][Who am I? ---Using Gnus for Gmail]]
- [[#prettifications][Prettifications]]
- [[#super-terse-tutorial][Super Terse Tutorial]]
- [[#capturing-mail-as-todonotes][Capturing Mail as Todo/Notes]]
- [[#auto-completing-mail-addresses][Auto-completing mail addresses]]
- [[#feeds-to-blogs][Feeds to Blogs]]
- [[#jumping-to-extreme-semantic-units][Jumping to extreme semantic units]]
- [[#quickly-pop-up-a-terminal-run-a-command-close-it----and-zsh][Quickly pop-up a terminal, run a command, close it ---and zsh]]
- [[#restarting-emacs----keeping-buffers-open-across-sessions][Restarting Emacs ---Keeping buffers open across sessions?]]
- [[#automatic-backups][Automatic Backups]]
- [[#screencapturing-the-current-emacs-frame][Screencapturing the Current Emacs Frame]]
- [[#editor-documentation-with-contextual-information][Editor Documentation with Contextual Information]]

* 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 [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html#Init-File][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
[[https://www.gnu.org/software/emacs/manual/html_node/eintr/Beginning-init-File.html#Beginning-init-File][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 [[#Life-within-Org-mode][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_
#+begin_src emacs-lisp :tangle no
;; Emacs looks for this first;
(set-background-color "chocolate3")
(message-box ".emacs.el says hello")
#+end_src
_~/.emacs_
#+begin_src emacs-lisp :tangle no
;; else; looks for this one;
(set-background-color "plum4")
(message-box ".emacs says hello")
#+end_src
_~/.emacs.d/init.el_
#+begin_src emacs-lisp :tangle no
;; Finally, if neither are found; it looks for this one.
(set-background-color "salmon")
(message-box ".emacs.d/init.el says hello")
#+end_src

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.
#+begin_src emacs-lisp
(setq custom-file "~/.emacs.d/custom.el")
(ignore-errors (load custom-file)) ;; It may not yet exist.
#+end_src

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! )
#+begin_src emacs-lisp
(setq enable-local-variables :safe)
#+end_src

** =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 [[https://melpa.org/#/][MELPA]]
(Milkypostman's ELPA) ---it builds packages [[https://github.com/melpa/melpa][directly from the source-code
reposistories of developers]], rather than having all packages in one repository.
#+begin_src emacs-lisp
;; 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)
#+end_src

- 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 [[https://github.com/jwiegley/use-package/][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ₙ) . -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~.
#+begin_src emacs-lisp
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(require 'use-package)
#+end_src

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.
#+begin_src emacs-lisp
(setq use-package-always-ensure t)
#+end_src
The use of ~:ensure t~ only installs absent modules, but it does no updating.
Let's set up [[https://github.com/rranelli/auto-package-update.el][an auto-update mechanism]].
#+begin_src emacs-lisp
(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))
#+end_src

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 :-)
#+begin_src emacs-lisp
;; 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))
#+end_src
⟨ 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.
#+begin_src emacs-lisp
(use-package diminish
:defer 5
:config ;; Let's hide some markers.
(diminish 'org-indent-mode))
#+end_src

Here are other packages that I want to be installed onto my machine.
#+begin_src emacs-lisp
;; 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)
#+end_src

Note:
- [[https://github.com/magnars/dash.el][dash]]: “A modern list library for Emacs”
- E.g., ~(--filter (> it 10) (list 8 9 10 11 12))~
- [[https://github.com/magnars/s.el][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.
#+begin_src emacs-lisp :noweb yes
<>
#+end_src

Finally, let's try our best to have a [[https://chris.beams.io/posts/git-commit/][useful & consistent commit log]]:
#+begin_src emacs-lisp
(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)
#+end_src

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.

#+name: startup-code
#+begin_src emacs-lisp :eval never-export
(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)
#+end_src

*** 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.
#+name: make-readme
#+begin_src emacs-lisp :tangle no :export_never t
(save-buffer)
(with-temp-buffer
(insert
"#+EXPORT_FILE_NAME: README.org

# Logos and birthday present painting
,#+HTML:" (s-collapse-whitespace (concat
"










"))

;; 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)))
#+end_src
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:
#+begin_example org
https://img.shields.io/badge/--.svg
#+end_example

*** ‘Table of Contents’ for Org vs. Github
The above mentioned package [[https://github.com/snosov1/toc-org][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 [[https://github.com/alphapapa/org-make-toc][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.
#+begin_src emacs-lisp
(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]\\)?:\\($\\|[^ ]*?:$\\)"))
#+end_src

However, [[https://github.com/snosov1/toc-org/issues/54#issuecomment-363710561][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, [[https://github.com/snosov1/toc-org/issues/3][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.
#+begin_src emacs-lisp
(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")
#+end_src
*** Alternate approaches to generating a README
Github supports several markup languages, one of which is Org-mode.
- It seems that Github uses [[https://github.com/bdewey/org-ruby][org-ruby]] to convert org-mode to html.
- [[https://github.com/novoid/github-orgmode-tests][Here]] is a repo demonstrating how Github interprets Org-mode files.
- org-ruby supports inline ~#+HTML~ but [[https://github.com/wallyqs/org-ruby/issues/51][not html blocks]].

It seems coloured HTML does not render well:
#+begin_example emacs-lisp
(org-html-export-to-html)
(shell-command "mv README.html README.md")
#+end_example

[[https://orgmode.org/manual/JavaScript-support.html][JavaScript supported display of web pages]] with:
#+begin_example org
,#+INFOJS_OPT: view:info toc:t buttons:t
#+end_example
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 [[https://github.com/joeyespo/grip][grip]].

#+begin_src emacs-lisp :tangle no
;; grip looks for README.md
(system-packages-ensure "grip")
;; Next: (async-shell-command "cd ~/.emacs.d/; grip")
#+end_src

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
[[https://github.com/quelpa/quelpa-use-package][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~.

#+begin_src emacs-lisp
(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))
#+end_src

Let's use this to obtain an improved info-mode from the EmacsWiki. [Disabled for
now]
#+begin_src emacs-lisp :tangle no
(use-package info+
:disabled
:quelpa (info+ :fetcher wiki :url "https://www.emacswiki.org/emacs/info%2b.el"))
#+end_src

** =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.
#+begin_src emacs-lisp
;; 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]\""))
#+end_src

Below is my personal quick guide to working with magit ---for a full tutorial
see [[http://jr0cket.co.uk/2012/12/driving-git-with-emacs-pure-magic-with.html.html][jr0cket's blog]].

- ~dired~ :: See the contents of a particular directory.

- ~magit-init~ :: Put 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 g~ :: See status in another buffer.
Press ~?~ to see options, including:
- g :: Refresh the status buffer.
- TAB :: See collapsed items, such as what text has been changed.
- ~q~ :: Quit magit, or go to previous magit screen.
- ~s~ :: Stage, i.e., add, a file to version control.
Add all untracked files by selecting the /Untracked files/ title.

[[https://softwareengineering.stackexchange.com/a/119807/185815][The staging area is akin to a pet store; commiting is taking the pet home.]]

- ~k~ :: Kill, i.e., delete a file locally.
- ~K~ :: This' ~(magit-file-untrack)~ which does ~git rm --cached~.
- ~i~ :: Add a file to the project ~.gitignore~ file. Nice stuff =)
- ~u~ :: Unstage a specfif staged change highlighed by cursor.
~C-u s~ stages everything --tracked or not.
- ~c~ :: Commit 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~.

- ~d~ :: Show differences, another ~d~ or another option.
- This is magit! Each hunk can be acted upon; e.g., ~s~ or ~c~ or ~k~ ;-)
- ~v~ :: Revert a commit.
- ~x~ :: Undo last commit. Tantamount to ~git reset HEAD~~ when cursor is on most recent
commit; otherwise resets to whatever commit is under the cursor.
- ~l~ :: Show 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.
- ~P~ :: Push.
- ~F~ :: Pull.
- ~:~ :: 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.
#+begin_src emacs-lisp
(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.
#+end_src
Let's always notify ourselves of a file that has [[https://tpapp.github.io/post/check-uncommitted/][uncommited changes]]
---we might have had to step away from the computer and forgotten to commit.
#+begin_src emacs-lisp
(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)))
#+end_src

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.
#+begin_src emacs-lisp
(use-package git-timemachine :defer t)
#+end_src
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.

#+begin_src emacs-lisp
(use-package exec-path-from-shell
:init
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))
#+end_src

See the [[https://github.com/purcell/exec-path-from-shell][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.
#+begin_src emacs-lisp
;; 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.
#+end_src

After an update to Mac OS, one may need to [[https://emacs.stackexchange.com/questions/53026/how-to-restore-file-system-access-in-macos-catalina][restore file system access privileges
to Emacs]].

Here's an example use for Emacs packages that require OS packages:
#+begin_src emacs-lisp :tangle no
(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!
#+end_src
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 [[https://github.com/jwiegley/use-package#use-package-ensure-system-package][use-package-ensure-system-package]] documentation for a flurry of use cases.

The extension makes use of [[https://gitlab.com/jabranham/system-packages][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 [[https://github.com/emacs-helm/helm-system-packages][M-x helm-system-packages]] then ~RET~ to see a system
package's description, or ~TAB~ for the other features!
/This is so cool!/

#+begin_src emacs-lisp
;; An Emacs-based interface to the package manager of your operating system.
(use-package helm-system-packages :defer t)
#+end_src

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 [[https://xmonad.org][xmonad]]
until recently when I obtained a Mac machine and now use [[https://ianyh.com/amethyst/][Amethyst]] ---“Tiling
window manager for macOS along the lines of xmonad.”

#+begin_src emacs-lisp
;; Unlike the Helm variant, we need to specify our OS pacman.
(setq system-packages-package-manager 'brew)
#+end_src
#+begin_src emacs-lisp :tangle no
;; 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")
#+end_src
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, [[http://tuhdo.github.io/helm-intro.html][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!/
#+begin_src emacs-lisp
(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)
("" . helm-execute-persistent-action)))
#+end_src

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:
[[http://tuhdo.github.io/helm-intro.html][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.
#+begin_src emacs-lisp
(setq helm-mini-default-sources '(helm-source-buffers-list
helm-source-recentf
helm-source-bookmarks
helm-source-bookmark-set
helm-source-buffer-not-found))
#+end_src

Incidentally, Helm even provides an [[http://tuhdo.github.io/helm-intro.html#orgheadline24][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~.
#+begin_src emacs-lisp
(system-packages-ensure "surfraw")
; ⇒ “M-x helm-surfraw” or “C-x c s”
#+end_src
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 -- [[https://github.com/ShingoFukuyama/helm-swoop][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~.
#+begin_src emacs-lisp
(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."))
#+end_src

- ~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 [[https://github.com/nex3/perspective-el][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’. )

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

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.
- ~c~ :: Query a perspective to kill.
- ~r~ :: Rename a perspective.
- ~A~ :: Add 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 😃
** Excellent PDF Viewer
Let's install the [[https://github.com/politza/pdf-tools][pdf-tools]] library for viewing PDFs in Emacs.
#+begin_src emacs-lisp
(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.
#+end_src

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 [[https://www.dailymotion.com/video/x2bc1is][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.
#+begin_src emacs-lisp
(setq user-full-name "Musa Al-hassy"
user-mail-address "[email protected]")
#+end_src

For some fun, run this cute method.
#+begin_src emacs-lisp :tangle no
(animate-birthday-present user-full-name)
#+end_src

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 [[https://en.wikipedia.org/wiki/Gnus][GNUS]], which, like GNU itself, is a
recursive acronym: GNUS Network User Service.

1. Execute, rather place in your init:
#+begin_src emacs-lisp
(setq message-send-mail-function 'smtpmail-send-it)
#+end_src
Revert to the default OS mailing method by setting this variable to
~mailclient-send-it~.

2. Follow only the [[https://www.emacswiki.org/emacs/GnusGmail#toc1][quickstart here]]; namely, make a file named ~~/.gnus~ containing:
#+begin_src emacs-lisp :tangle ~/.gnus
;; 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. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")
#+end_src

3. Enable “2 step authentication” for Gmail following [[https://emacs.stackexchange.com/a/33309/10352][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.
#+begin_src shell :tangle no
machine imap.gmail.com login [email protected] password xxxxxxxxxxxxxxxx port imaps
machine smtp.gmail.com login [email protected] password xxxxxxxxxxxxxxxx port 587
#+end_src

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 [[https://www.gnus.org/manual/message.pdf][Message Manual]].

#+begin_src emacs-lisp
;; 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)
#+end_src

Learn more by reading [[https://www.gnu.org/software/emacs/manual/html_mono/gnus.html#Top][The Gnus Newsreader Manual]]; also available within Emacs by
~C-h i m gnus~ (•̀ᴗ•́)و

- Or look at the [[https://www.gnu.org/software/emacs/refcards/pdf/gnus-refcard.pdf][Gnus Reference Card]].
- Or, less comprehensively, this [[https://github.com/redguardtoo/mastering-emacs-in-one-year-guide/blob/master/gnus-guide-en.org#subscribe-groups][outline]].

[[https://www.emacswiki.org/emacs/GnusTutorial][EmacsWiki]] has a less technical and more user friendly tutorial.

*** Prettifications

Let's add the icon  near my mail groups ^_^
#+begin_src emacs-lisp
;; 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))
#+end_src

Next, let's paste in some [[http://groups.google.com/group/gnu.emacs.gnus/browse_thread/thread/a673a74356e7141f][eye-candy for Gnus]]:
#+begin_src emacs-lisp
(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"))
#+end_src

*** Super Terse Tutorial
⟨ See the [[https://www.gnu.org/software/emacs/refcards/pdf/gnus-refcard.pdf][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 [[https://www.gnu.org/software/emacs/manual/html_mono/gnus.html#Limiting][§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/=.

#+begin_src emacs-lisp :tangle "~/.gnus"
(setq gnus-use-cache 'use-as-much-cache-as-possible)
#+end_src

- =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”:
#+begin_src emacs-lisp
(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
#+end_src

- 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-ideas-notes-without-interrupting-the-current-workflow][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.

#+begin_src emacs-lisp
(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
#+end_src

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 [[https://github.com/redguardtoo/gmail2bbdb][gmail2bbdb]], let's convert our Gmail
contacts into a BBDB file ---the [[http://bbdb.sourceforge.net/][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 [[https://github.com/emacs-helm/helm-bbdb][helm-bbdb]] which gives a nice menu
interface.

- From the [[https://www.google.com/contacts][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.

#+begin_src emacs-lisp
(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))
#+end_src

Here is an [[http://emacs-fu.blogspot.com/2009/08/managing-e-mail-addresses-with-bbdb.html][emacs-fu]] article on managing e-mail addressed with bbdb.

*** Feeds to Blogs :Disabled:
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 [[https://github.com/skeeto/elfeed][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.
#+begin_src emacs-lisp :tangle no
;; 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)
(cl-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))
#+end_src

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
[[https://github.com/DamienCassou/beginend][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.
#+begin_src emacs-lisp
;; 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)
(cl-loop for (_ . m) in beginend-modes do (diminish m)))
#+end_src

** 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./

[[https://github.com/kyagi/shell-pop-el][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.

#+begin_src emacs-lisp
(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"))
#+end_src

Now that we have access to quick pop-up for a shell, let's get a pretty and
practical shell: [[https://www.howtogeek.com/362409/what-is-zsh-and-why-should-you-use-it-instead-of-bash/][zsh]] along with the [[https://ohmyz.sh/][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 ^_^

#+begin_src emacs-lisp
;; Be default, Emacs please use zsh
;; E.g., M-x shell
(setq shell-file-name "/bin/zsh")
#+end_src

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 [[https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins#apache2-macports][250+ Plugins]] and [[https://github.com/ohmyzsh/ohmyzsh/wiki/Themes][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 [[https://tldr.sh/][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 𝒳.
#+begin_src emacs-lisp :tangle no
(system-packages-ensure "tldr")
#+end_src

** Restarting Emacs ---Keeping buffers open across sessions?
Sometimes I wish to close then reopen Emacs; unsurprisingly someone's
thought of implementing that.
#+begin_src emacs-lisp
;; Provides only the command “restart-emacs”.
(use-package restart-emacs
;; If I ever close Emacs, it's likely because I want to restart it.
:bind ("C-x C-c" . restart-emacs)
;; Let's define an alias so there's no need to remember the order.
:config (defalias 'emacs-restart #'restart-emacs))
#+end_src

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.
#+begin_example emacs-lisp
;; Keep open files open across sessions.
(desktop-save-mode 1)
(setq desktop-restore-eager 10)
#+end_example

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.
#+begin_src emacs-lisp
(setq-default save-place t)
(setq save-place-file "~/.emacs.d/etc/saveplace")
#+end_src

** 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 😼

#+begin_src emacs-lisp
;; 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)
#+end_src

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.
#+begin_src emacs-lisp
(use-package backup-walker
:commands backup-walker-start)
#+end_src

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!
#+begin_src emacs-lisp
;; 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)
#+end_src

It is intestesting to note that the above snippet could be modified to [[https://stackoverflow.com/a/6918217/3550444][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=.
#+begin_src emacs-lisp
(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)
#+end_src

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.
#+begin_src emacs-lisp
(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)
#+end_src

I like [[https://github.com/Wilfred/helpful][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.