bnb-emacs icon indicating copy to clipboard operation
bnb-emacs copied to clipboard

My (tangled) emacs config

#+TITLE: Beckwith Tangled Emacs Initialization #+STARTUP: show2levels #+OPTIONS: html-link-use-abs-url:nil html-postamble:auto #+OPTIONS: html-preamble:t html-scripts:t html-style:t #+OPTIONS: html5-fancy:nil tex:t #+CREATOR: Emacs 24.3.1 (Org mode 8.2.7a) #+EXPORT_FILE_NAME: index.html #+HTML_CONTAINER: div #+HTML_DOCTYPE: xhtml-strict #+HTML_HEAD: #+HTML_HEAD_EXTRA: #+HTML_LINK_HOME: #+HTML_LINK_UP: #+HTML_MATHJAX: #+INFOJS_OPT: #+LATEX_HEADER: #+PROPERTY: header-args:emacs-lisp :results silent #+HTML_HEAD:

  • Introduction

    This document tangles (in literate programming style) the necessary commands to initialize Emacs to my liking and the documentation for my choices.

    To clone, go to the [[http://github.com/bnbeckwith/bnb-emacs][github repository]]. For a pretty view, head over to the [[http://bnbeckwith.com/bnb-emacs/][generated page]].

** Installation

My =init.el= file is quite simple and is generated by the following block. Essentially, I just have to install this package (=bnb-emacs=) in the [[file:~/.emacs.d/][~/.emacs.d/]] directory and run the following code block (=C-c C-c=) to bootstrap the system.

#+begin_src emacs-lisp :tangle "~/.emacs.d/init.el" :exports code :results silent ;;; init.el --- bnbeckwith config -- eval: (read-only-mode 1) -- ;; START ELPACA INSTALLER (defvar elpaca-installer-version 0.7) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (< emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let ((buffer (pop-to-buffer-same-window "elpaca-bootstrap")) ((zerop (apply #'call-process ("git" nil ,buffer t "clone" ,@(when-let ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (load "./elpaca-autoloads"))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca (,@elpaca-order)) ;; END ELPACA INSTALLER

 ;; Install use-package support
 (elpaca elpaca-use-package
   ;; Enable :elpaca use-package keyword.
   (elpaca-use-package-mode)
   ;; Assume :elpaca t unless otherwise specified.
   (setq elpaca-use-package-by-default t))
 (elpaca-wait)

 (load "~/.emacs.d/full.el")

#+end_src

From there on, the bootstrapping is simple. Emacs finds [[file:~/.emacs.d/init.el][~/.emacs.d/init.el]] and runs the code.

First, I disable =package=, and use the standard =elpaca= initialization. Following that, I enable =elpaca-use-package= so that the rest of this setup can use the standard [[help:use-package][use-package]] interface.

Finally, the output of this file, [[file:~/.emacs.d/full.el][~/.emacs.d/full.el]], is loaded for the complete initialization.

If you are reading this online, the html version of this file is generated by using bnb/export-readme explained in [[*Styled HTML Export][Styled HTML Export]].

** Notes

This section has specific notes that are relevant to my emacs setup in general and this document in particular.

*** Elpaca

A newer package manager, [[https://github.com/progfolio/elpaca][Elpaca]] seeks to be a preferred drop-in
replacement for the built-in =package.el= manager. For the
configuration above, I use the standard installation boilerplate
and enable [[help:use-package][use-package]] support.

This is the quick cheat sheet of commands:
| Operation                             | UI (keys apply in elpaca-ui-mode) | completing-read interface commands               |
|---------------------------------------+-----------------------------------+--------------------------------------------------|
| Finding Packages                      | =M-x elpaca-manager=                | [[help:elpaca-try][elpaca-try]]                                       |
| Trying Packages (for current session) | =i x=                               | [[help:elpaca-try][elpaca-try]]                                       |
| Fetching Package Updates              | =f x=                               | [[help:elpaca-fetch][elpaca-fetch]] or [[help:elpaca-fetch-all][elpaca-fetch-all]]                 |
| Merging Updates                       | =u x=                               | [[help:elpaca-merge][elpaca-merge]] or [[help:elpaca-merge-all][elpaca-merge-all]]                 |
| Pulling Updates*                      | =C-u u x=                           | =C-u M-x elpaca-merge= or =C-u M-x elpaca-merge-all= |
| Rebuilding Packages                   | =r x=                               | [[help:elpaca-rebuild][elpaca-rebuild]]                                   |
| Deleting Packages                     | =d x=                               | [[help:elpaca-delete][elpaca-delete]]                                    |
| View Package Logs                     | =l= filters log to current package  | [[help:elpaca-log][elpaca-log]]                                       |
| Visit Package Repository Directory    | =v=                                 | [[help:elpaca-visit][elpaca-visit]]                                     |
| Visit Package Build Directory         | =C-u v=                             | =C-u M-x elpaca-visit=                             |
| Browse Package Website                | =b=                                 | [[help:elpaca-browse][elpaca-browse]]                                    |

There is also a [[https://github.com/progfolio/elpaca/blob/master/doc/manual.md][helpful manual]].


To see how the startup time has imporoved, let's store when we
start evaluating these settings.

#+begin_src emacs-lisp
  (setq bnb/start-time (float-time))
#+end_src


To aid with general code that needs to run /after/ =elpaca=, the
following macro sets up the right hook.

#+begin_src emacs-lisp
  (defmacro with-after-elpaca-init (&rest body)
      "Adds BODY to `elpaca-after-init-hook`"
      `(add-hook 'elpaca-after-init-hook (lambda () ,@body)))
#+end_src

*** Emacs Build

My current flavor of Emacs comes from:
https://github.com/d12frosted/homebrew-emacs-plus

To install with =brew=, run the following command:
#+begin_src sh :tangle no :eval no
  brew install emacs-plus@29 --with-nobu417-big-sur-icon --with-imagemagick --with-native-comp
#+end_src

Notes: [[https://www.masteringemacs.org/article/whats-new-in-emacs-29-1][What's new in 29.1]]

*** Pending sections

There are some features that I like to take on a /trial run/. These
are marked with the *PENDING* tag to help me remember and evaluate.

*** Performance

By utilizing elements of =use-package=, I can keep an eye on
troublesome packages during startup. Together, these turn on
reporting and set the minimum time to consider when building the
report.

#+begin_src emacs-lisp
  (setq use-package-verbose t
        use-package-compute-statistics t
        use-package-minimum-reported-time 0)
#+end_src

The generated messages will be found in the =*Messsages*= buffer.

There is also the [[elisp:(elpaca-log)][elpaca log]] that can show loading times.
  • Preamble

    This sections houses the settings that need to be made up front and support subsuquent package installation and activiation.

** Default Setup

The full name is used for email messages. And =bnb/biblio= is set to a sensible default. These can be overridden in =.var.el=.

#+begin_src emacs-lisp (setq user-full-name "Benjamin Beckwith" bnb/biblio '("~/references.bib")) #+end_src

** Local customizations (custom.el, username.var.el)

I typically use the customize interface to generate any local
settings such as proxies, paths, fonts, etc. that may vary from
machine to machine. This keeps the setup the same and allows for
only some details to differ.

I like to set the custom file explicitly. Mine resides in the
[[file+emacs:~/.emacs.d/][~/.emacs.d/]] directory. This code block sets the file name and
loads it if it exists.

#+begin_src emacs-lisp
  (setq custom-file "~/.emacs.d/custom.el")
  (if (file-exists-p custom-file)
      (load-file custom-file))
#+end_src

If the file doesn't exist, =Emacs= will still use the file if any
changes are made through the /custom interface/.

Sometimes I'll get bad settings or cruft in that file. I now have a
key, ~<F7>~, for easy navigation to wherever the =custom-file= points.

*** Local variables (user-login-name)

I also intend to have a generic call to an installed local file
that may need to behave differently from =custom.el=. This loads
last so that it can modify any existing setting made here to work
on the specific system in question.

In the code below, I add =~/.emacs.d/= to the load path and have a
protected call to [[help:load-library][load-library]].  If the file exists, it gets
loaded, otherwise the error normally returned if the file is
non-existent gets ignored.

 #+begin_src emacs-lisp
   (condition-case err
       (progn
         (load-file (format "~/.emacs.d/%s.vars.el"  user-login-name))
         (message "Loaded local settings file %s.vars.el" user-login-name))
     (file-error
      (message "Skipping %s.vars library as it does not exist." user-login-name))
     nil)
 #+end_src

** Early Initialization

There are a few optimizations to make so that emacs can get initialized quickly. First, setup the garbage collector to have a default value of 16mb and a initializtion time value of =most-positive-fixnum=.

This prevents garbage collection from pausing evaluation during startup. After startup, I leverage the hook to reset the optimizations down to their default values.

The next setting stores [[help:file-name-handler-alist][file-name-handler-alist]] and then sets it to =nil=. By doing this, there is no automatic handler evalutation happening during startup. This setting goes back to its original value post startup.

Finally, user interface elements are hidden early to have a nice streamlined interface.

#+begin_src emacs-lisp :tangle "~/.emacs.d/early-init.el" :exports code :results silent ;; Disable package enabling at startup (setq package-enable-at-startup nil)

 ;; Tweak garbage collection threshold
 (defvar default-gc-cons-threshold 16777216 ; 16mb
   "my default desired value of `gc-cons-threshold'
 during normal emacs operations.")

 ;; make garbage collector less invasive
 (setq
  gc-cons-threshold most-positive-fixnum
  gc-cons-percentage 0.6)

 (setq
  default-file-name-handler-alist file-name-handler-alist
  file-name-handler-alist nil)

 (add-hook
  'emacs-startup-hook
  (lambda (&rest _)
    (setq
     gc-cons-threshold
     default-gc-cons-threshold
     gc-cons-percentage 0.1
     file-name-handler-alist default-file-name-handler-alist)

    ;; delete no longer necessary startup variable
    (makunbound 'default-file-name-handler-alist)))

#+end_src

The block above is written to [[file+emacs:~/.emacs.d/early-init.el][~/.emacs.d/early-init.el]] and automatically evaluated first by emacs.

*** Init debug assistance

#+begin_src emacs-lisp
  (defmacro comment (&rest body)
"Comment out sexps in BODY"
nil)
#+end_src

** Libraries

This section hosts early loading of libraries required by subsequent packages.

*** Dash

The modern list library, [[https://github.com/magnars/dash.el][Dash]], provides a set of common list
manipulation functions (all prepended with '-', hence the name).

#+begin_src emacs-lisp
  (use-package dash
    :ensure t)
#+end_src

*** Delight

The mode line can get pretty busy showing all of the package
names. [[https://www.gnu.org/software/emacs/manual/html_node/use-package/Delight.html][Delight]] helps tone it down by removing some packages from
showing up, or changing their name to something shorter.

In =use-package= delcarations, I use the =:delight= keyword to set a
string to represent the package. It is also possible to provide
elisp for evaluation.

#+begin_src emacs-lisp
  (use-package delight :ensure t)
#+end_src

*** Hydra

Sometimes it is useful to go into a /command mode/ that lets you
quickly do a few different actions. [[https://github.com/abo-abo/hydra][Hydra]] does that and more.

By defining specific /hydras/, you can group together commands with
documentation. Think of it as a mini-control-panel. I include it
here and use it elsewhere when grouping commands. (See [[Toggle Map]]
for an example)

#+begin_src emacs-lisp
  (use-package hydra
    :ensure t)
#+end_src

**** Major mode and Pretty Hydra

 #+begin_src emacs-lisp
   (use-package major-mode-hydra
     :ensure t
     :demand t
     :bind  ("s-." . major-mode-hydra))
 #+end_src

*** Seq

[[*Magit][Magit]] needs an updated [[https://elpa.gnu.org/packages/seq.html][seq]], so we can install it here. Note that
the functions below unload the library if already loaded, and then
does the correct install.

#+begin_src emacs-lisp
      ;;; Take care of the seq dependency
  (defun +elpaca-unload-seq (e)
    (and (featurep 'seq) (unload-feature 'seq t))
    (elpaca--continue-build e))
  (defun +elpaca-seq-build-steps ()
    (append (butlast (if (file-exists-p (expand-file-name "seq" elpaca-builds-directory))
                         elpaca--pre-built-steps elpaca-build-steps))
            (list '+elpaca-unload-seq 'elpaca--activate-package)))

  (use-package seq :ensure `(seq :build ,(+elpaca-seq-build-steps)))
#+end_src

** Coda

#+begin_src emacs-lisp ;;; Wait for this to be processed before packages that depend on it (elpaca-wait) #+end_src

  • Settings

    The sections here contain mostly settings that configure keymaps, command launchers, built-in features, and other details for day-to-day life.

** Keys

These sections contain setting related to keys and keymaps.

*** Binding Keys

For binding keys, I use the [[https://github.com/jwiegley/use-package/blob/master/bind-key.el][bind-key]] package. Not only does it
easily bind keys, but it does so with some nice features.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (bind-keys ("C-h B" . describe-personal-keybindings)
               ("<f7>"  . (lambda () (interactive (find-file custom-file))))))
#+end_src

By using ~bind-key~, you can specify the keystrokes that invoke a
command. In the example above, we bind functions to the global key
map. Note that in later settings, there are also examples of
mapping keys within local keymaps.

If you also want to override any possible minor-mode bindings of
the same keys, you can use ~bind-key*~ instead.

There is also an ~unbind-key~ to, of course, remove any binding.

The real kicker is that it will keep track of these bindings and
let you see a summary of your customizations with

: M-x describe-personal-keybindings

This is bound to ~C-h B~ above.

As of emacs 28.1, there is a setting to group bindings into an
outline format. Use the following settings with ~M-x
describe-bindings~ or ~C-h b~.

#+begin_src emacs-lisp
  (setq describe-bindings-outline t)
#+end_src

*** Personal Keymaps

The following settings are inspired from
[[http://endlessparentheses.com/the-toggle-map-and-wizardry.html]].

**** Toggle Map

 This toggle map shows the current /toggleable/ settings with
 shortcut keys for enabling. The amaranth color makes this buffer
 stay around until I press =q=.

 What are these settings?
 
 #+CAPTION: Toggle Map Functions
 #+LABEL: tbl:toggle-map
 | Key | Function                  | Description                                  |
 |-----+---------------------------+----------------------------------------------|
 | =c=   | [[help:column-number-mode][column-number-mode]]        | Toggle column number display in the modeline |
 | =e=   | [[help:toggle-debug-on-error][toggle-debug-on-error]]     | Enter debugger on error                      |
 | =u=   | [[help:toggle-debug-on-quit][toggle-debug-on-quit]]      | Enter debugger on =C-g=                        |
 | =f=   | [[help:auto-fill-mode][auto-fill-mode]]            | Automatic line breaking                      |
 | =t=   | [[help:toggle-truncate-lines][toggle-truncate-lines]]     | Truncate long lines in the buffer            |
 | =r=   | [[help:dired-toggle-read-only][dired-toggle-read-only]]    | Read-only mode                               |
 | =w=   | [[help:whitespace-mode][whitespace-mode]]           | Whitespace visualization                     |
 | =b=   | [[help:orgtbl-mode][orgtbl-mode]]               | Use org table minor mode (non-org buffers)   |
 | =x=   | [[help:bnb/transparency-next][bnb/transparency-next]]     | Cycle forward through transparency settings  |
 | =X=   | [[help:bnb/transparency-previous][bnb/transparency-previous]] | Cycle backward through transparency settings |
 | =B=   | [[help:display-battery-mode][display-battery-mode]]      | Show battery info in modeline                |
 | =l=   | [[help:hl-line-mode][hl-line-mode]]              | Highlight current line                       |
 | =m=   | [[help:bnb/hide-mode-line-mode][bnb/hide-mode-line-mode]]   | Toggle mode line                             |
 
 #+begin_src emacs-lisp
   (with-after-elpaca-init
     (pretty-hydra-define hydra-toggle (:color amaranth :quit-key "q" :title "๏ˆ…  TOGGLES")
       ("Basic"
        (("c" column-number-mode "col number" :toggle t)
         ("l" hl-line-mode "highlight line" :toggle t)
         ("f" auto-fill-mode "auto-fill" :toggle t)
         ("t" toggle-truncate-lines "truncate lines" :toggle truncate-lines))
        "Minor"
        (("r" rainbow-mode "rainbow" :toggle t)
         ("w" whitespace-mode "whitespace" :toggle t)
         ("b" orgtbl-mode "Org table" :toggle t)
         ("R" dired-toggle-read-only "dired read only" :toggle t))
        "UI"
        (("m" bnb/hide-mode-line-mode "hide mode line" :toggle t)
         ("B" display-battery-mode "display battery" :toggle t)
         ("x" bnb/transparency-next "transparency next")
         ("X" bnb/transparency-previous "transparency prev"))
        "Emacs"
        (("D" toggle-debug-on-error "debug on error" :toggle (default-value 'debug-on-error))
         ("X" toggle-debug-on-quit "debug on quit" :toggle (default-value 'debug-on-quit)))))
     (bind-key "C-x t" 'hydra-toggle/body))
 #+end_src

**** Whitespace

 This mode (used in the keymap above) toggles a mode that shows
 the different whitespace in a buffer.
 
 #+begin_src emacs-lisp
   (use-package whitespace
     :ensure nil
     :commands (whitespace-mode)
     :custom
     (whitespace-line-column nil)
     :delight " ๐ŸŸ‚")
 #+end_src

****** Deletion

   By default, ~M-\~ performs =delete-horizontal-space= and will
   consume all of the whitespace present.

   I'd like it to be smart and leave one or no spaces if
   possible. The =fixup-whitespace= function will do that.

   #+begin_src emacs-lisp
     (with-after-elpaca-init
       (bind-key "M-k" 'fixup-whitespace))
   #+end_src

***** Scroll window up/down

  In addition to moving the cursor, it is also interesting to
  scroll the screen (without moving the cursor with respect to the
  frame).

  #+begin_src emacs-lisp
    (defun bnb/scroll-up-1 ()
      "Scroll up by one line."
      (interactive)
      (cua-scroll-up 1))

    (defun bnb/scroll-down-1 ()
      "Scroll down by one line."
      (interactive)
      (cua-scroll-down 1))

    (with-after-elpaca-init
      (with-eval-after-load 'bind-key
        (bind-keys
         ("M-n" . bnb/scroll-up-1)
         ("M-p" . bnb/scroll-down-1))))
  #+end_src

***** Align Regexp

  When selecting a region, a quick trip to [[help:align-regexp][align-regexp]] can align
  all of that nasty text.

  #+begin_src emacs-lisp
    (with-after-elpaca-init
      (with-eval-after-load 'bind-key
        (bind-key "C-c TAB" 'align-regexp)))
  #+end_src

**** Kill current buffer

 Another great tip from [[http://pragmaticemacs.com/emacs/dont-kill-buffer-kill-this-buffer-instead/][Pragmatic Emacs]], use [[help:kill-this-buffer][kill-this-buffer]] to
 kill the current buffer instead of asking which one.  I'm not
 overriding the =C-x k= default, but added a =C-x C-k= alternative.

 #+begin_src emacs-lisp
   (defun bnb/kill-this-buffer ()
     "Kill the current buffer"
     (interactive)
     (kill-buffer (current-buffer)))

   (with-after-elpaca-init
     (bind-keys
      ("C-x C-k" . bnb/kill-this-buffer)))
 #+end_src

*** Super keys

I like to be able to use the command (or super or hyper) keys for
shortcuts. I need to take care to not interfere with the built-in
operating system shortcuts or my bindings will not work.

#+begin_src emacs-lisp
  (setq mac-function-modifier 'hyper
        mac-pass-command-to-system nil
        mac-right-option-modifier 'none
        mac-right-command-modifier 'hyper
        mac-right-control-modifier 'hyper
        mac-command-modifier 'meta
        mac-control-modifier 'ctrl
        mac-option-modifier 'super)
#+end_src

Note that the right =option= and =command= keys will pass through to
the system. This is especially cool for the =option= key on a mac
that lets insert special characters directly. (E.g. รก or โˆ‘ or ยฎ)

Inspiration for the keys comes from [[https://www.wisdomandwonder.com/article/10146/every-emacser-can-use-hyper-on-every-usb-hid-keyboard][wisdom and wonder]].

** Command Launchers

This section holds the settings for my two main command launchers: hydra and vertico.

*** Hydra

Sometimes it is useful to go into a /command mode/ that lets you
quickly do a few different actions. Hydra does that and more.

By defining specific /hydras/, you can group together commands with
documentation. Think of it as a mini-control-panel. I include it
here and use it elsewhere when grouping commands. (See [[Toggle Map]]
for an example)

The setup is in [[*Hydra][Hydra]] so that I can use it with the previous
keybinding commands.

*** Vertico

Or [[https://github.com/minad/vertico][VERTical Interactive COmpletion]], is my preferred completion
interface.

#+begin_src emacs-lisp
  (use-package vertico
    :ensure t
    :config (vertico-mode))
#+end_src

**** Vertico Directory

 The [[https://github.com/minad/vertico/blob/main/extensions/vertico-directory.el][directory]] extension navigates directories like =Ido=.
 
 #+begin_src emacs-lisp
   ;; Configure directory extension.
   (use-package vertico-directory
     :after vertico
     :ensure nil
     ;; More convenient directory navigation commands
     :bind (:map vertico-map
                 ("RET"   . vertico-directory-enter)
                 ("DEL"   . vertico-directory-delete-char)
                 ("M-DEL" . vertico-directory-delete-word)
                 ("?"     . minibuffer-completion-help))
     ;; Tidy shadowed file names
     :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
 #+end_src

**** Embark

 The [[https://github.com/oantolin/embark][embark]] package helps find actions relevant to what is near
 the point. With =C-.=, a menu pops up with actions to choose from.

 #+begin_src emacs-lisp
   (use-package embark
     :ensure t
     :bind
     (("C-." . embark-act)
      ("C-;" . embark-dwim)
      ("C-x ." . embark-act)
      ("C-x ;" . embark-dwim)
      ("C-h C-b" . embark-bindings))
     :init
     (setq prefix-help-command #'embark-prefix-help-command)
     :config
     (add-to-list 'display-buffer-alist
                  '("\\'\\*Embark Collect \\(Live\\|Comletions\\)\\*"
                    nil
                    (window-parameters (mode-line-format . none)))))

   (use-package embark-consult
     :after (emark consult)
     :ensure t
     :hook
     (embark-collect-mode . consult-preview-at-point-mode))
 #+end_src

**** Orderless

 Easy completion is possible with [[https://github.com/oantolin/orderless][Orderless.]] This completion
 framework lets users utilize matching elements separated by
 spaces.

 #+begin_src emacs-lisp
   (use-package orderless
     :ensure t
     :custom
     (completion-styles '(orderless basic))
     (completion-category-overrides '((file (styles basic partial-completion)))))
 #+end_src

 Within the matching framework, a few /dispatchers/ can modify the
 subsequent matchers. The following table summarizes these
 elements.

 | Character | Effect                            |
 |-----------+-----------------------------------|
 | =!=         | Does /not/ match following literal  |
 | =,=         | Matches initial characters        |
 | ===         | Forces a literal match            |
 | =~=         | Uses the flex matching            |
 | =%=         | Matches while ignoring diacritics |

**** Consult

 Rounding out the completion helpers, [[https://github.com/minad/consult][Consult]] provides specific
 functions that help complete actions or find elements. The
 bindings are supplied below.

 #+begin_src emacs-lisp
   (use-package consult
     :ensure t
     :bind (;; C-c bindings
            ("C-c h" . consult-history)
            ("C-c m" . consult-mode-command)
            ("C-c b" . consult-bookmark)
            ("C-c k" . consult-macro)
            ("C-c o" . consult-outline)
            ;; C-x bindings
            ("C-x b"   . consult-buffer)
            ("C-x 4 b" . consult-buffer-other-window)
            ("C-x 5 b" . consult-buffer-other-frame)
            ("C-x r x" . consult-register)
            ("C-x r b" . consult-bookmark)
            ;; Custom M bindings
            ("M-g o" . consult-ouline)
            ("M-y"   . consult-yank-pop)
            ("M-i"   . consult-imenu))
     :config
     (defvar bnb/org-agendas
       (list :name "Org Agenda Files"
             :category 'file
             :narrow   ?a
             :face     'consult-file
             :history  'file-name-history
             :action   #'consult--file-action
             :items    #'org-agenda-files))
     (add-to-list 'consult-buffer-sources 'bnb/org-agendas 'append)
     :init
     (fset 'multi-occur #'consult-multi-occur))
 #+end_src

 One of the more interesting feaures is virtual buffers. When
 viewing buffers, recent files, bookmarks, and similar, the
 interface shows the buffer as you are selecting so that you can
 have the right file context for the line you are selecting.

 The [[help:consult-buffer][consult-buffer]] command is powerful and has specific key
 sequences that can narrow the buffer list in useful ways.  These
 are summarized in the following list.

 - =b <SPC>= :: buffers
 - =<SPC>= :: hidden buffers
 - =* <SPC>= :: modified buffers
 - =f <SPC>= :: files
 - =r <SPC>= :: file registers
 - =m <SPC>= :: bookmarks
 - =p <SPC>= :: project


 In the code block above, I add one more, =a <SPC>= that will show
 the available [[help:org-agenda-files][org-agenda-files]] for easy selection.

**** Marginalia

 The great thing about vertical completion is the extra horizontal
 space. [[https://github.com/minad/marginalia][Marginalia]] makes use of this extra space by providing
 relevant extra information about each element on the line.

 #+begin_src emacs-lisp
   (use-package marginalia
     :ensure t
     :bind (:map minibuffer-local-map
                 ("M-A" . marginalia-cycle))
     :init
     (marginalia-mode)
     :config
     (setq marginalia-annotators
           '(marginalia-annotators-heavy marginalia-annotators-light)))
 #+end_src

** Expansion & Completion

This section defines interations with text expansion systems.

*** Abbrev

The following block is courtesy of [[http://endlessparentheses.com/ispell-and-abbrev-the-perfect-auto-correct.html][Endless Parentheses]]. For
regular misspellings, we can do [[help:ispell][ispell]] and then make an
abbreviation for future corrections.

#+begin_src emacs-lisp
  (defun bnb/ispell-word-then-abbrev (p)
    "Call `ispell-word'. Then create an abbrev for the correction
      made. With prefix P, create local abbrev. Otherwise, it will be
      global."
    (interactive "P")
    (let ((bef (downcase (or (thing-at-point 'word) ""))) aft)
      (call-interactively 'ispell-word)
      (setq aft (downcase (or (thing-at-point 'word) "")))
      (unless (string= aft bef)
        (message "\"%s\" now expands to \"%s\" %sally"
                 bef aft (if p "loc" "glob"))
        (define-abbrev
          (if p global-abbrev-table local-abbrev-table)
          bef aft))))

  (use-package abbrev
    :ensure nil
    :delight "โ€‰โš†"
    :bind (("C-x C-i" . bnb/ispell-word-then-abbrev))
    :config
    (setq save-abbrevs t)
    (setq-default abbrev-mode t))
#+end_src

*** Cape

"Let your completions fly!" -- [[https://github.com/minad/cape][cape.el]]

Cape provies a set of completion backends avaialble right on bound
keys. It works with [[*Corfu][Corfu]].

#+begin_src emacs-lisp
  ;; Add extensions
  (use-package cape
    :ensure t
    ;; Bind dedicated completion commands
    ;; Alternative prefix keys: C-c p, M-p, M-+, ...
    :bind (("C-c p p" . completion-at-point) ;; capf
           ("C-c p t" . complete-tag)        ;; etags
           ("C-c p d" . cape-dabbrev)        ;; or dabbrev-completion
           ("C-c p h" . cape-history)
           ("C-c p f" . cape-file)
           ("C-c p k" . cape-keyword)
           ("C-c p s" . cape-elisp-symbol)
           ("C-c p e" . cape-elisp-block)
           ("C-c p a" . cape-abbrev)
           ("C-c p l" . cape-line)
           ("C-c p w" . cape-dict)
           ("C-c p :" . cape-emoji)
           ("C-c p \\" . cape-tex)
           ("C-c p _" . cape-tex)
           ("C-c p ^" . cape-tex)
           ("C-c p &" . cape-sgml)
           ("C-c p r" . cape-rfc1345))
    :init
    ;; Add to the global default value of `completion-at-point-functions' which is
    ;; used by `completion-at-point'.  The order of the functions matters, the
    ;; first function returning a result wins.  Note that the list of buffer-local
    ;; completion functions takes precedence over the global list.
    (add-to-list 'completion-at-point-functions #'cape-dabbrev)
    (add-to-list 'completion-at-point-functions #'cape-file)
    (add-to-list 'completion-at-point-functions #'cape-elisp-block)
    ;;(add-to-list 'completion-at-point-functions #'cape-history)
    ;;(add-to-list 'completion-at-point-functions #'cape-keyword)
    ;;(add-to-list 'completion-at-point-functions #'cape-tex)
    ;;(add-to-list 'completion-at-point-functions #'cape-sgml)
    ;;(add-to-list 'completion-at-point-functions #'cape-rfc1345)
    ;;(add-to-list 'completion-at-point-functions #'cape-abbrev)
    ;;(add-to-list 'completion-at-point-functions #'cape-dict)
    ;;(add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
    ;;(add-to-list 'completion-at-point-functions #'cape-line)
    )
#+end_src

*** Corfu

Taking in-buffer completion to the next level, [[https://github.com/minad/corfu][Corfu]] gives familar
functionality with nice enhancements. It integrates with orderless
for easier searching, and has the ability to show documentation
alongside of the completion popup.
    
#+begin_src emacs-lisp
  (use-package corfu
    :ensure t
    :custom
    (corfu-auto nil)
    (tab-always-indent 'complete)
    :bind
    (:map corfu-map ("SPC" . corfu-insert-separator))
    :init
    (global-corfu-mode)
    (corfu-popupinfo-mode 1))
#+end_src

**** Terminal support

 Because Corfu uses child frames, terminal support needs to be
 added that leverages overlays for non-graphical frames.

 #+begin_src emacs-lisp
   (use-package corfu-terminal
     :if (not (display-graphic-p))
     :ensure (corfu-terminal
              :host github
              :repo "https://codeberg.org/akib/emacs-corfu-terminal.git"))
 #+end_src

*** Yasnippet :PENDING:

Text expansion makes sense in many programming modes. [[https://joaotavora.github.io/yasnippet/index.html][Yasnippet]]
comes in handy by providing a minor mode for easy expansions.
 
#+begin_src emacs-lisp
  (use-package yasnippet
    :ensure t
    :defer 30
    :hook
    (prog-mode . yas-minor-mode)
    (text-mode . yas-minor-mode)
    :config
    (yas-reload-all))
#+end_src

I also load a collection of [[https://github.com/AndreaCrotti/yasnippet-snippets][yasnippet snippets]] so I don't have to
maintain my own.
 
#+begin_src emacs-lisp
  (use-package yasnippet-snippets
    :ensure t)
#+end_src

*** Hippie Expand

Try to expand the text before point in an intelligent way. Repeat
the keypress to cycle through options.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (bind-key "M-/" 'hippie-expand))
#+end_src

** Built-in Features

Emacs comes with some nice batteries. This section configures my favorites.

*** Backups

Sensible backup settings from [[https://www.emacswiki.org/emacs/BackupDirectory]]

#+begin_src emacs-lisp
  (setq backup-by-copying t
        create-lockfiles nil
        backup-directory-alist '((".*" . "~/.emacs.d/.saves"))
        ;; auto-save-file-name-transforms `((".*" "~/.saves" t))
        kill-buffer-delete-auto-save-files t
        delete-old-versions t
        kept-new-versions 6
        kept-old-versions 2
        version-control t)
#+end_src

Here's a quick rundown of the settings:

- [[help:backup-by-copying][backup-by-copying]] :: Use copying to create backups when ~t~
- [[help:create-lockfile][create-lockfiles]] :: Don't use lockfiles if ~nil~
- [[help:backup-directory-alist][backup-directory-alist]] :: List of regexp/location pairs of where to backup files
- [[help:backup-directory-alist][kill-buffer-delete-auto-save-files]] :: Killing a buffer with an auto-save file will prompt for deletion
- [[help:delete-old-versions][delete-old-versions]] :: Delete excess backups silently if ~t~
- [[help:kept-new-versions][kept-new-versions]] :: Number of newest versions to keep
- [[help:kept-old-versions][kept-old-versions]] :: Number of oldest versions to keep
- [[help:version-control][version-control]] :: When ~t~, make numeric backup versions always

*** Default File encoding

I like to have the files be =utf-8= by default. Do
let me know if I shouldn't do this, will you?

Set =utf-8= for all coding systems except for the clipboard on
windows. That one gets =utf-16le= to be compatible.

#+begin_src emacs-lisp
  (prefer-coding-system       'utf-8)
  (set-default-coding-systems 'utf-8)
  (set-terminal-coding-system 'utf-8)
  (set-keyboard-coding-system 'utf-8)
  (set-language-environment 'utf-8)
  (setq buffer-file-coding-system 'utf-8
        x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
  ;; MS Windows clipboard is UTF-16LE
  (when (eq system-type 'windows-nt)
    (set-clipboard-coding-system 'utf-16le-dos))
#+end_src

*** Native Compilation

Emacs 28.1 introduced [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Native-Compilation.html][Native Compilation]]. When this feature is
available, I use it to compile the packages.

There are also two settings to make the process slightly more
verbose and ensure that warnings and erros are bubbled up from any
async processes.

#+begin_src emacs-lisp
  (if (native-comp-available-p)
      (setq package-native-compile t
            native-comp-verbose 1
            native-comp-async-report-warnings-errors t))
#+end_src

*** Path

Sometimes Emacs' idea of path differs from the shell. The package
[[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] seeks to bring those in line with each other.

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

*** Server

[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html][Using Emacs as a server]] is a great way to keep the power
responsive.

#+begin_src emacs-lisp
  (when (and (or (eq system-type 'windows-nt) (eq system-type 'darwin))
             (not (and (boundp 'server-clients) server-clients))
             (not (daemonp)))
    (server-start))
#+end_src

*** Sounds

I dislike the bell ringing when I hit =C-g=. To silence the bell,
just set the =ring-bell-function= to =nil=.

#+begin_src emacs-lisp
  (setq visual-bell nil
        ring-bell-function `(lambda () nil))
#+end_src

*** Recentf

I enable emacs remembering recently open files. For my setup, this
feeds into the candidates for [[*Consult][Consult]].

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (recentf-mode t))
#+end_src

*** Timezones

For [[help:world-clock][world-clock]], it's best to define the time zones most relevant
to me. For compatible time zones, check [[https://en.wikipedia.org/wiki/List_of_tz_database_time_zones][this handy list]].

#+begin_src emacs-lisp
  (setq zoneinfo-style-world-list
        '(("America/New_York" "CBUS")
          ("America/Los_Angeles" "San Fran")
          ("Europe/London" "London")
          ("Australia/Sydney" "Sydney")
          ("Asia/Kolkata" "Bangalore")))
#+end_src

*** Isearch

Folding quotes will allow isearch to find /similar/ characters to
the ones being searched for.

#+begin_src emacs-lisp
  ;; New in Emacs 29
  (setq isearch-fold-quotes-mode t)
#+end_src

** Minibuffer

This section holds any =minibuffer= settings.

*** Minibuffer History

Let's get rid of duplicates in the minibuffer history.

#+begin_src emacs-lisp
  (setq history-delete-duplicates t)
#+end_src

This saves the minibuffer histories to preserve across emacs
sessions.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (setq savehist-additional-variables '(search-ring regexp-search-ring)
          savehist-file "~/.emacs.d/savehist")
    (savehist-mode t))
#+end_src

** Movement

Getting around takes a little tweaking. This section holds the details on how movement is defined for me.

*** Ace Utilities

The Ace (and subsequent Avy) packages aid in jumping the cursor to
the right place in the buffer.

**** Ace Flyspell

 Turn on [[https://github.com/cute-jumper/ace-flyspell][ace-flyspell]] when flyspell is enabled. This mode helps
 jump between the errors (misspellings) discovered by flyspell.

 #+begin_src emacs-lisp
   (use-package ace-flyspell
     :after (hydra major-mode-hydra) 
     :ensure t
     :commands (ace-flyspell-setup)
     :bind
     ("H-s" . hydra-fly/body)
     :hook
     (flyspell-mode . ace-flyspell-setup)
     :init
     (pretty-hydra-define hydra-fly (:color pink :quit-key "q" :title "๎ŠŽ  Flyspell")
       ("Checking"
        (("b" flyspell-buffer "Check buffer")
         ("r" flyspell-region "Check region"))
        "Correction"
        (("c" ispell-word "Correct word")
         ("." ace-flyspell-dwim "dwim"))
        "Movement"
        (("n" flyspell-goto-next-error "Next error")
         ("j" ace-flyspell-jump-word "Jump word")))))
 #+end_src

**** Ace Isearch

 Supercharge ~isearch~ to vary its behavior depending on the
 input. The ~C-'~ key let's me jump to the isearch match easily
 with the ~ace-jump~ methods.

 #+begin_src emacs-lisp
   (use-package ace-isearch
     :ensure t
     :bind (:map isearch-mode-map
                 ("C-'" . ace-isearch-jump-during-isearch))
     :delight ace-isearch-mode
     :config
     (global-ace-isearch-mode t)
     (setq ace-isearch-input-length 8))
 #+end_src

**** Ace Link

 In modes with links, use =o= to jump to links. Map =M-o= to do the
 same in [[*Orgmode][Orgmode]].

 #+begin_src emacs-lisp
   (use-package ace-link
     :ensure t
     :bind (:map org-mode-map ("M-o" . ace-link-org))
     :config (ace-link-setup-default))
 #+end_src

**** Ace Window

 Instead of =C-x o= traversal, =ace-window= provides numbers
 for quick window access

 Set the keys to something other than the default numbers. Note
 that this also limits the number of windows that can be used, but
 given my usage, I doubt it goes up to 'm' often.

 Also, I modify the face attribute to make the window numbers large.

 After reading [[https://github.com/abo-abo/ace-window/wiki][the wiki]], I supercharged the interface for =ace-window=.

 #+begin_src emacs-lisp
   (use-package ace-window
     :ensure t
     :bind
     ("H-SPC"  . ace-window)
     ("<f9> a" . ace-window)
     :custom
     (aw-keys '(?j ?k ?l ?\; ?a ?s ?d ?f))
     (aw-leading-char-style 'path)
     (aw-dispatch-always t))

   (with-after-elpaca-init
     (progn
       (pretty-hydra-define hydra-window-controls (:color amaranth :quit-key "q" :title "๎˜ช Window controls")
         ("Window Size"
          (("h" shrink-window-horizontally "shrink horizontal")
           ("j" shrink-window "shrink vertical")
           ("k" enlarge-window "enlarge vertical")
           ("l" enlarge-window-horizontally "enlarge horizontal"))
          "Scroll other window"
          (("n" scroll-other-window "scroll")
           ("p" scroll-other-window-down "scroll down"))))
       (pretty-hydra-define hydra-frame-controls (:color red :title "๎ฎ‹ Frame controls")
         ("Modification"
          (("f" make-frame "new frame")
           ("x" delete-frame "delete frame"))))
       (with-eval-after-load 'ace-window
         (progn
           (add-to-list 'aw-dispatch-alist '(?w hydra-window-controls/body) t)
           (add-to-list 'aw-dispatch-alist '(?F hydra-frame-controls/body) t)
           (add-to-list 'aw-dispatch-alist '(?B balance-windows) t)
           (set-face-attribute 'aw-leading-char-face nil :height 2.0)))))
 #+end_src

**** Avy Goto

 Navigating to the right spot in a buffer can be done in an easy
 fashion with [[https://github.com/abo-abo/avy][Avy]]. The collection of /goto/ functions yield a
 variety of methods to select where to place the point.

 In the set of mappings below, it's easy to see the /thing/ you are
 targeting (word, char, line), and how you are targeting it. The
 how is the suffix.

 A suffix of =1= means you will input one character to show the
 candidates. A suffix of =0= will list all candidates without an
 initial selection. A suffix of =2= means you'll input two
 characters before showing candidates. Finally, a suffix of =timer=
 will accept several characters and then show the candidates after
 an elapsed timer.

 #+begin_src emacs-lisp
   (use-package avy
     :ensure t
     :bind
     ("H-." . avy-goto-char-timer)
     ("H-w"   . avy-goto-word-1)
     ("H-/"   . avy-goto-char-2)
     ("H-l"   . avy-goto-line)
     ("H-d"   . avy-goto-word-0)
     ("<f9> ." . avy-goto-char-timer)
     ("C-c g" . avy-goto-word-1)
     ("M-g l" . avy-goto-line)
     ("M-g ." . avy-goto-char-2)
     ("M-g w" . avy-goto-word-0))
 #+end_src

 The commands begin with the normal prefix of =M-g= for the goto
 commands and use l,c and w for lines, characters and words
 respectively.

**** Avy Zap

 Zap to char using avy. This is just what is sounds like. You kill
 everything from point to the selected character.

 #+begin_src emacs-lisp
   (use-package avy-zap
     :ensure t
     :bind
     ("M-z" . avy-zap-to-char-dwim)
     ("M-Z" . avy-zap-up-to-char-dwim))
 #+end_src

*** Errors

When navigating errors (output from ~M-x compile~ for example), this
highlights the visited error. Although named for errors, this
functionality is also used for ~M-x occur~ and ~M-x rgrep~ and others.

Within the buffer full of errors or matches, ~M-g M-n/M-p~ will
navigate up/down visiting the errors in a separate buffer and
highlighting the current error or match.

#+begin_src elisp
  (setq next-error-message-highlight t)
#+end_src

*** Read-only helpers

For read-only files, look at them in [[help:view-mode][view-mode]] which will enable
vi-style navigation. In this mode, kill commands will save text,
but not remove it.

#+begin_src emacs-lisp
  (use-package view
    :ensure nil
    :delight "โ€‰๐Ÿ‘"
    :init (setq view-read-only t)
    :bind (:map view-mode-map
                ("n" . next-line    )
                ("p" . previous-line)
                ("j" . next-line    )
                ("k" . previous-line)
                ("l" . forward-char)
                ("h" . bnb/view/h)
                ("q" . bnb/view/q))
    :config
    (defun bnb/view/h ()
      "Setup a function to go backwards a character"
      (interactive)
      (forward-char -1))
    (defun bnb/view/q ()
      "Setup a function to quit `view-mode`"
      (interactive)
      (view-mode -1)))
#+end_src

*** Scroll Screen Position

This is one of those cool finds for a problem I mostly knew that I
had. I often hit =C-v= by accident and lose my place. With the
following setting, =M-v= completely undoes the scroll leaving the
cursor back in the original position.

#+begin_src emacs-lisp
  (setq scroll-preserve-screen-position 'always)
#+end_src

Thanks to http://irreal.org/blog/?p=3963 for the tip.

** Custom Helpers

This is a collection of code specific to how I use emacs. Some are from different websites or other Emacs users.

*** Auto-display agenda

[[http://lists.gnu.org/archive/html/emacs-orgmode/2010-03/msg00367.html][John Weigley shows a way]] to display the agenda after some period
of inactivity.

#+begin_src emacs-lisp
  (defun bnb/jump-to-org-agenda ()
    "Create and jump to the bnb org agenda."
    (interactive)
    (let ((buf (get-buffer "*Org Agenda*"))
          wind)
      (if buf
          (if (setq wind (get-buffer-window buf))
              (select-window wind)
            (if (called-interactively-p)
                (progn
                  (select-window (display-buffer buf t t))
                  (org-fit-window-to-buffer))
              (with-selected-window (display-buffer buf)
                (org-fit-window-to-buffer))))
        (org-agenda nil "f."))))

  (defun bnb/idle-agenda (&optional arg)
    "Set or cancel idle agenda timer based on [ARG]."
    (interactive "P")
    (setq bnb/iagenda
          (if arg
              (cancel-timer bnb/iagenda)
            (run-with-idle-timer 3600 t 'bnb/jump-to-org-agenda))))

  (with-after-elpaca-init
    (bnb/idle-agenda))
#+end_src

*** Auto-indent when pasting

Automatically indent pasted blocks of text.

#+begin_src elisp
  (dolist (command '(yank yank-pop))
    (eval `(defadvice ,command (after indent-region activate)
             (and (not current-prefix-arg)
                  (let ((mark-even-if-inactive transient-mark-mode))
                    (indent-region (region-beginning) (region-end) nil))))))
#+end_src

*** Better window splitting functions

http://www.reddit.com/r/emacs/comments/25v0eo/you_emacs_tips_and_tricks/chldury

These settings split the window and load a previous buffer (instead
of the same buffer in both).  This has a better chance of being
what I want when splitting strings.

#+begin_src emacs-lisp
  (defun bnb/vplit-last-buffer ()
    "When splitting the frame, load the last visited buffer."
    (interactive)
    (split-window-vertically)
    (other-window 1 nil)
    (switch-to-next-buffer))

  (defun bnb/hsplit-last-buffer ()
    "When splitting the frame, load the last visited buffer."
    (interactive)
    (split-window-horizontally)
    (other-window 1 nil)
    (switch-to-next-buffer))

  (with-after-elpaca-init
    (bind-keys
     ("C-x 2" . bnb/vplit-last-buffer)
     ("C-x 3" . bnb/hsplit-last-buffer)))
#+end_src

*** Hide mode line

This is a fun one I picked from a now defunct website. This block
of code hides the mode-line for the current buffer (window).

#+begin_src emacs-lisp
  ;; Setup buffer-local behavior
  (defvar-local bnb/hide-mode-line-mode nil)
  ;; Setup minor mode
  (define-minor-mode bnb/hide-mode-line-mode
    "Minor mode to hide mode-line in current buffer"
    :init-value nil
    :global nil
    :variable bnb/hide-mode-line-mode
    :group 'editing-basics
    (if bnb/hide-mode-line-mode
        (setq bnb/hide-mode-line-mode/saved-format mode-line-format
              mode-line-format nil)
      (setq mode-line-format bnb/hide-mode-line-mode/saved-format
            bnb/hide-mode-line-mode/saved-format nil))
    (force-mode-line-update)
    (redraw-display)
    (when (and (called-interactively-p 'interactive)
               bnb/hide-mode-line-mode)
      (run-with-idle-timer
       0 nil 'message
       (concat "Goodbye mode line!"
               "Use M-x bnb/hide-mode-line-mode to make the mode-line appear"))))

  ;; Bind global key
  (with-after-elpaca-init
    (bind-key "H-0" 'bnb/hide-mode-line-mode))
#+end_src

*** Open/Edit This file

When I hit ~<F5>~, open this file for editing. That way, any
time I have something I need to remember for my emacs setting, it
is just a button-push away.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (bind-key
     "<f5>"
     (lambda ()
       (interactive)
       (find-file "~/.emacs.d/bnb-emacs/Readme.org"))))
#+end_src

*** Org-column resizing

In order to resize the face when `org-column` mode is on, some
advice is in order. The face used has a set =:height= that is not
overridden by custom face settings.

To have a custom height, this advice prepends the list with an
anonymous face with a height of 0.8. This setting happens first, so
it wins.

#+begin_src emacs-lisp
  (defun bnb/org-overlay-font-override (orig-fn beg end &optional txt face)
    (let ((bnbface (cons '(:height 0.8) face)))
      (funcall orig-fn beg end txt bnbface)))

  (with-eval-after-load 'org
    (advice-add 'org-columns--new-overlay :around #'bnb/org-overlay-font-override))
  ;(advice-remove 'org-columns--new-overlay #'bnb/org-overlay-font-override)
#+end_src

*** Prettify macro

There is a little bit of boilerplate to get the right set or
replacements set for prettify correctly. This is exactly why
macros are a thing. This one simplifies the call to provide a
mode, and the list of replacements.

#+begin_src emacs-lisp
  (defmacro bnb/prettify (mode replacements)
    "Set the prettify REPLACEMETS for MODE in a mode hook"
    `(progn
       (setq ,(intern (concat "bnb/prettify-" mode "-replacements")) ,replacements)
       (defun ,(intern (concat "bnb/prettify-" mode "-setup"))
           ()
         (mapc
          (lambda (pair) (push pair prettify-symbols-alist))
          ,(intern (concat "bnb/prettify-" mode "-replacements")))
         (prettify-symbols-mode t))
       (add-hook
        (quote ,(intern (concat mode "-hook")))
        (function ,(intern (concat "bnb/prettify-" mode "-setup"))))))
#+end_src

*** Styled HTML Export

This is how I get the one-page html output for Github Pages. There
are two main parts to setting up and executing the export.

First, I use a =SETUPFILE= from
https://github.com/fniessen/org-html-themes. Specifically, I use
the /readtheorg/ style.

Second, I setup the emacs theme correctly for nice code
output. Syntax highlighting in the export will pull from the
current theme. I don't want this. Instead, I want to specify which
theme to use for /every/ export.

The code below stores away the current list of enabled themes
before disabling them all. Then, it enables my preferred export
theme (~sanityinc-tomorrow-day~) before performing the
export. Finally, it disables the last theme and renables all of the
ones on the list.

#+begin_src emacs-lisp
  (defvar bnb/export-theme '(sanityinc-tomorrow-day))
  (defun bnb/export-readme ()
    "Export the tangled org setting as html.

  `bnb/export-theme` sets the theme for the code exports."
    (interactive)
    (let ((themes custom-enabled-themes)
          (file "~/.emacs.d/bnb-emacs/Readme.org"))
      (with-temp-buffer
       (insert "#+SETUPFILE: https://fniessen.github.io/org-html-themes/org/theme-readtheorg.setup\n")
       (insert (format "#+include: %s\n" (file-truename file)))
       (org-mode)
       (elpaca-wait) ;; ensure all modules are loaded
       (mapc 'disable-theme themes)
       (mapc 'load-theme bnb/export-theme)
       (let ((exported (org-export-as 'html))
             (save-silently-p t))
         (with-temp-file
             (format "%sindex.html" (file-name-directory file))
           (insert exported))
         (mapc 'disable-theme bnb/export-theme)
         (mapcar 'load-theme (reverse themes))))))
#+end_src

The process is to create a temp buffer and insert the setupfile
and an include to this file. Some of the finer points are that I
ensure =org-mode= is on, themes are loaded/unloaded correctly and
the export goes to the right file.

Not all of the links I use in this file easily export. Some
require some tweaking to show up nicely on the web. This next
block sets up some handlers for the link types that need a little
extra care and attention.

#+begin_src emacs-lisp
  (defun bnb/export-tooltip (link description format)
    "Exporter for help: links"
    (let ((desc (or description link)))
      (pcase format
        ('html (format "<span class=\"tooltip\"><code>%s</code>%s</span>" desc (bnb/make-doc-tooltip desc)))
        (_ desc))))

  (defun bnb/space-to-html-entity (text)
    "Change spaces to html entities in TEXT."
    (string-replace " " "&nbsp;" text))

  (defun bnb/linebreak-to-html-entity (text)
    "Change linebreaks to html entities in TEXT."
    (string-replace "\n" "<br>" text))

  (defun bnb/html-entity-replacement (text)
    "Perform html entity conversions on TEXT."
    (bnb/linebreak-to-html-entity
     (bnb/space-to-html-entity text)))

  (defun bnb/make-doc-tooltip (element)
    "Pop out tooltip text if we have it"
    (condition-case err
        (let* ((template "<span class=\"tooltiptext\">%s</span>")
               (sym (intern element))
               (doc (if (symbolp sym)
                        (or (documentation-property sym 'variable-documentation)
                            (documentation sym))
                      "")))
          (format template (bnb/html-entity-replacement doc)))
      (error (message "Skipping Error: %s" err))))

  (defun bnb/export-help-links (link description format)
    (bnb/export-tooltip link description format))

  (defun bnb/export-org-ql-links (link description format)
    (let ((desc (or description link)))
      (pcase format
        ('html (format "<span class=\"tooltip\"><code>%s</code>%s</span>" desc "<span class=\"tooltiptext\">Org QL search links only work in Emacs.</span>"))
        (_ desc))))

  (with-eval-after-load 'org
    (org-link-set-parameters "help" :export #'bnb/export-help-links)
    (org-link-set-parameters "org-ql-search" :export #'bnb/export-org-ql-links))
#+end_src

*** Transparency

Using the =ring= package, these commands will cycles through
transparency settings.

The transparency ring variable holds cells that determing the
focused and unfocused opacity settings in terms of percentage.

#+begin_src emacs-lisp
  (use-package ring
    :ensure nil
    :commands (bnb/transparency-apply bnb/transparency-next bnb/transparency-previous
                                      bnb/transparency-cycle bnb/transparency-add)
    :config
    (setq bnb/transparency-ring
          (ring-convert-sequence-to-ring (list '(100 100) '(100 50) '(100 10) '(95 50) '(90 50) '(85 50)))
          bnb/transparency
          (ring-ref bnb/transparency-ring 0))

    (defun bnb/transparency-apply (trans)
      "Apply the TRANS alpha value to the frame."
      (set-frame-parameter (selected-frame) 'alpha (setq bnb/transparency trans)))

    (defun bnb/transparency-next ()
      "Apply the next transparency value in the ring `bnb/transparency-ring`."
      (interactive)
      (bnb/transparency-apply (ring-next bnb/transparency-ring bnb/transparency)))

    (defun bnb/transparency-previous ()
      "Apply the previous transparency value in the ring `bnb/transparency-ring`."
      (interactive)
      (bnb/transparency-apply (ring-previous bnb/transparency-ring bnb/transparency)))

    (defun bnb/transparency-cycle ()
      "Cycle to the next transparency setting."
      (interactive)
      (bnb/transparency-next))

    (defun bnb/transparency-add (active inactive)
      "Add ACTIVE and INACTIVE transparency values to the ring."
      (interactive "nActive Transparency:\nnInactive Transparency:")
      (ring-insert+extend bnb/transparency-ring (list active inactive) t)
      (bnb/transparency-apply (list active inactive))))
#+end_src

*** Weekly Score Goal in Org-Agenda

I use a scoring system to keep track of my overall progress.  This
involves scoring my tasks and attributing my idea of impact of a
particular done item.

To use these numbers, I do a weekly review on Monday and compare
the numbers to past years/weeks/etc. To keep pushing forward, this
little bit of code will insert a running status at the top of my
agenda.

If I am on track for the given day (at or above the scaled goal),
all is green. Otherwise, I get a warning type formatting above 80%
and error type formatting under.

#+begin_src emacs-lisp
  ;; Define my goal to hit
  (defvar bnb/weekly-score-goal 42)

  ;; Add up all the scores from DONE items in the agenda files
  (defun bnb/agenda-score-goal ()
    "Add up scores from done items.

     In the agenda, this will show the number of done items and the
     target goal from `bnb/weekly-score-goal`."
    (let* ((score ;; Add up all scores from DONE items
            (apply '+
                   (org-map-entries
                    (lambda () (string-to-number (or (org-entry-get (point) "Score") "0")))
                    "/DONE" 'agenda)))
           (scaled-goal (* bnb/weekly-score-goal
                           (/ (string-to-number (format-time-string "%w"))
                              5.0)))
           (face (cond ((>= score scaled-goal) 'success)
                       ((>= score (* .8 scaled-goal)) 'warning)
                       (t 'error)))
           (goal-label (format "โœง Score Goal (%d): " scaled-goal))
           (goal-metric (format "%d/%d\n" score bnb/weekly-score-goal))
           (header-size (+ (string-width goal-label)
                           (string-width goal-metric)))
           (goal-separator (concat (make-string header-size ?โ”„) "\n")))
      (insert
       (concat
        (propertize goal-label 'face 'org-agenda-structure)
        (propertize goal-metric 'face face)
        (propertize goal-separator 'face 'org-agenda-structure)))))

  ;; This hook runs first in the agenda (and before it is set to read-only)
  (with-eval-after-load 'org
    (add-hook 'org-agenda-mode-hook 'bnb/agenda-score-goal))
#+end_src

*** Weekly Time Reporting

This is a function to create an entry like a datetree, but using
years and workweeks instead.

#+begin_src emacs-lisp
  (defun bnb/find-year-create (year)
    "Find or create a [YEAR] in an Org journal."
    (let ((re "^\\**[ \t]+\\([12][0-9]\\{3\\}\\)")
          match)
      (org-narrow-to-subtree)
      (goto-char (point-min))
      (while (and (setq match (re-search-forward re nil t))
                  (goto-char (match-beginning 1))
                  (< (string-to-number (match-string 1)) year)))
      (cond
       ((not match)
        (goto-char (point-max))
        (or (bolp) (newline))
        (insert (format  "** %s\n" year)))
       ((= (string-to-number (match-string 1)) year)
        (goto-char (point-at-bol)))
       (t
        (beginning-of-line 1)
        (insert (format  "** %s\n" year))))))

  (defun bnb/find-ww-create (ww)
    "Find or create a [WW] (workweek) in an Org journal."
    (let ((re "^\\**[ \t]+\\WW\\([0-9]\\{2\\}\\)")
          match)
      (org-narrow-to-subtree)
      (goto-char (point-min))
      (while (and (setq match (re-search-forward re nil t))
                  (goto-char (match-beginning 1))
                  (< (string-to-number (match-string 1)) ww)))
      (cond
       ((not match)
        (goto-char (point-max))
        (or (bolp) (newline))
        (insert (format "*** WW%02d\n" ww)))
       ((= (string-to-number (match-string 1)) ww)
        (goto-char (point-at-bol)))
       (t
        (beginning-of-line 1)
        (insert (format "*** WW%02d\n" ww))))))

  (defun bnb/insert-weekly-time-sheet ()
    "Generated and insert a weekly time sheet generated from the default Org Agenda."
    (with-temp-buffer
      (insert
       (concat  "#+BEGIN: clocktable :maxlevel 3 :scope agenda-with-archives :block lastweek :fileskip0 t :properties (\"Score\") :indent nil \n"
                "#+TBLFM: $6='(org-clock-time% @2$4 $3..$5);%.1f::@2$2=vsum(@3$2..@>$2)\n"
                "#+END:\n\n"))
      (goto-char (point-min))
      (org-update-dblock)
      (buffer-substring (point-min) (point-max))))

  (defun bnb/insert-weekly-clocking ()
    "Insert the weekly clocking clocking data."
    (let ((year (number-to-string (nth 2 (calendar-gregorian-from-absolute (org-today)))))
          (ww (bnb/workweek)))
      (goto-char (point-min))
      (goto-char (cdr (org-id-find "clocking")))
      (bnb/find-year-create (string-to-number year))
      (bnb/find-ww-create ww)))
#+end_src

*** Workweeks

This is vestigal content from my Intel days and this generates
their idea of a work week number.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (progn
      (defun bnb/workweek ()
        "Return the current workweek number."
        (interactive)
        (string-to-number
         (format-time-string "%W" (current-time))))

      (defun bnb/workweek-string ()
        "Convert the current workweek into a string.

      The string is of the format WW##."
        (interactive)
        (concat "WW"
                (number-to-string
                 (bnb/workweek))))

      (require 'calendar)
      (defun bnb/workweek-from-gregorian (&optional date)
        "Calculate the workweek from the Gregorian calendar."
        (let* ((date (or date (calendar-current-date)))
               (year (calendar-extract-year date))
               (fst (calendar-day-of-week (list 1 1 year)))
               (x   (if (>= fst 4)1 0)))
          (+ x
             (car
              (calendar-iso-from-absolute
               (calendar-absolute-from-gregorian date))))))

      (setq calendar-week-start-day 1
            calendar-intermonth-text
            '(propertize
              (format "%2d"
                      (bnb/workweek-from-gregorian (list month day year)))
              'font-lock-face 'font-lock-function-name-face))))
#+end_src

** Editing

Similar to movement, editing happens /every day/, so I use a few customizations to make it nice.

*** Ediff single frame

I really dislike the multi-frame mode of =ediff=.  It is confusing
to use and really messes up my [[http://dwm.suckless.org][dwm]] usage. By explicitly setting
the following setting, it forces =ediff= to use only one
frame.

#+begin_src emacs-lisp
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
#+end_src

Now the control window will be a small window instead of a
separate frame.

*** Multiple Cursors

This interface is a mix of an example on the [[https://github.com/abo-abo/hydra/wiki/multiple-cursors][hydra wiki]] and my own
additions.

I think that the key thing is remembering to not have this affect
*all* cursors when prompted. Otherwise, it seems, the cursors are
duplicated in strange ways.

#+begin_src emacs-lisp
  (use-package multiple-cursors
    :ensure t
    :bind
    ("H-m"   . hydra-mc/body)
    ("C-x m" . hydra-mc/body)
    ("s-<mouse-1>" . mc/add-cursor-on-click)
    ("C-x M" . compose-mail)
    :config
    (pretty-hydra-define hydra-mc (:hint nil :title "๏“ณ Multiple cursors" :quit-key "q")
      ("Down"
       (("n"   mc/mark-next-like-this "Mark next line")
        ("N"   mc/skip-to-next-like-this "Skip next line")
        ("M-n" mc/unmark-next-like-this "Unmark line going down"))
       "Up"
       (("p"   mc/mark-previous-like-this "Mark previous line")
        ("P"   mc/skip-to-previous-like-this "Skip previous line")
        ("M-p" mc/unmark-previous-like-this "Unmark line going up"))
       "Mark many"
       (("l" mc/edit-lines "Convert region")
        ("a" mc/mark-all-like-this-dwim :exit t "Mark all like selection")
        ("g" mc/mark-all-in-region-regexp :exit t "Mark regexp in region")
        ("r" mc/mark-sgml-tag-pair :exit t "Mark tag pair")
        ("x" mc/mark-more-like-this-extended "Extended marking"))
       "Special"
       (("1" mc/insert-numbers "Insert numbers")
        ("^" mc/sort-regions   "Sort regions")
        ("|" mc/vertical-align "Vertially align")
        ("A" mc/insert-numbers "Insert letters")))))
#+end_src

*** Regexp-Builder

Emacs regular expressions are not the easiest to use out of the
box. Emacs now has [[help:re-builder][regexp-builder]] to assist you in building the
correct regexp as you type.

However, to complicate matters, there are five different /syntaxes/
of regular expression that the builder can use. The =string=
syntax is what I tend to use most in searching and replacing, so I
will make that my default.

#+begin_src emacs-lisp
  (setq reb-re-syntax 'string)
#+end_src

| Key Binding | Meaning                                    |
|-------------+--------------------------------------------|
| =C-c TAB=     | Switch syntax                              |
| =C-c C-e=     | Sub-expression mode (show matching groups) |
| =C-c C-s/r=   | Search forward/backward                    |
| =C-c C-w=     | Copy regexp to kill ring                   |
| =C-c C-q=     | Quit the builder                           |

Be sure to consult the [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html][syntax of regular expressions]] to learn more
about the weird backslashing.

*** Executable Scripts on save

Taken from http://mbork.pl/2015-01-10_A_few_random_Emacs_tips,
this setting makes a file executable if it's a script.

#+begin_src emacs-lisp
  (add-hook 'after-save-hook
            'executable-make-buffer-file-executable-if-script-p)
#+end_src

*** Auto Reverting

For view-only buffers rendering content, it is useful to have them
~auto-revert~ in case of changes.

#+begin_src emacs-lisp
  (add-hook 'doc-view-mode-hook 'auto-revert-mode)
  (add-hook 'image-mode 'auto-revert-mode)
#+end_src

** Images

Emacs does a good job with images, so any particular preferences are handled in this section.

*** ImageMagick

Register image file types that can be handled by ImageMagick. Note
that Emacs needs to be compiled with ImageMagick support for this
to do anything.

#+begin_src emacs-lisp
  (with-after-elpaca-init
(when (fboundp 'imagemagick-register-types)
  (imagemagick-register-types)))
#+end_src
  • Minor Modes

    The minor modes can be used in a variety of situations to enhance the editing experience overall.

** Reference

These modes help present reference material.

*** Helpful

Using [[https://github.com/Wilfred/helpful][Helpful]] enables a better help buffer by providing a more
organized screen with contextual information and linked
references.

#+begin_src emacs-lisp
  (use-package helpful
    :ensure t
    :bind
    ("C-h K" . helpful-key)
    ("C-h v" . helpful-variable)
    ("C-h f" . helpful-function)
    ("C-h x" . helpful-command)
    ("C-h z" . helpful-macro)
    ("C-h ." . helpful-at-point))
#+end_src

*** Which Key

This [[https://github.com/justbur/emacs-which-key][helpful little package]] makes it easy to remember emacs
prefixed commands.  Start typing a prefix such as =C-x= after a brief
delay, the options for any following commands are shown.

I am using a setup that tries the right side of emacs first, and
punts to a bottom window if there is not enough room.

#+begin_src emacs-lisp
  (use-package which-key
    :defer t
    :ensure t
    :delight which-key-mode
    :init
    (which-key-mode)
    (which-key-setup-side-window-right-bottom)
    :custom
    (which-key-max-description-length 60))
#+end_src

*** Dictionary

To use the online dictionary at [[https://dict.org][dict.org]], set =dictionary-server=
accordingly. Then swap around keybindinds such that this is an easy
deafult, but the OSX version isn't far away.

One of the cooler features of this mode is that the [[https://dict.org][dict.org]] server
has [[https://www.websters1913.com/][Webster's 1913]] dictionary.

#+begin_src emacs-lisp
  (use-package dictionary
    :init
    (setq dictionary-server "dict.org")
    :bind (("C-c d" . dictionary-search)
           ("C-c D" . osx-dictionary-search-word-at-point)))
#+end_src

*** OSX Dictionary

Search ~Dictionary.app~ from the comfort of an Emacs buffer.

#+begin_src emacs-lisp
  (use-package osx-dictionary
    :ensure t
    :bind
    ("C-c d" . osx-dictionary-search-word-at-point)
    ("C-c i" . osx-dictionary-search-input))
#+end_src

** Editing

This section covers minor modes that personalize and improve the editing experience.

*** Adaptive Fill :PENDING:

Update: Turning this off for now to see if I really use it for
just text modes.

Try to keep any prefixed elements of the first line for paragraph
filling.

#+begin_src emacs-lisp
  (use-package filladapt
    :delight "โ€‰โ–ฆ"
    :disabled t
    :ensure t
    :commands filladapt-mode
    :init (setq-default filladapt-mode t)
    :hook ((text-mode . filladapt-mode)
           (org-mode . turn-off-filladapt-mode)
           (prog-mode . turn-off-filladapt-mode)))
#+end_src

*** Focus Mode

Dim everything except for the thing-at-point. Improves focus when
reading code and text.

#+begin_src emacs-lisp
  (use-package focus
    :ensure t
    :bind
    ("C-c f" . focus-mode)
    ("C-c F" . focus-read-only-mode))
#+end_src

*** Common User Access mode

[[https://www.gnu.org/software/emacs/manual/html_node/emacs/CUA-Bindings.html][CUA]] has a primary feature of enabling cut, copy, paste and undo
shortcuts compatible with most applications, but I leave that part
disabled and prefer the normal emacs bindings.

What I do enjoy about CUA are the rectangle restures and *that* is
why I enable it.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (progn
      (cua-mode t)
      (setq cua-enable-cua-keys nil)))
#+end_src

There are two main binding types: [[CUA Rectangles]] and [[CUA Global Mark]].

***** CUA Rectangles

  These take place with an active rectangle. To start/cancel a
  rectangle use =C-RET=.

  | Keys          | Function                                                              |
  |---------------+-----------------------------------------------------------------------|
  | =M-<arrow>=     | Move rectangle overlay                                                |
  | =C-<SPACE>=     | Activate region bounded by rectangle                                  |
  |---------------+-----------------------------------------------------------------------|
  | =M-a=           | Align all words at the left edge                                      |
  | =M-b=           | Fill rectangle with blanks (tabs and spaces)                          |
  | =M-c=           | Closes the rectangle by removing left edge blanks                     |
  | =M-f=           | Fills the rectangle with a single character (prompt)                  |
  | =M-i=           | Increases number found on each line of rectangle                      |
  | =M-k=           | Kills the rectangle as normal multi-line kill                         |
  | =M-l=           | Downcases the rectangle                                               |
  | =M-m=           | Copies the rectangle for normal multi-line paste                      |
  | =M-n=           | Fills each line with increasing numbers (prompt)                      |
  | =M-o=           | Opens the rect by moving hilighted text right and filling with blanks |
  | =M-p=           | Toggles virtual straight rectangle edges                              |
  | =M-P=           | Inserts tabs and spaces to make real straight edges                   |
  | =M-q=           | Performs text filling on the rectangle                                |
  | =M-q=           | Performs text filling on the rectangle                                |
  | =M-r=           | Replaces REGEXP (prompt) by STRING (prompt) in rectangle              |
  | =M-R=           | Reverse the lines in the rectangle                                    |
  | =M-s=           | Fills each line of the rectangle with the same STRING (prompt)        |
  | =M-t=           | Performs text fill of the rectangle with TEXT (prompt)                |
  | =M-u=           | Upcases the rectangle                                                 |
  | =M-<VBar>=      | Runs shell command on rectangle                                       |
  | =M-'=           | Restricts rectangle to lines with CHAR (prompt) at left column        |
  | =M-/=           | Restricts rectangle to lines matching REGEXP (prompt)                 |
  | =C-?=           | Shows a brief list of the above commands.                             |
  |---------------+-----------------------------------------------------------------------|
  | =M-C-<UP/DOWN>= | Scrolls the lines INSIDE the rectangle up/down                        |

***** CUA Global Mark

  The global mark feature enables a target the receives any
  typed/copied/killed text from any buffer (even the current
  one).

  | Key           | function                                                                                                            |
  |---------------+---------------------------------------------------------------------------------------------------------------------|
  | =<ch>=          | All characters (including newlines) you type are inserted at the global mark!                                       |
  | =C-x=           | If you cut a region or rectangle, it is automatically inserted at the global mark, and the global mark is advanced. |
  | =C-c=           | If you copy a region or rectangle, it is immediately inserted  at the global mark, and the global mark is advanced. |
  | =C-v=           | Copies a single character to the global mark.                                                                       |
  | =C-d=           | Moves (i.e. deletes and inserts) a single character to the global mark.                                             |
  | =<BACKSPACE>=   | deletes the character before the global mark                                                                        |
  | =<DELETE>=      | deletes the character after the global mark.                                                                        |
  |---------------+---------------------------------------------------------------------------------------------------------------------|
  | =S-C-space=     | Jumps to and cancels the global mark.                                                                               |
  | =C-u S-C-space= | Cancels the global mark (stays in current buffer).                                                                  |
  |---------------+---------------------------------------------------------------------------------------------------------------------|
  | =<TAB>=         | Indents the current line or rectangle to the column of the global mark.                                             |

*** Easy Kill

While looking for a way to store the filename in the clipboard, I
ran across [[https://github.com/leoliu/easy-kill][easy-kill]]. Not only will it grab the filename, but
provides ways to grab all sorts of fun things.

#+begin_src emacs-lisp
  (use-package easy-kill
    :bind ("M-w" . easy-kill)
    :ensure t)
#+end_src

The way the binding works is as a prefix key that also tries a
default "kill" and replaces [[help:kill-ring-save][kill-ring-save]]. The thing at point is
saved to the kill ring. The following table shows the details.

| Key   | Saves at point                        |
|-------+---------------------------------------|
| =M-w w= | word                                  |
| =M-w s= | sexp                                  |
| =M-w l= | list                                  |
| =M-w d= | defun                                 |
| =M-w D= | defun name                            |
| =M-w f= | filename                              |
| =M-w b= | buffer file name or default directory |

There are also modifiers to treat how the saved text is handled.

| Modifier   | Effect                            |
|------------+-----------------------------------|
| =@=          | append to previous kill           |
| =C-w=        | kill selection                    |
| =+=, =-=, =1..9= | expand/shrink selection           |
| =0=          | shrink selection to initial size  |
| =<SPC>=      | cycle through =easy-kill-alist=     |
| =C-<SPC>=    | turn selection into active region |
| =C-g=        | abort                             |
| =?=          | help                              |

*** Vundo :PENDING:

I like to have undo navigation. [[https://github.com/casouri/vundo][Vundo]] gives a nice mini interface
(git-style) to move around undo history.

#+begin_src emacs-lisp
  (use-package vundo
    :bind
    ("C-x u" . vundo)
    :custom
    (vundo-glyph-alist vundo-unicode-symbols))
#+end_src

When in the undo mode, some keys help with navigation.

| Key | Effect                               |
|-----+--------------------------------------|
| =f=   | go forward                           |
| =b=   | go backward                          |
|-----+--------------------------------------|
| =n=   | go to the node below at branch point |
| =p=   | go to the node above                 |
|-----+--------------------------------------|
| =a=   | go back to last branch               |
| =e=   | go to the end of the branch          |
| =l=   | go to last saved node                |
| =r=   | go to next saved node                |
|-----+--------------------------------------|
| =m=   | mark current node for diff           |
| =u=   | unmark marked node                   |
| =d=   | show a diff                          |
|-----+--------------------------------------|
| =q=   | quit (=C-g= also works)                |

*** Expand Region

Easily one of my favorite packages, this is a nice way to expand
selections to semantic regions. Read more on
[[https://github.com/magnars/expand-region.el]].

#+begin_src emacs-lisp
  (use-package expand-region
    :ensure t
    :bind ("C-=" . er/expand-region))
#+end_src

*** Citar (Bibtex completions)

For getting completions from bibliographic data, [[https://github.com/emacs-citar/citar][Citar]] links
things together.

#+begin_src emacs-lisp
  (use-package citar
    :commands (citar-capf-setup)
    :ensure t
    :bind
    (:map org-mode-map ("C-c b" . #'org-cite-insert))
    :custom
    (citar-bibliography bnb/biblio)
    (org-cite-global-bibliography bnb/biblio)
    (org-cite-insert-processor 'citar)
    (org-cite-follow-processor 'citar)
    (org-cite-activate-processor 'citar)
    :hook
    (LaTeX-mode . citar-capf-setup)
    (org-mode . citar-capf-setup))

  (use-package citar-embark
    :ensure t
    :after (citar embark)
    :no-require
    :config (citar-embark-mode)
    :custom
    (citar-at-point-function 'embark-act))

  (use-package citar-org-roam
    :ensure t
    :after (citar org-roam)
    :config
    (add-to-list 'org-roam-capture-templates
                 '("n" "Literature note" plain
                   "%?"
                   :target
                   (file+head
                    "%(expand-file-name (or citar-org-roam-subdir \"\") org-roam-directory)/${citar-citekey}.org"
                    "#+title: ${citar-citekey} (${citar-date}). ${note-title}.\n#+created: %U\n#+last_modified: %U\n\n")
                   :unnarrowed t))
    (citar-org-roam-mode))
#+end_src

*** Tree Sitter

Introduced in emacs 29, [[https://tree-sitter.github.io/tree-sitter/][tree sitter]] transforms code into a
concrete syntax tree.  [[https://www.masteringemacs.org/article/how-to-get-started-tree-sitter][Read up on how to get started with
tree-sitter]]

**** Treesit Auto

 Automatically install treesit grammars

 #+begin_src emacs-lisp
   (use-package treesit-auto
     :defer t
     :ensure t
     :custom
     (treesit-auto-install 'prompt)
     :config
     (treesit-auto-add-to-auto-mode-alist 'all)
     (global-treesit-auto-mode))
 #+end_src

** Version Control

Emacs is fantastic for interfacing with version control systems. For git, it may have the best interface.

*** Magit

[[https://magit.vc/manual/magit.html][Magit]] is a git interface for Emacs.

Here I set a global key for ~magit-status~. Think 'G' looks like 6.

#+begin_src emacs-lisp
  (use-package transient)

  (use-package magit
    :ensure t
    :after transient
    :bind ("<f6>" . magit-status)
    :custom
    (magit-last-seen-setup-instructions "1.4.0"))
#+END_SRC

**** Release 1.4.0

 This magit release warns about auto-revert of buffers.  This is
 turned on by default and I will keep that setting.  To turn off
 the magit warning, I set =magit-last-seen-setup-instructions= to
 1.4.0 as shown above.

**** Forge

 Git is different than [[https://github.com][Github]] and [[https://gitlab.com][Gitlab]]. [[https://magit.vc/manual/forge/index.html#Top][Forge]] provides the right
 interface to work with both of these forges.

 #+begin_src emacs-lisp
   (use-package forge
 :after magit
 :ensure (forge :host github :repo "magit/forge")
 :commands (forge-pull))
 #+end_src

*** Smerge

Somewhere along the line, =smerge= was added to native version
control support. To facilitate editing merge conflicts, this hydra
helps me do the work.

#+begin_src emacs-lisp
  (use-package smerge
    :ensure nil
    :bind
    (:map smerge-mode-map ("C-c ^ h" . hydra-smerge/body))
    :mode-hydra
    (hydra-smerge (:color amaranth :title "๎œง SMerge" :quit-key "q")
      ("Selection"
       (("a" smerge-keep-all "Keep all")
        ("b" smerge-keep-base "Keep base")
        ("m" smerge-keep-mine "Keep mine")
        ("o" smerge-keep-other "Keep other")
        ("r" smerge-resolve "Keep mine"))
       "Movement"
       (("n" smerge-next "Next conflict")
        ("p" smerge-previous "Previous conflict")))))
#+end_src

** Checking

Authors can always use that little bit of extra help to ensure the prose is right from the beginning.

*** Writegood Mode

To avoid weaslewords, passive voice, and accidental duplicates,
employ [[https://github.com/bnbeckwith/writegood-mode][Writegood]].

#+begin_src emacs-lisp
  (use-package writegood-mode
    :ensure t
    :bind
    ("C-c g"     . writegood-mode)
    ("C-c C-g g" . writegood-grade-level)
    ("C-c C-g e" . writegood-reading-ease))
#+end_src

*** Spell Checking

[[http://blog.binchen.org/posts/what-s-the-best-spell-check-set-up-in-emacs.html][This site]] has an interesting suggestion on how to use =aspell= for
CamelCase spell checking.

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (progn
      (cond
       ((executable-find "aspell")
        (setq ispell-program-name (executable-find "aspell")
              ispell-extra-args '("--sug-mode=ultra" "--lang=en_US")))
       (t (setq ispell-program-name nil)
          (message "No aspell found!")))
      (bind-key "H-$" 'ispell-word)))
#+end_src

*** Proselint

To get a complete, robust analysis of writing, [[https://github.com/amperser/proselint][Proselint]] can be
configured to work as a checker for flycheck.

Note that the executable needs to be installed on the system and
is not automatically provided.

#+begin_src emacs-lisp
  (with-eval-after-load "flycheck-mode"
    (flycheck-define-checker proselint
      "A linter for prose"
      :command ("proselint" source-inplace)
      :error-patterns
      ((warning line-start (file-name) ":" line ":" column ": "
                (id (one-or-more (not (any " "))))
                (message (one-or-more not-newline)
                         (zero-or-more "\n" (any " ") (one-or-more not-newline)))
                line-end))
      :modes (text-mode markdown-mode gfm-mode org-mode))
    (add-to-list 'flycheck-checkers 'proselint))
#+end_src

** Buffers

Handling buffers is central to an effective Emacs experience. This section adds in the tools to make management easy.

*** Midnight Mode

This mode looks at midnight and kills any inactive buffers
(keeping things tidy). By default, /inactive/ means is any buffer
untouched for three days.

#+begin_src emacs-lisp
  (use-package midnight
    :ensure nil
    :defer 10)
#+end_src

*** IBuffer

Use [[help:ibuffer][ibuffer]] instead of [[help:list-buffers][list-buffers]] for buffer management. The
most visible difference being the coloring that ~ibuffer~ uses.

I also squash any empty groups from being displayed and add hooks
to automatically set the filter groups and update contents.

#+begin_src emacs-lisp
  (use-package ibuffer
    :ensure nil
    :bind
    ("C-x C-b" . ibuffer)
    :custom
    (ibuffer-show-empty-filter-groups nil)
    :hook
    (ibuffer-mode . (lambda ()
                      (ibuffer-auto-mode 1)
                      (ibuffer-switch-to-saved-filter-groups "Standard"))))
#+end_src

**** Groups

 The buffer list splits into arbitrary groups for easier
 management. Below I create an "Org" group for ~org-mode~ buffers.

 #+begin_src emacs-lisp
   (setq ibuffer-saved-filter-groups
         '(("Standard"
            ("Emacs" (or (filename . ".*bnb-emacs.*")
                         (mode . emacs-lisp-mode)))
            ("Org" (mode . org-mode))
            ("Magit" (name . "\*magit"))
            ("Mail" (or (mode . message-mode)
                        (mode . mail-mode)))
            ("HTML" (mode . html-mode))
            ("Help" (or (name . "\*Help\*")
                        (name . "\*Apropos\*")
                        (name . "\*info\*"))))))
 #+end_src

***** VC Grouping

  The [[https://github.com/purcell/ibuffer-vc][ibuffer-vc]] Package provides groups according to version
  control sets. Here I setup a small keybinding (=/ v=) to get to the
  filtered vc groups.  The keys =/ R= will go back to the standard
  view.

  #+begin_src emacs-lisp
    (use-package ibuffer-vc
      :ensure t
      :bind
      (:map ibuffer-mode-map
            ("/ ;" . ibuffer-vc-set-filter-groups-by-vc-root)))
  #+end_src

*** Unique Buffer Names

When editing files with the same name, but different location, a
unique identifier (based on path) is preferred over a number. The
format below shows the buffername as =<filename>:<parent directory>=.

#+begin_src emacs-lisp
  (use-package uniquify
    :ensure nil
    :defer 10
    :config
    (setq uniquify-buffer-name-style 'post-forward
          uniquify-separator ":"))
#+end_src

*** OSX Reveal

For file-backed buffers, reveal the file in OSX finder with this
binding.

#+begin_src emacs-lisp
  (use-package reveal-in-osx-finder
    :ensure t
    :bind ("C-c z" . reveal-in-osx-finder))
#+end_src

** Development

The minor modes for development deal mainly with parenthenses and structured editing.

*** Check parens on save

This check has saved me from a broken configuration file many
times. I highly recommend.

#+begin_src emacs-lisp
  (add-hook 'after-save-hook  'check-parens nil t)
#+end_src

*** Eldoc

While developing, documentation is nice to have handy and
automatic.

#+begin_src emacs-lisp
  (use-package eldoc
    :ensure nil
    :hook
    (prog-mode . turn-on-eldoc-mode)
    (ielm-mode . turn-on-eldoc-mode)
    :custom (eldoc-documentation-strategy 'eldoc-documentation-compose-eagerly)
    :config
    (eldoc-add-command-completions "paredit-"))
#+end_src

*** Eglot

Use the built-in `eglot` functionality.

#+begin_src emacs-lisp
  (use-package eglot
    :ensure nil
    :demand t)
#+end_src

In Emacs devel, there is also an `eglot-x` that will be available,
but it is tracking some development versions for now, so I have
left it out.

*** Paredit

I added =paredit-mode= to several of the lisp modes that follow.

[[http://www.emacswiki.org/emacs/PareditCheatsheet][Paredit Cheatsheet]]

[[http://danmidwood.com/content/2014/11/21/animated-paredit.html][Animated Paredit]]

#+begin_src emacs-lisp
  (use-package paredit
    :ensure t
    :delight "โ€‰๐Ÿ"
    :hook
    (emacs-lisp-mode . paxedit-mode)
    (clojure-mode . paxedit-mode)
    :commands (paredit-mode))
#+end_src

*** Paxedit

Maybe even /more/ power for lisp coding?
[[https://github.com/promethial/paxedit][Paxedit repo]]

#+begin_src emacs-lisp
  (use-package paxedit
    :ensure t
    :delight "โ€‰๊€"
    :hook
    (emacs-lisp-mode . paxedit-mode)
    (clojure-mode . paxedit-mode)
    :bind
    (:map paxedit-mode-map
          ("M-<right>" . paxedit-transpose-forward)
          ("M-<left>"  . paxedit-transpose-backward)
          ("M-<up>"    . paxedit-backward-up)
          ("M-<down>"  . paxedit-backward-end)
          ("M-b"       . paxedit-previous-symbol)
          ("M-f"       . paxedit-next-symbol)
          ("C-%"       . paxedit-copy)
          ("C-&"       . paxedit-kill)
          ("C-*"       . paxedit-delete)
          ("C-^"       . paxedit-sexp-raise)
          ("M-u"       . paxedit-symbol-change-case)
          ("C-@"       . paxedit-symbol-copy)
          ("C-#"       . paxedit-symbol-kill)))
#+end_src

*** Rainbow Delimiters

In deeply nested structures (I'm looking at you lisp),
automatically coloring the matching delimiter can speed up
understanding and refactoring.

For a lighter-weight alternative, check out [[help:show-paren-mode][show-paren-mode]].

#+begin_src emacs-lisp
  (use-package rainbow-delimiters
    :ensure t
    :hook (prog-mode . rainbow-delimiters-mode))
#+end_src

** Organization

There are a couple of built-in features that help with organization. (Outside of org-mode, that is)

*** Bookmarks

[[http://emacswiki.org/emacs/BookMarks]]

| Keystroke           | Action                  |
|---------------------+-------------------------|
| =C-x r m=             | Set a bookmark          |
| =C-x r b=             | Jump to a bookmark      |
| =C-x r l=             | List your bookmarks     |
| =M-x bookmark-delete= | Delete bookmark by name |

The settings below auto-save bookmarks, adds a fringe marker on the
current line when setting/jumping, and confirms bookmark deletion.

#+begin_src emacs-lisp
  (setq bookmark-save-flag t
    bookmark-set-fringe-mark t
    bookmark-menu-confirm-deletion t)
#+end_src

*** Project

The built-in emacs package =project= replaces the projectile
functionality. Use ~C-x p p~ to navigate to a project and get started.

Useful key mappings

| Binding | Function               |
|---------+------------------------|
| =C-x p p= | Find project           |
| =C-x p f= | Find file in project   |
| =C-x p b= | Find buffer in project |
| =C-x p e= | Eshell in project      |
  • Major Modes

    This section holds the details for major modes. These are interfaces in their own right.

** File Management

Finding files in the minibuffer is easy with the completion frameworks above, but Emacs also functions very well as a fully fledged file manager.

*** Dired

The built-in directory editor, [[help:dired][dired]], can be customized to a great
degree. The following sections walk us through my particular
preferences.

**** Basic Settings

 First, add the basic dired settings.

 #+begin_src emacs-lisp
   (setq dired-kill-when-opening-new-dired-buffer t
         dired-mark-region t)
 #+end_src

 The first setting, [[help:dired-kill-when-opening-new-dired-buffer][dired-kill-when-opening-new-dired-buffer]] keeps
 =dired= from littering little visited folder buffers along the way.

 Marking commands can now act on regions with [[help:dired-mark-region][dired-mark-region]]
 set to ~t~. 

**** Hacks

 These are part of the [[https://github.com/Fuco1/dired-hacks][dired-hacks repository]].

 #+begin_src emacs-lisp
   (use-package dired-hacks-utils
     :defer t
     :ensure t)
 #+end_src

***** Filter mode

  This first package provides [[help:dired-filter-mode][dired-filter-mode]] giving some very
  handy ways to filter the view. Enable it with =C-c C-d f= and then
  get to the commands with =C-c C-f=.
 
  #+begin_src emacs-lisp
     (use-package dired-filter
       :defer t
       :hook (dired-mode . dired-filter-mode)
       :ensure t
       :bind
       ("C-c C-d f" . dired-filter-mode)
       :bind-keymap
       ("C-c C-f" . dired-filter-map))
  #+end_src

***** Colorized Files

  This next addition colorizes files in dired accorting to type or
  the =chmod= bits.
 
  #+begin_src emacs-lisp
    (use-package dired-rainbow
      :ensure t
      :config
      (progn
        (dired-rainbow-define html        "#eb5286" ("css" "less" "sass" "scss" "htm" "html" "jhtm" "mht" "eml" "mustache" "xhtml"))
        (dired-rainbow-define xml         "#f2d024" ("xml" "xsd" "xsl" "xslt" "wsdl" "bib" "json" "msg" "pgn" "rss" "yaml" "yml" "rdata"))
        (dired-rainbow-define document    "#9561e2" ("docm" "doc" "docx" "odb" "odt" "pdb" "pdf" "ps" "rtf" "djvu" "epub" "odp" "ppt" "pptx"))
        (dired-rainbow-define markdown    "#ffed4a" ("org" "etx" "info" "markdown" "md" "mkd" "nfo" "pod" "rst" "tex" "textfile" "txt"))
        (dired-rainbow-define database    "#6574cd" ("xlsx" "xls" "csv" "accdb" "db" "mdb" "sqlite" "nc"))
        (dired-rainbow-define media       "#de751f" ("mp3" "mp4" "MP3" "MP4" "avi" "mpeg" "mpg" "flv" "ogg" "mov" "mid" "midi" "wav" "aiff" "flac"))
        (dired-rainbow-define image       "#f66d9b" ("tiff" "tif" "cdr" "gif" "ico" "jpeg" "jpg" "png" "psd" "eps" "svg"))
        (dired-rainbow-define log         "#c17d11" ("log"))
        (dired-rainbow-define shell       "#f6993f" ("awk" "bash" "bat" "sed" "sh" "zsh" "vim"))
        (dired-rainbow-define interpreted "#38c172" ("py" "ipynb" "rb" "pl" "t" "msql" "mysql" "pgsql" "sql" "r" "clj" "cljs" "scala" "js"))
        (dired-rainbow-define compiled    "#4dc0b5" ("asm" "cl" "lisp" "el" "c" "h" "c++" "h++" "hpp" "hxx" "m" "cc" "cs" "cp" "cpp" "go" "f" "for" "ftn" "f90" "f95" "f03" "f08" "s" "rs" "hi" "hs" "pyc" ".java"))
        (dired-rainbow-define executable  "#8cc4ff" ("exe" "msi"))
        (dired-rainbow-define compressed  "#51d88a" ("7z" "zip" "bz2" "tgz" "txz" "gz" "xz" "z" "Z" "jar" "war" "ear" "rar" "sar" "xpi" "apk" "xz" "tar"))
        (dired-rainbow-define packaged    "#faad63" ("deb" "rpm" "apk" "jad" "jar" "cab" "pak" "pk3" "vdf" "vpk" "bsp"))
        (dired-rainbow-define encrypted   "#ffed4a" ("gpg" "pgp" "asc" "bfe" "enc" "signature" "sig" "p12" "pem"))
        (dired-rainbow-define fonts       "#6cb2eb" ("afm" "fon" "fnt" "pfb" "pfm" "ttf" "otf"))
        (dired-rainbow-define partition   "#e3342f" ("dmg" "iso" "bin" "nrg" "qcow" "toast" "vcd" "vmdk" "bak"))
        (dired-rainbow-define vc          "#0074d9" ("git" "gitignore" "gitattributes" "gitmodules"))
        (dired-rainbow-define-chmod executable-unix "#38c172" "-.*x.*")
        (dired-rainbow-define-chmod directory       "#6cb2eb" "d.*")))
   #+end_src

***** Narrowing

  Instead of [[*Filter mode][filter mode]], we can use two functions to narrow the
  =dired= buffer to only the matches. The flavors of filterring are
  /fuzzy/ or /regexp/.
  
 #+begin_src emacs-lisp
    (use-package dired-narrow
      :defer t
      :bind (:map dired-mode-map
                  ("C-c C-d n" . dired-narrow-fuzzy)
                  ("C-c C-d r" . dired-narrow-regexp))
      :ensure t)
  #+end_src

***** Collapsing directories

  In the case of deep folder structures without any intermediate
  files (files only in the leaves), this mode helps collapse the
  view to be easier to navigate.

  Per the documentation, this will be especially useful in
  directories such as =~/.config/foo/config=.
  
 #+begin_src emacs-lisp
    (use-package dired-collapse
      :defer t
      :bind
      ("C-c C-d c" . dired-collapse-mode)
      :ensure t)
 #+end_src

***** External Commands

 Also, there is a nice faculty to run an external command on a given
 file with ==!==.

*** Neotree

Neotree is a file sidebar for navigation.  Dired has a superior
interface for interacting with files, but =Neotree= offers the tree
stucture view for the times you need to see the whole folder tree.

#+begin_src emacs-lisp
  (use-package neotree
    :ensure t
    :commands (neotree)
    :bind ("H-t" . neotree-toggle)
    :config
    (setq neo-theme (if (display-graphic-p) 'icons 'arrow)))
#+end_src

** Documents

These days, one of my favorite uses of the one true editor is to author prose and scientific writing. These major modes provide the tools to make this easy and fun.

*** AucTeX

Using TeX systems is easy with AUCTeX. To learn everything, read
the [[https://www.gnu.org/software/auctex/manual/auctex/index.html][AUCTeX Manual]].

The following block ensures that AUCTeX builds and loads
correctly. The main settings deal with setting up =PDF= output and
the =xetex= engine.

#+begin_src emacs-lisp
  (use-package auctex
    :defer t
    :after org
    :ensure (auctex :pre-build (("./autogen.sh")
                                ("./configure" "--without-texmf-dir" "--with-lispdir=.")
                                ("make")))
    :mode (("\\.tex\\'" . LaTeX-mode)
           ("\\.tex\\.erb\\'" . LaTeX-mode)
           ("\\.etx\\'" . LaTeX-mode))
    :hook ((LaTeX-mode . flyspell-mode)
           (LaTeX-mode . LaTeX-math-mode)
           (LaTeX-mode . auto-fill-mode)
           (LaTeX-mode . orgtbl-mode)
           (doc-view-mode . auto-revert-mode))
    :config
    (setq TeX-auto-untabify t
          TeX-auto-save t
          TeX-save-query nil
          TeX-parse-self t
          TeX-output-view-style
          (if (eq system-type 'windows-nt)
              (quote
               (("^pdf$" "." "SumatraPDF.exe -reuse-instance %o")
                ("^html?$" "." "start %o")))
            (quote
             (("^pdf$" "." "evince -f %o")
              ("^html?$" "." "start %o"))))
          TeX-command-extra-options "-shell-escape"
          TeX-PDF-mode 1
          TeX-engine 'xetex)
    (setq-default TeX-master nil)
    (setq-default TeX-global-PDF-mode 1)
    (add-to-list 'org-latex-packages-alist
                 '("" "tikz" t))
    (add-to-list 'org-latex-packages-alist
                 '("" "minted" t))
    (setq org-latex-create-formula-image-program 'imagemagick)
    (eval-after-load "preview"
      '(add-to-list 'preview-default-preamble "\\PreviewEnvironment{tikzpicture}" t)))
#+end_src

Let me walk through some of the settings.

Parse-self and auto-save will parse the file on load and save
respectively. Untabify will remove tabs (real ones) before saving.
 
I also have a default of =TeX-master= set to =nil=. I used to have it
set to "master" as recommended in the documentation, but I had bad
results for LaTeX files generated on the fly.

For viewing the output, I can specify the command to use on the
files generated in the process. However, the programs differ on
GNU/Linux and Windows, so I have per-platform settings.

There are two settings that add the =tikz= and =minted= packages to
=org-mode= exports.

**** RefTeX

 RefTeX provides navigation, easy references, easy citations and
 integrates well into AUCTeX. Find all of the details in the
 [[https://www.gnu.org/software/auctex/manual/reftex/index.html][RefTeX Manual]].

 Automatically turn it on in LaTeX modes.

 #+begin_src emacs-lisp
   (add-hook 'LaTeX-mode-hook 'turn-on-reftex)
 #+end_src

 | Keystroke | Function                           |
 |-----------+------------------------------------|
 | C-c =     | Show TOC and jump to sections      |
 | C-c (     | Insert a label                     |
 | C-c )     | Reference a label                  |
 | C-c [     | Insert a citation (from BibTex db) |
 | C-c <     | Index entry                        |
 | C-c >     | View index                         |
 | C-c &     | View crossref                      |

*** HTML

The document standard that is ubiquitous, but typically authored
through some processing tool. This section helps wtih the real
hands-on editing of HTML (and other similarily structued)
documents.

**** Impatient mode

 In order to play nicely with HTML+, it needs to be added to the
 filters of impatient mode.

 #+begin_src emacs-lisp
   (use-package impatient-mode
     :ensure t
     :mode "\\.html\\'"
     :bind
     ("C-x C-h s" . httpd-start)
     ("C-x C-h x" . httpd-stop)
     ("C-x C-h d" . httpd-serve-directory)
     :config
     (add-to-list 'imp-default-user-filters '(mhtml-mode . nil)))
 #+end_src

 To use impatient mode, you'll first want to call [[help:httpd-start][httpd-start]] and
 then navigate to [[http://localhost:8080/imp]] to see the rendered
 buffers.

**** Emmet

 [[https://github.com/smihica/emmet-mode][Emmet mode]] allows for terse description of nested elements. There
 is great documentation on the approach at [[http://emmet.io][emmet.io]].

 #+begin_src emacs-lisp
   (use-package emmet-mode
     :ensure t
     :commands (emmet-mode)
     :hook ((web-mode  . emmet-mode)
            (sgml-mode . emmet-mode)
            (css-mode  . emmet-mode)))
 #+end_src

*** Markdown

Everything can't be as nice as [[*Orgmode][org-mode]]. Oh well.

#+begin_src emacs-lisp
  (use-package markdown-mode
:ensure t
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
       ("\\.md\\'" . markdown-mode)
       ("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command "multimarkdown"))
#+end_src

*** Orgmode

The one feature I cannot do without. Let's set up some basics.

#+begin_src emacs-lisp
  (use-package org
    :ensure (org :type git :repo "https://git.savannah.gnu.org/git/emacs/org-mode.git" :tag "release_9.6.19")
    :delight (org-mode "๐Ÿฆ„" :major)
    :mode ("\\.org\\(_archive\\)?\\'" . org-mode)
    :bind
    ("C-c t"  . orgtbl-mode)
    ("C-c l"  . org-store-link)
    ("C-c r"  . org-capture)
    ("C-c a"  . org-agenda)
    ("<f12>"  . org-agenda)
    ("H-z"    . org-agenda)
    ("<apps>" . org-agenda)
    ("<f9> g" . org-clock-goto)
    ("<f9> i" . org-clock-in)
    ("<f9> o" . org-clock-out)
    (:map org-mode-map
          ("M-i"   . org-toggle-inline-images)
          ("C-c ," . org-insert-structure-template)
          ("C-c ," . org-insert-structure-template)
          ("M-o"   . ace-link-org))
    :hook
    (org-babel-after-execute . (lambda () (org-display-inline-images t t))))
#+end_src

This block installs [[https://orgmode.org/][org-mode]] along with some bindings.

| Binding | Effect                         |
|---------+--------------------------------|
| =C-c t=   | Edit tables in any mode        |
| =C-c l=   | Store a link to thing at point |
| =C-c r=   | Dispatch org capture           |
| =<f12>=   | Open org agenda                |
| =H-z=     | Open org agenda                |
| =<apps>=  | Open org agenda                |
| =<f9> g=  | Goto open org clock            |
| =<f9> i=  | Org clock in                   |
| =<f9> o=  | Org clock out                  |

**** Contrib

 There are a set of contributed packages that install nicely
 together. This code block ensures that the libraries are
 available.

 #+begin_src emacs-lisp
   (use-package org-contrib
 :after org
 :ensure t)
 #+end_src

**** Auto mode

 I add =_archive= to the list of known org files. This alternative
 extensions correctly identifies org archives (=.org_archive=).

 This mode is set above with =use-package=.

**** Hooks

 There are two hooks to consider. Theone initialized in [[Orgmode]]
 toggles on the inline images.

 The next hook just saves the org files opened before exiting
 emacs -- just in case.

 #+begin_src emacs-lisp
   (with-eval-after-load 'org
     (add-hook 'bnb/kill-emacs-hooks 'org-save-all-org-buffers 'append))
 #+end_src

**** Speed Keys

 Using org-mode efficiently for task management is best done with
 speed keys. This are in effect when the cursor is on the first =*=
 of a headline. And they come with an easy cheat-sheet by typing
 =?=. I enable this feature and add some of my own commands.

 #+begin_src emacs-lisp
   (with-eval-after-load 'org
     (setq org-use-speed-commands t
           org-speed-commands
           (append org-speed-commands
                   '(("BNB Additions")
                     ("0" . delete-window)
                     ("1" . delete-other-windows)
                     ("2" . split-window-vertically)
                     ("3" . split-window-horizontally)
                     ("z" . org-add-note)
                     ("h" . hide-other)
                     ("." . org-save-all-org-buffers)
                     ("/" . org-global-cycle)
                     ("k" . #'(lambda ()
                                 (org-mark-subtree)
                                 (kill-region
                                  (region-beginning)
                                  (region-end))))))))
 #+end_src

**** Org Configuration

 This is the meat of what Org can do. Keeping track of todo items
 with due dates, tags, etc. is really powerful. And I get to
 customize it to suit my needs and my workflow.

***** Keywords

  The keywords that org uses in the headlines exist as sequences
  describing the state changes. [[https://orgmode.org/manual/Workflow-states.html][The sequences]] describe how you can
  cycle through the different states. However, I don't cycle
  through states and just select them. I find that is better for
  the large list of possibilities here.

  The characters in =()= also allow fast access to these states
  described [[https://orgmode.org/manual/Fast-access-to-TODO-states.html][here]].

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (setq org-todo-keywords
            '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!/!)")
    	        (sequence "WAITING(w@/!)" "SOMEDAY(s!)" "|" "CANCELED(c@/!)")
    	        (sequence "CANCELED(c@/!)"))))
  #+end_src

***** Tags

  Org uses tags on headlines for organization. I don't currently
  use them much. I organize mainly by file with a file tag
  specified via [[https://orgmode.org/manual/In_002dbuffer-Settings.html][in-buffer settings]] (=#+FILETAGS=).

  However, a global tag list provides a selection list for the
  tagging interface. I use 'project' as my tag to easily
  differentiate simple tasks from more complex ones.

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (setq org-tag-alist '(("PROJECT" . ?p))))
  #+end_src

***** Mechanics

  The todo interface allows easy selection of states and triggers
  on certain states to store notes.

  Instead of cycling through states (and possibly triggering log
  entries), I prefer fast entry to jump right to the correct
  state. I also turn off the S-cursor transitions as state changes
  to avoid the logging prompts.

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (setq org-use-fast-todo-selection t
            org-treat-S-cursor-todo-selection-as-state-change nil))
  #+end_src

  Upon changing the state of todo items, I can automatically
  add/remove tags with the following list. It's a bit lispy, but
  describes what happens upon entry in the specified state. The
  state named as a string has tuples of tags and flags. 't'
  indicates to set the flag, empty means to remove it.

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (setq org-todo-state-tags-triggers
            '(("CANCELED" ("CANCELED" . t))
              ("WAITING"  ("WAITING" . t))
              ("SOMEDAY"  ("SOMEDAY" . t))
              (done       ("WAITING"))
              ("TODO"     ("WAITING") ("CANCELED"))
              ("NEXT"     ("WAITING"))
              ("DONE"     ("WAITING") ("CANCELED")))))
  #+end_src

  Along with tags and states are priorities. I do not use task
  priorities myself so I turn them off.

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (setq org-enable-priority-commands nil))
  #+end_src

****** Logging

   Org allows logging of states. I turn this on to prompt myself
   for reasons behind specific state changes. There is also a
   setting to set a different drawer for clocking and logs.

   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (setq org-log-done       'note
             org-log-redeadline 'time
             org-log-reschedule 'time
             org-log-into-drawer t
             org-drawers '("PROPERTIES" "LOGBOOK" "CLOCK")))
   #+end_src

****** Sub-tasks

   Naturally, some tasks are projects composed of smaller
   sub-tasks. Org handles this easily. I like to enforce the
   dependencies of regular todo items and plain checkbox lists. In
   this way, the overall item cannot change to done without the
   completion of the sub-tasks.

   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (setq org-enforce-todo-checkbox-dependencies t
             org-enforce-todo-dependencies t))
   #+end_src

   Because of the previous enforcement of state, I can also
   automatically infer when a parent state is complete. The
   following code marks the parent complete once the sub-tasks
   are all done.

   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (defun org-summary-todo (n-done n-not-done)
         "Switch entry to DONE when all sub-entries are done, to TODO otherwise."
         (let (org-log-done org-log-states)
           (org-todo (if (= n-not-done 0) "DONE" "TODO"))))
       (add-hook 'org-after-todo-statistics-hook 'org-summary-todo))
   #+end_src

**** Capture

 [[https://orgmode.org/manual/Capture.html][Capturing]] is crucial to a task system and in this vein, org is no
 slouch. The capture templates define what get captured, where it
 goes, and what the user needs to type.

 #+begin_src emacs-lisp
   ;; Files
   (setq org-default-notes-file "~/Documents/Org/Inbox.org"
         bnb/weekly-reports-file "~/Documents/Org/WeeklyReports.org")

   ;; Default templates
   (setq org-capture-templates
         `(("t" "Todo" entry
            (file ,org-default-notes-file)
            "* TODO %?\n  %U\n%^{Score}p" :clock-in t :clock-resume t)
           ("r" "todo (Remember location)" entry
            (file org-default-notes-file)
            "* TODO %?\n  %U\n  %a" :clock-in t :clock-resume t)
           ("n" "Note" entry
            (file org-default-notes-file)
            "* %?                                                                            :NOTE:\n  %U\n  %a\n  :CLOCK:\n  :END:")
           ("c" "Capture current TODO mix in table" table-line (file+headline ,bnb/weekly-reports-file "Burndown")
            "%(bnb/org-count-tasks-by-status)")
           ("s" "Capture Weekly Score in table" table-line (file+headline ,bnb/weekly-reports-file "Scores")
            "%(bnb/add-weekly-score-table-entry)")
           ("e" "Capture Weekly time in table" table-line (file+headline ,bnb/weekly-reports-file "Minutes")
            "%(bnb/org-time-logged-table-entry)")
           ("u" "Url" entry (file ,org-default-notes-file)
            "* TODO %?\n  %U\n\n  %(org-mac-chrome-get-frontmost-url)")
           ("m" "Mail" entry (file ,org-default-notes-file)
            "* TODO %?\n  %U\n\n  %(org-mac-message-get-links \"s\")")))
 #+end_src

 There are five main capture templates here. The first two store a
 todo item in my Refile.org file. The only difference is automatic
 (contextual) link storage in the second case.

 The next item simply stores a note. The next for "Weekly Report"
 is a work in progress. I think that I'll have to either settle
 for a proper datetree or write a custom function.

 The final item is not for direct use, but through the
 =org-protocol= interface and =org-outlook= usage. This lets me add a
 link to an Outlook message on windows. I can then get an email at
 work, mark it to store in emacs and quickly get back to the
 message later.

***** Capture-template helpers for data tables

  These helpers provide functionality used in the capture templates
  above.

  Modified from [[http://sachachua.com/blog/2014/05/getting-r-ggplot2-work-emacs-org-mode-babel-blocks-also-tracking-number-todos/][Sacha Chua]], this code get the current mix of tasks
  in the agenda files. I use this as part of my weekly review for
  task amount and mix at a glance.

  #+begin_src emacs-lisp
    (defun bnb/org-count-tasks-by-status ()
      "Create a table entry for the tracking of task mix."
      (interactive)
      (let ((counts (make-hash-table :test 'equal))
            (today (format-time-string "%Y-%m-%d" (current-time)))
            values output)
        (org-map-entries
         (lambda ()
           (let ((status (elt (org-heading-components) 2)))
             (when status
               (puthash status (1+ (or (gethash status counts) 0)) counts))))
         "-HOME"
         'agenda)
        (setq values (mapcar (lambda (x)
                               (or (gethash x counts) 0))
                             '("DONE" "TODO" "WAITING" "CANCELLED" "SOMEDAY")))
        (setq output
              (concat "| " today " | "
                      (mapconcat 'number-to-string values " | ")
                      " | "
                      (number-to-string (apply '+ values))
                      " | "
                      (number-to-string
                       (round (/ (* 100.0 (car values)) (apply '+ values))))
                      "% |"))
        (if (called-interactively-p 'any)
            (insert output)
          output)))
  #+end_src

  I also have a helper function to get the score of done tasks
  closed within the last week.  I store this in a table line with
  year and workweek number.

  #+begin_src emacs-lisp
    (defun bnb/add-weekly-score-table-entry ()
      "Track my weekly scores in a table."
      (let ((score (apply
                    '+
                    (org-map-entries
                     (lambda ()
                       (string-to-number (or (org-entry-get (point) "Score") "0")))
                     "/DONE"
                     'agenda)))
            (year (format-time-string "%Y" (current-time)))
            (ww (number-to-string (bnb/workweek))))
        (format "| %s | %s | %s |" year ww score)))
  #+end_src

  How about the hours logged last week? Let's give that a go. Note
  that if there are no clocked hours for a week, this comes up
  empty.

  #+begin_src emacs-lisp
    (defun bnb/get-clocked-categories-hashtbl (days-ago)
      "Get clocktable of categories starting DAYS-AGO"
      (let ((clocked-fmt (- 0 days-ago))
            (org-fmt (format-time-string "%Y-%m-%d" (time-subtract (current-time) (days-to-time days-ago)))))
        (let ((clocktbl (make-hash-table :test 'equal))
              (entries (org-ql-select (org-agenda-files) '(clocked :from clocked-fmt)
                         :action (lambda ()
                                   (list (org-entry-get-with-inheritance "CATEGORY" t)
                                         (org-clock-sum-current-item org-fmt))))))
          (dolist (e entries clocktbl)
            (puthash (car e) (+ (cadr e)
                                   (or (gethash (car e) clocktbl) 0))
                     clocktbl)))))

    (defun bnb/org-time-logged-table-entry (&optional additional-weeks include-zeros)
      "Insert table of minutes per category.
      Optionally provide ADDITIONAL-WEEKS to get more history"
      (interactive "P")
      (let* ((minh (bnb/get-clocked-categories-hashtbl (+ 7 (* 7 (or additional-weeks 0)))))
             (today (format-time-string "%Y-%m-%d" (current-time))))
        ;; Print out table lines
        (let ((rows nil))
          (maphash
           (lambda (k v)
             (when (or (> v 0) include-zeros) 
               (setq rows
                     (cons (format "| %s | %s | %d |" today k v) rows))))
           minh)
          (if (called-interactively-p 'any)
              (insert (mapconcat 'identity rows "\n"))
            (mapconcat 'identity rows "\n")))))

    ; (bnb/org-time-logged-table-entry 1 t)
  #+end_src

**** Refile

 [[https://orgmode.org/manual/Refiling-and-Archiving.html][Refiling notes]] is also spectacular with Org. That is what makes
 it possible for me to simply put every captured item into
 Refile.org and worry about organization later.

 For my setup, I use separate files that hold a singular Tasks
 headline. Because of that, I turn on caching first.

 For the refile targets, I will allow up to 2 levels of search for
 filing in any of the agenda files. For refiling within the
 current file, I set the max to five levels. Anything deeper than
 six levels will exhaust the depth of my thought.

 The refiling system is set to =confirm= creation of parent
 nodes. This allows me to not only refile, but create along the
 way for faster organization.

 Finally, I set the filenames to be first for refiling.

 #+begin_src emacs-lisp
   (setq org-refile-use-cache t
         org-refile-targets '((org-agenda-files :maxlevel . 2)
                              (nil :maxlevel . 5))
         org-refile-allow-creating-parent-nodes 'confirm
         org-refile-use-outline-path 'file)
 #+end_src

**** Agenda

 Once I have captured and refiled my tasks, I need to remember to
 do them and see what is on the agenda. The ways to view the tasks
 at hand are nicely programmable.

 Some basic settings control small tidbits in the agenda. I turn
 on tags in the agenda line, show the logged items for the day,
 and only show a time grid if a scheduled tasks exists.

 #+begin_src emacs-lisp
   (setq org-agenda-show-inherited-tags t
         org-agenda-log-mode-items '(clock)
         org-agenda-clockreport-parameter-plist '(:link nil :maxlevel 2 :fileskip0 t)
         org-agenda-block-separator nil
         org-agenda-dim-blocked-tasks nil
         org-agenda-inhibit-startup t
         org-agenda-breadcrumbs-separator " โฑ ")
 #+end_src

***** Super agenda

  Enriching the agenda view is easy with [[https://github.com/alphapapa/org-super-agenda/tree/master][org-super-agenda]]. I don't
  make any default settings here, but override
  [[help:org-super-agenda-groups][org-super-agenda-groups]] for each agenda view dispatcher.
  
  #+begin_src emacs-lisp
    (use-package org-super-agenda
      :after org
      :ensure t
      :config
      (org-super-agenda-mode))
  #+end_src

  The [[https://github.com/alphapapa/org-super-agenda/blob/master/examples.org][examples]] online provide a good idea of the grouping
  customization (and ease).

***** Category Icons

  Org-mode can show category icons in some agenda views. The
  underlying setting is just an ~alist~ of categories and the icons
  to use.

  #+begin_src emacs-lisp
    ;;;;;;;;;;;;;
    ;; Org agenda category icons
    (with-eval-after-load 'nerd-icons
      (setq org-agenda-category-icon-alist 
            `(("[iI]nbox"     ;; ๏’
               ,(list (nerd-icons-octicon "nf-oct-inbox")) nil nil :ascent center)
              ("[Ww]ork"      ;; ๏ซ
               ,(list (nerd-icons-octicon "nf-oct-organization")) nil nil :ascent center)
              ("[Pp]ersonal"  ;; ๏‘ญ
               ,(list (nerd-icons-octicon "nf-oct-home")) nil nil :ascent center)
              ("[Ii][Cc]"     ;; ๏•
               ,(list (nerd-icons-octicon "nf-oct-person")) nil nil :ascent center)
              ("[Mm]anager"   ;; ๏‚…
               ,(list (nerd-icons-faicon "nf-fa-cogs")) nil nil :ascent center))))
  #+end_src

***** Views

  The key to exploring open work are the agenda views. These
  provide a landscape to list, filter or manipulate
  tasks. [[help:org-agenda-custom-commands][org-agenda-custom-commands]] defines which views are
  available by default.

  Adapted from [[https://github.com/fniessen/emacs-leuven/blob/master/lisp/org-leuven-agenda-views.txt][org-leuven-agenda-views.txt]].

  #+begin_src emacs-lisp
    ;; Reset everything to nil
    (setq org-agenda-custom-commands nil)
  #+end_src
  
  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (add-to-list
       'org-agenda-custom-commands
       '("o" "My Agenda"
         ((todo "TODO"
                ((org-agenda-overriding-header "\nโšก Do Today\nโ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„")
                 (org-agenda-remove-tags t)
                 (org-agenda-prefix-format " %-2i %-15b")
                 (org-agenda-todo-keyword-format "")))
          (agenda ""
                  ((org-agenda-start-day "+0d")
                   (org-agenda-span 5)
                   (org-agenda-overriding-header "โšก Schedule\nโ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„")
                   (org-agenda-repeating-timestamp-show-all nil)
                   (org-agenda-remove-tags t)
                   (org-agenda-prefix-format   "  %-3i  %-15b %t%s")
                   (org-agenda-todo-keyword-format " โ˜ ")
                   (org-agenda-current-time-string "โฎœโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆ now")
                   (org-agenda-scheduled-leaders '("" ""))
                   (org-agenda-time-grid (quote ((daily today remove-match)
                                                 (0900 1200 1500 1800 2100)
                                                 "      " "โ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆโ”ˆ")))))))))
  #+end_src

****** Process

   In the /process/ section, the goal is to take the incoming items
   and process them.  There is a menu key, =p=, that will open up
   the different views.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("p" . "PROCESS...") t))
   #+end_src

   The first view grabs anything tagged =inbox=. In my setup, my
   default notes file does have a filetag of =inbox=, so all of
   those will also show up in this view.

   The nice part is that I can have other agenda files with
   inboxes that need addressed This helps them stay in the
   forefront of processing.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("pp" "All TODOs in Inboxen"
          ((org-ql-block '(and (tags "inbox") (or (todo) (done)))
                         ((org-ql-block-header "Inboxed tasks")
                          (org-agenda-overriding-header "List of all TODO tasks in Inbox")
                          (org-agenda-sorting-strategy '(priority-down))
                          (org-super-agenda-groups '((:auto-category t))))))) t))
   #+end_src

   I try to put effort estimates on all of my tasks. As part of
   processing, the =pe= view lists tasks without effort. Typically I
   then edit with [[help:org-columns][org-columns]] (=C-c C-x C-c=).

   In the column view, navigating to the effort column and hitting
   the right number will set the effort to one of the predefined
   settings (found in [[help:org-global-properties][org-global-properties]]).
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("pe" "No Estimates" 
          ((org-ql-block '(and (not (effort)) (todo))
                         ((org-agenda-overriding-header "Lacking ESTIMATES")
                          (org-agenda-sorting-strategy '(priority-down))
                          (org-super-agenda-groups '((:auto-category t))))))) t))
   #+end_src

   This view (reachable via =ps=) is similar to the previous one,
   only it finds tasks without scores. This helps me process them
   in the same way -- ensure everthing that /can/ have a score,
   does.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("ps" "No Score"
          ((org-ql-block '(and (not (property "SCORE")) (or (todo) (done)))
                         ((org-agenda-overriding-header "Lacking SCORE")
                          (org-agenda-sorting-strategy '(priority-down)))))) t))
   #+end_src

   The archivable view =pa= is also similar to the previous one,
   only it finds tasks that are complete and ready to be refiled
   or archived. 
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("pa" "Archivable"
          ((agenda "DONE|PROJECTDONE"
                 ((org-agenda-clockreport-mode t)
                  (org-agenda-start-day "-7")
                  (org-agenda-overriding-header "PAST WEEK")
                  (org-agenda-prefix-format " %?-11t %i %-12:c% s")
                  (org-agenda-show-log 'clockcheck)))
           (org-ql-block '(done)
                         ((org-agenda-overriding-header "Completed Tasks")
                          (org-agenda-sorting-strategy '(priority-down))
                          (org-super-agenda-groups '((:auto-category t)))))))))
   #+end_src

   Finally, this view shows the items tagged =someday=. As process
   goes, this could be part of review, but I like it better as a
   processing step.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("pd" "Somday items" tags-todo "SOMEDAY"
          ((org-agenda-overriding-header "SOMEDAY tasks")
           (org-agenda-sorting-strategy '(priority-down)))) t))
   #+end_src

****** Focus

   The /focus/ section builds up views to help focus on tasks. The
   dispatcher starts with an =f=.
   
   #+begin_src emacs-lisp
       (with-eval-after-load 'org
         (add-to-list
          'org-agenda-custom-commands
          '("f" . "FOCUS...") t))
   #+end_src

   The /today/ focus view unfolds like a compass guiding through the
   day's tasks, presenting a constellation of sections aimed at
   pinpointing the most crucial endeavors to tackle next.

   In the calendar section, a mosaic of diary entries and
   timestamps for today awaits exploration, offering a glimpse
   into the rhythm of the day.

   The inbox section beckons with its array of unscheduled
   top-level items, each a potential gem awaiting processing. Here
   lie tasks in need of scheduling, refining, or simply bringing
   to completion.

   For those with deadlines looming, the due today and overdue
   sections serve as a stark reminder, listing tasks teetering on
   the edge of time. They demand attention, beckoning to be
   brought to fruition.

   Meanwhile, the scheduled section offers a glimpse into the near
   future, showcasing the tasks slated for today, like eager
   performers awaiting their cue.

   Lastly, the completed section stands as a testament to
   progress, a growing archive of triumphs marked by tasks
   conquered. As the week unfolds, this section burgeons,
   reflecting the journey traversed and milestones achieved.

   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        `("f." "Today"
          ((agenda ""
                   ((org-agenda-entry-types '(:timestamp :sexp))
                    (org-agenda-overriding-header
                     (concat "CALENDAR Today "
                             (format-time-string "%a %d" (current-time))))
                    (org-agenda-span 'day)))
           (tags-todo "LEVEL=1+inbox"
                      ((org-agenda-overriding-header "INBOX (Unscheduled)")))
           (tags-todo "DEADLINE<\"<+1d>\"+DEADLINE>\"<-1d>\""
                      ((org-agenda-overriding-header "DUE TODAY")
                       (org-agenda-skip-function
                        '(org-agenda-skip-entry-if 'notdeadline))
                       (org-agenda-sorting-strategy '(priority-down))))
           (tags-todo "DEADLINE<\"<today>\""
                      ((org-agenda-overriding-header "OVERDUE")
                       (org-agenda-skip-function
                        '(org-agenda-skip-entry-if 'notdeadline))
                       (org-agenda-sorting-strategy '(priority-down))))
           (agenda ""
                   ((org-agenda-entry-types '(:scheduled))
                    (org-agenda-overriding-header "SCHEDULED")
                    (org-agenda-skip-function
                     '(org-agenda-skip-entry-if 'todo 'done))
                    (org-agenda-sorting-strategy
                     '(priority-down time-down))
                    (org-agenda-span 'day)
                    (org-agenda-start-on-weekday nil)))
           (todo "DONE"
                 ((org-agenda-overriding-header "COMPLETED"))))
          ((org-agenda-format-date "")
           (org-agenda-start-with-clockreport-mode nil))) t))
   #+end_src

   The hotlist keeps a focus on tasks that may be heating up. This
   has three sections: overdue tasks, ones due within a week, and
   anything marked FLAGGED.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("fh" "Hotlist"
          ((tags-todo "DEADLINE<\"<+0d>\""
                      ((org-agenda-overriding-header "OVERDUE")))
           (tags-todo "DEADLINE>=\"<+0d>\"+DEADLINE<=\"<+1w>\""
                      ((org-agenda-overriding-header "DUE IN NEXT 7 DAYS")))
           (tags-todo "DEADLINE=\"\"+FLAGGED|DEADLINE>\"<+1w>\"+FLAGGED"
                      ((org-agenda-overriding-header "FLAGGED"))))
          ((org-agenda-todo-ignore-scheduled 'future)
           (org-agenda-sorting-strategy '(deadline-up)))) t))
   #+end_src

   Finally the /Hot & Fast/ view assembles tasks into three
   sections: overdue, take less then 1 hour, or a score of 1.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("ff" "Hot & Fast"
          ((tags-todo "DEADLINE<\"<+0d>\""
                      ((org-agenda-overriding-header "OVERDUE")))
           (tags-todo "Effort={.}+Effort<\"1:00\""
                      ((org-agenda-overriding-header "QUICK")))
           (tags-todo "SCORE=1"
                      ((org-agenda-overriding-header "EASY"))))) t))
   #+end_src

****** Review

   After processing incoming items and focusing on some work,
   there is the step of reviewing to ensure that progress is being
   made in the right spots.

   The set of views start on the =r= key.
   
   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("r" . "REVIEW...") t))
   #+end_src

   On a weekly basis, the view (=rw=) prvides a look back and look
   forward for all tasks.

   #+begin_src emacs-lisp
     (with-eval-after-load 'org
       (add-to-list
        'org-agenda-custom-commands
        '("rw" "Weekly review"
          ((tags "{INBOX}&LEVEL<=2"
                 ((org-agenda-overriding-header "NEW TASKS")))
           (agenda ""
                   ((org-agenda-clockreport-mode t)
                    (org-agenda-format-date
                     (concat "\n"
                             "%Y-%m-%d" " %a "
                             (make-string (window-width) ?_)))
                    (org-agenda-overriding-header "PAST WEEK")
                    (org-agenda-prefix-format " %?-11t %i %-12:c% s")
                    (org-agenda-show-log 'clockcheck)
                    (org-agenda-span 7)
                    (org-deadline-warning-days 0)))
           (agenda ""
                   ((org-agenda-overriding-header "NEXT MONTH")
                    (org-agenda-span 'month)
                    (org-agenda-start-day "+0d")
                    (org-deadline-warning-days 0)))
           (todo "PROJECT"
                 ((org-agenda-overriding-header "PROJECT LIST")))
           (todo "DONE|PROJECTDONE"
                 ((org-agenda-overriding-header
                   "Candidates to be archived"))))) t))
   #+end_src

******* All Tasks

    The first review section is for all tasks and launchable via
    =ra=.
   
    #+begin_src emacs-lisp
      (with-eval-after-load 'org
        (add-to-list
         'org-agenda-custom-commands
         '("ra" . "All Tasks...") t))
    #+end_src

    The first view lists tasks grouped by due dates.  The sections
    of this view list tasks that are overdue, due today, due
    tomorrow, due within a week, due within a month, due later,
    waiting for, and tasks without a due date.

    #+begin_src emacs-lisp
      (with-eval-after-load 'org
        (add-to-list
         'org-agenda-custom-commands
         '("rad" "All Tasks (grouped by Due Date)"
           ((tags-todo "DEADLINE<\"<+0d>\""
                       ((org-agenda-overriding-header "OVERDUE")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'notdeadline))))
            (tags-todo "DEADLINE=\"<+0d>\""
                       ((org-agenda-overriding-header "DUE TODAY")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'notdeadline))))
            (tags-todo "DEADLINE=\"<+1d>\""
                       ((org-agenda-overriding-header "DUE TOMORROW")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'notdeadline))))
            (tags-todo "DEADLINE>\"<+1d>\"+DEADLINE<=\"<+7d>\""
                       ((org-agenda-overriding-header "DUE WITHIN A WEEK")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'notdeadline))))
            (tags-todo "DEADLINE>\"<+7d>\"+DEADLINE<=\"<+28d>\""
                       ((org-agenda-overriding-header "DUE WITHIN A MONTH")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'notdeadline))))
            (tags-todo "DEADLINE>\"<+28d>\""
                       ((org-agenda-overriding-header "DUE LATER")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'notdeadline))))
            (tags-todo "TODO={WAIT}"
                       ((org-agenda-overriding-header "WAITING FOR")
                        (org-agenda-skip-function
                         '(org-agenda-skip-entry-if 'deadline))))
            (todo ""
                  ((org-agenda-overriding-header "NO DUE DATE")
                   (org-agenda-skip-function
                    '(org-agenda-skip-entry-if 'deadline)))))
           ((org-agenda-sorting-strategy '(priority-down))
            (org-agenda-write-buffer-name "All Tasks (grouped by Due Date)"))
           "~/Documents/Org/all-tasks-by-due-date.pdf") t))
    #+end_src

    Hitting =ra1= lists all tasks (with a due date) by due date.
   
    #+begin_src emacs-lisp
      (with-eval-after-load 'org
        (add-to-list
         'org-agenda-custom-commands
         '("ra1" "All Tasks with a due date" alltodo ""
           ((org-agenda-overriding-header "All Tasks (sorted by Due Date)")
            (org-agenda-skip-function
             '(org-agenda-skip-entry-if 'notdeadline))
            (org-agenda-sorting-strategy '(deadline-up)))) t))
    #+end_src

    
    
    #+begin_src emacs-lisp
      (defconst bnb/org-completed-date-regexp
        (concat " \\("
                "CLOSED: \\[%Y-%m-%d"
                "\\|"
                "- State \"\\(DONE\\)\" * from .* \\[%Y-%m-%d"
                "\\|"
                "- State .* ->  *\"\\(DONE\\)\" * \\[%Y-%m-%d"
                "\\) ")
        "Matches any completion time stamp.")

      (defun current-time-ndays-ago (n)
        "Return the current time minus N days."
        (time-subtract (current-time) (days-to-time n)))

      (with-eval-after-load 'org
        (add-to-list
         'org-agenda-custom-commands
         `("rac" "Completed view"
           ((todo "TODO|DONE"
                  ((org-agenda-overriding-header
                    (format "YESTERDAY [%s]" (format-time-string "%a %d" (current-time-ndays-ago 1))))
                   (org-agenda-skip-function
                    '(org-agenda-skip-entry-if
                      'notregexp
                      (format-time-string bnb/org-completed-date-regexp (current-time-ndays-ago 1))))
                   (org-agenda-sorting-strategy '(priority-down))))
            (todo "TODO|DONE"
                  ((org-agenda-overriding-header
                    (format "2 DAYS AGO [%s]" (format-time-string "%a %d" (current-time-ndays-ago 2))))
                   (org-agenda-skip-function
                    '(org-agenda-skip-entry-if
                      'notregexp
                      (format-time-string bnb/org-completed-date-regexp (current-time-ndays-ago 2))))
                   (org-agenda-sorting-strategy '(priority-down))))
            (todo "TODO|DONE"
                  ((org-agenda-overriding-header
                    (format "3 DAYS AGO [%s]" (format-time-string "%a %d" (current-time-ndays-ago 3))))
                   (org-agenda-skip-function
                    '(org-agenda-skip-entry-if
                      'notregexp
                      (format-time-string bnb/org-completed-date-regexp (current-time-ndays-ago 3))))
                   (org-agenda-sorting-strategy '(priority-down)))))
           ((org-agenda-format-date "")
            (org-agenda-start-with-clockreport-mode nil)))))
    #+end_src

******* Timesheets

    As part of a review, timesheets (reachable at =rt=) illustrate
    where the time went.
    
    #+begin_src emacs-lisp
      (with-eval-after-load 'org
        (add-to-list
         'org-agenda-custom-commands
         '("rt" . "Timesheet...") t))
    #+end_src

    The first timesheet is a daily one that includes the logged
    tasks and a clockreport.
   
    #+begin_src emacs-lisp
      (with-eval-after-load 'org
        ;; Show what happened today.
        (add-to-list
         'org-agenda-custom-commands
         '("rtd" "Daily Timesheet" agenda ""
           ((org-agenda-log-mode-items '(clock closed))
            (org-agenda-overriding-header "DAY TIMESHEET")
            (org-agenda-show-log '(clock closed clockcheck))
            (org-agenda-span 'day)
            (org-agenda-start-with-clockreport-mode t)
            (org-agenda-start-with-log-mode t)
            (org-agenda-time-grid nil))) t))
    #+end_src

    Naturally, the level up from a daily timesheet is a weekly
    timesheet (reachable via =rtw=).
    
    #+begin_src emacs-lisp
      (with-eval-after-load 'org
        ;; Show what happened this week.
        (add-to-list
         'org-agenda-custom-commands
         '("rtw" "Weekly Timesheet" agenda ""
           (
            ;; (org-agenda-format-date "")
            (org-agenda-overriding-header "WEEKLY TIMESHEET")
            (org-agenda-skip-function '(org-agenda-skip-entry-if 'timestamp))
            (org-agenda-span 'week)
            (org-agenda-log-mode-items '(closed clock))
            (org-agenda-show-log '(closed clock))
            (org-agenda-start-on-weekday 1)
            (org-agenda-start-with-clockreport-mode t)
            (org-agenda-start-with-log-mode t)
            (org-agenda-time-grid '(weekly)))) t))
    #+end_src

**** Export

 THe following sections configue global export settings that make
 sense for HTML and \LaTeX.

***** HTML

  For HTML, I just want to inline the links to images.

  #+begin_src emacs-lisp
    (setq org-export-html-inline-images t)
  #+end_src

  I suppress the postamble with [[help:org-html-postamble][org-html-postamble]].

  #+begin_src emacs-lisp
    (setq org-html-postamble nil)
  #+end_src

  I'll use the /fancy/ HTML5 export by default.

  #+begin_src emacs-lisp
    (setq org-html-doctype "html5"
          org-html-html5-fancy t)
  #+end_src

  Striped tables are nice in email, but this is terribly difficult
  due to cruddy CSS support. Luckily, [[https://orgmode.org/manual/Tables-in-HTML-export.html][org-html-table-row-tags]]
  saves the day and assigns the right classes to the table rows
  with a little bit of help. This makes styling correct in
  CSS-reduced instances.

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (setq org-html-table-row-tags
            (cons '(cond (top-row-p "<tr class=\"tr-top\">")
                         (bottom-row-p "<tr class=\"tr-bottom\">")
                         (t (if (= (mod row-number 2) 1)
                                "<tr class=\"tr-odd\">"
                              "<tr class=\"tr-even\">")))
                  "</tr>"))) 
  #+end_src

***** LaTeX

  For \LaTeX, I want to convert fragments to images, and use
  [[https://ctan.org/pkg/minted?lang=en][minted]] for any source blocks. I also want to have [[https://en.wikipedia.org/wiki/XeTeX][XeTeX]] as the
  backend.

  #+begin_src emacs-lisp
    (setq org-export-latex-listings 'minted
          org-export-latex-custom-lang-environments
          '((emacs-lisp "common-lispcode"))
          org-export-latex-minted-options '()
          org-highlight-latex-and-related '(latex script entities)
          org-latex-to-pdf-process
          '("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
            "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
            "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
  #+end_src

***** Tufte

  Other contributed org-mode exporters require activiation to show
  up in the export menus. This exporter stylizes =html= in a
  beautiful way.

  #+begin_src emacs-lisp
    (use-package ox-tufte
      :after org-mode
      :ensure t)
  #+end_src

***** Github Flavored Markdown

  Useful on its own, but required for the [[*Slack][Slack]] exporter, the [[https://github.com/larstvei/ox-gfm][GFM]]
  exporter transforms the current orgmode buffer into markdown
  (yuck).

  #+begin_src emacs-lisp
    (use-package ox-gfm
      :after org-mode
      :ensure (ox-gfm :depth nil :version "1.0"))
  #+end_src

***** Slack

  [[https://github.com/titaniumbones/ox-slack][This exporter]] is not added to the export dispatcher, but
  provides functions to copy the text into the clipboard or open a
  buffer with the markdown.
  
  #+begin_src emacs-lisp
    (use-package ox-slack
      :after (ox-gfm org-mode)
      :bind
      (:map org-mode-map
            ("C-c e c" . org-slack-export-to-clipboard-as-slack)
            ("C-c e b" . org-slack-export-as-slack))
      :ensure t)
  #+end_src

**** Clocking

 I have found clocking to be useful in understanding where my time
 goes. And Org makes this easy, fast, and painless to do.

 The clock has some general settings around persistence (resuming
 clocks), history length and resuming a task after clocking in
 twice (interrupted task).

 #+begin_src emacs-lisp
   (with-after-elpaca-init
     (org-clock-persistence-insinuate)
     (setq org-clock-history-length 28
           org-clock-in-resume t))
 #+end_src

 Behavior of the clock can change to accommodate other needs. I
 like having clocks log into a specific drawer. Also, it is nice
 to remove zero-time clocks and clock out automatically when an
 item completes.

 #+begin_src emacs-lisp
   (setq org-clock-into-drawer "CLOCK"
         org-clock-out-remove-zero-time-clocks t
         org-clock-out-when-done t)
 #+end_src

 Two settings help resolve most clock issues that I have
 seen. Persisting the clock across sessions helps prevent loss of
 time by accident. Auto-resolution of open clocks help prompt how
 to handle the situation where a dangling clock exists.

 #+begin_src emacs-lisp
   (setq org-clock-persist 'history
         org-clock-auto-clock-resolution 'when-no-clock-is-running)
 #+end_src

 Two final settings regarding clocking configure how I change and
 view the clocks. I want any clock reports to include the
 currently clocked task as well. And for clock editing, I change
 to 15 minute increments.

 #+begin_src emacs-lisp
   (setq org-clock-report-include-clocking-task t
         org-time-stamp-rounding-minutes '(1 15))
 #+end_src

**** Modules

 Org-modules allow for specific functionality within
 org-mode. These modules (plugins) activate by adding them to the
 list of [[help:org-modules][org-modules]].

 #+begin_src emacs-lisp
   (with-eval-after-load 'org
     (mapc (lambda (x) (add-to-list 'org-modules x t))
           '(org-id
             org-habit
             org-plot
             org-protocol
             ol-bookmark)))
 #+end_src

***** Global Ids

  By enabling the =org-id= module, =org= will use globally unique
  identifiers for entries.

***** Habit

  Some tasks repeat, but you still want to log when you have done
  it. I use this to help me always do my weekly or yearly
  reviews. By including it in =org-modules=, habits get activated.

  My one setting blow sets a width for the graph in Agenda View.

  #+begin_src emacs-lisp
    (setq org-habit-graph-column 50)
  #+end_src

  To view habits in the agenda (not just on today), try =C-u K=.

  To ensure that a task is treated as a /habit/, the =STYLE= property
  will have to be set to =habit=.  [[info:org#Tracking your habits][Read more in the manual]].

***** Org protocol

  External applications can have actions in =org-mode= through the
  use of protocols. A popular usage is accepting bookmarks from
  browsers. [[info:org#Protocols][Read more about it in the manual]].

***** Bookmarks

  The org linking system is powerful in the way it can connect to
  many part of Emacs. This module enables links to any stored
  bookmark.

**** Babel

 Babel is some serious magic for Org files. It enables tangled
 code blocks (this file), notebook-style interactive documents,
 delarative diagrams, and nicely-formatted examples.

 Each code block can have a different language and be edited
 remotely in a properly mode'd buffer.

 This is the list of languages I like to have enabled for use.
 
 #+begin_src emacs-lisp
   (with-after-elpaca-init
     (org-babel-do-load-languages
      'org-babel-load-languages
      '((calc       . t)
        (C          . t)
        (ditaa      . t)
        (dot        . t)
        (emacs-lisp . t)
        (gnuplot    . t)
        (latex      . t)
        (maxima     . t)
        (perl       . t)
        (plantuml   . t)
        (python     . t)
        (ruby       . t)
        (shell      . t)
        (sqlite     . t)
        (sql        . t)
        (R          . t))))
 #+end_src

***** Extra Babel Packages

  These two packages assist with making HTTP requets. They can act
  like an alternative to Postman.
  
  #+begin_src emacs-lisp
    (use-package ob-http :after org-mode
      :ensure t)

    (use-package ob-restclient
      :after org-mode
      :ensure (ob-restclient :host github :repo "alf/ob-restclient.el")
      :config
      (org-babel-do-load-languages
       'org-babel-load-languages
       (append org-babel-load-languages '((restclient . t)))))
  #+end_src

***** Customization

  Python needs to find the right executable, so I hard code what babel
  should use for a command.

  #+begin_src emacs-lisp
    (setq org-babel-python-command "python3")
  #+end_src

**** Miscellaneous Settings

 This section holds important small preferences for Org.

***** Auto-revert mode

  If the org files are under DVCS like git, then the edits may
  happen while open in emacs.

  This is a global setting, but most useful for the org files that
  exists elsewhere.

  #+begin_src emacs-lisp
    (use-package autorevert
      :ensure nil
      :defer 10
      :diminish " "
      :custom
      (global-auto-revert-mode t))
  #+end_src

***** Automatically save org files

  I like to save early and often. In earlier versions of orgmode, I
  sometimes had the capture buffer/timer crash on me. So, now I
  save at the top of every hour to be sure.

  #+begin_src emacs-lisp
    (with-eval-after-load 'org
      (run-at-time "00:59" 3600 'org-save-all-org-buffers))
  #+end_src

***** Columns

  The default columns are as follows. In English, it shows the
  item (or task), the score, the effort estimate, and the current
  clock sum (time already spent).

  #+begin_src emacs-lisp
    (setq
     org-columns-default-format
     "%80ITEM(Task) %5Score{+} %10Effort(Effort){:} %10CLOCKSUM")
  #+end_src

***** Display settings

  There are a collection of settings that define how the
  headlines, subtrees, and notes render.

  For the headline stars, there are two settings of note. I am
  explicit that I do *not* want only odd levels. I also like to hide
  the leading stars.

  #+begin_src emacs-lisp
    (setq org-odd-levels-only nil
          org-hide-leading-stars nil)
  #+end_src

  Cycling the headline states can produce different views of the
  files. I like this to be as compact as possible, so I try to
  squash the lines between the collapsed trees. There is also a
  flag to open a file collapsed. This I like too -- I get a
  compact view of the file and can jump to a relevant section with
  =C-c C-j=.

  #+begin_src emacs-lisp
    (setq org-cycle-separator-lines 0
          org-startup-folded 'content)
  #+end_src

  When using SRC-blocks, org can provide highlighting native to
  the SRC type. Note that this may slow down some files.

  #+begin_src emacs-lisp
    (setq org-src-fontify-natively t)
  #+end_src

***** File Applications

  This list lets org know how to handle the links of given file
  types. Most things open inside =emacs=, but the others set to
  default rely on the OS to supply a program.

  #+begin_src emacs-lisp
    (setq org-file-apps
          '((auto-mode . emacs)
            ("\\.x?html?\\'" . default)
            ("\\.pdf\\'"     . default)
            ("\\.mm\\'"      . default)))
  #+end_src

***** Goto Interface

  By using =C-c C-j=, you can jump easily around a large orgfile
  such as this one. Naturally, the interface you use to do so is
  customizable.

  I explicitly set it to the default because I sometimes go back
  and forth with the default and =outline-path-completion= setting.

  #+begin_src emacs-lisp
    (setq org-goto-interface 'outline-path)
  #+end_src

***** IDO Integration

  IDO integrates well into orgmode. Anytime completion is
  necessary, I like to use the IDO mechanics.

  The =outline-path-completion= may conflict with IDO, so then it is
  best to have it not use IDO in this case.

  #+begin_src emacs-lisp
    (setq org-completion-use-ido t
          org-outline-path-complete-in-steps nil)
  #+end_src

***** Insertion

  I define when org should leave a blank line before an
  item. In my case it is headings and plain list items.

  #+begin_src emacs-lisp
    (setq org-blank-before-new-entry
          '((heading)
            (plain-list-item)))
  #+end_src

  Also, when inserting a new heading, do so after the current
  subtree.

  #+begin_src emacs-lisp
    (setq org-insert-heading-respect-content t)
  #+end_src

  Set the indentation to the outline node level.

  #+begin_src emacs-lisp
    (setq org-adapt-indentation t)
  #+end_src

***** Plantuml

  Setup the path for orgmode to find the jar needed.

  #+begin_src emacs-lisp
    (setq org-plantuml-jar-path "/usr/local/Cellar/plantuml/1.2017.18/libexec/plantuml.jar")
  #+end_src

***** Properties

  Here I add my global properties. The appendix =_ALL= indicates to
  the system that these are the values avaialble for completion
  for each of these properties.

  #+begin_src emacs-lisp
    (setq org-global-properties
          '(("STYLE_ALL"  . "habit")
            ("Effort_ALL" . "0:10 0:30 1:00 2:00 3:00 4:00")
            ("Score_ALL"  . "1 2 3 5 8")))
  #+end_src

***** Special Control Keys

  Org has a different idea of some of the default emacs commands
  to make it easier to work with the structures involved.

  For =C-a= or =C-e= within a headline, it will only try to navigate
  the headline text the first time. Additional keypresses will
  move to the true beginning/ending of lines.

  =C-k= also can behave specially in headlines depending on its
  location. When point is at the beginning, it will kill the
  headline and the folded subtree below. In the middle of a
  headline, it kills the headline text up to the tags. After the
  headline text, it kills the tags.

  #+begin_src emacs-lisp
    (setq org-special-ctrl-a/e t
          org-special-ctrl-k t)
  #+end_src

**** Pretty Org-mode

 This collection of settings enhances the visual appeal when
 working in org-mode.

 First, some initial built-in settings to make.This block styles
 the headlines to hide the stars, and fontify them. The next
 setting hides emphasis markers on words. And finally, entities
 are drawn with UTF-8 characters.

 #+begin_src emacs-lisp
   (setq org-hide-leading-stars t
         org-fontify-done-headline t
         org-hide-emphasis-markers t
         org-pretty-entities t)
 #+end_src

 Using [[*Prettify Symbols][Prettify]], I add these symbols to make the structure of
 org-mode files cleaner to read. In the list, the strings on the
 left are replaced by the elements on the right. Moving a cursor
 over the symbols will show them in their original form.

 #+begin_src emacs-lisp
   (bnb/prettify
    "org-mode"
    '(("#+BEGIN_SRC" . "โŒˆ")
      ("#+END_SRC"   . "โŒŠ")
      ("#+begin_src" . "โŒˆ")
      ("#+end_src"   . "โŒŠ")
      (">="          . "โ‰ฅ")
      ("=>"          . "โ‡จ")))
 #+end_src

***** Org Bullets

  Bullet shapes do a better job conveying depth then just
  position/depth of stars. This snippet loads the package and sets
  the list of bullets to use.
  
  #+begin_src emacs-lisp
    (use-package org-bullets
      :ensure t
      :custom
      (org-bullets-bullet-list '("โ—‰" "โ—Š" "โ—‹" "โงซ" "โœธ" "โฌจ" "โฌŸ" "โฌง" "โฌข" "โฌซ" "โŒ‘" "โฌช" "โ–ฑ"))
      (org-ellipsis "หฏ") ;; Options: หฏโ‡‚โ†ฏโคต๐Ÿ ป๐Ÿข—
      :hook (org-mode . org-bullets-mode))
  #+end_src

**** Org-AI

 As much as I find this to be ridiculous, interacting with AI via
 Emacs is likely the one true way. [[https://github.com/rksm/org-ai][Org-ai]] provides a natrual
 interface for real humans.

 #+begin_src emacs-lisp
   (use-package org-ai
     :ensure t
     :commands (org-ai-mode
                org-ai-global-mode)
     :init
     (org-ai-global-mode) ; installs global keybindings on C-c M-a
     :custom
     (org-ai-default-chat-model "gpt-3.5-turbo")
     :config
     (org-ai-install-yasnippets))
 #+end_src

 This adds the ability to have =#+begin/end_ai= blocks to have a
 "conversation" with ChatGPT or DALLโ‹…E. Be sure to set
 [[help:org-ai-openai-api-token][org-ai-openai-api-token]] to your API token before using.

**** Org Repo Todo :PENDING:

 Make it easy to setup a =TODO.org= from within a repo. I use this
 to capture thoughts while coding.

 #+begin_src emacs-lisp
   (use-package org-repo-todo
     :ensure t
     :bind (("s-;" . ort/capture-todo)
            ("s-'" . ort/capture-checkitem)
            ("s-`" . ort/goto-todos)))
 #+end_src

**** Org Ref

 Setups the Org-style interface with Biblio.
 #+begin_src emacs-lisp
   (use-package org-ref
     :defer 10
     :config
     (setq org-ref-notes-directory "~/Documents/Personal/Org/Biblio/"
           org-ref-bibliography-notes "~/Documents/Personal/Org/Biblio/index.org"
           org-ref-default-bibliography '("~/Documents/Personal/Org/Biblio/index.bib")
           org-ref-pdf-directory "~/Documents/Personal/Org/Biblio/lib"))
 #+end_src

**** Org Noter

 [[https://github.com/weirdNox/org-noter][Taking notes in a PDF]] is a useful trick. =org-noter= lets me do
 just that.

 #+begin_src emacs-lisp
   (use-package org-noter
     :ensure t
     :bind ("H-n" . org-noter))
 #+end_src

**** Org Roam

 The best of all worlds? Org-mode and a Zettelkasten system? Yes,
 [[https://www.orgroam.com/][Org-roam]] sets up a knowledge capture and organization system
 built on the principles of [[https://en.wikipedia.org/wiki/Zettelkasten][Zettelkasten]].

 #+begin_src emacs-lisp
   (use-package org-roam
     :ensure t
     :after org
     :delight "โ€‰๐•ซ"
     :hook
     (after-init . org-roam-setup)
     :init
     (setq org-roam-v2-ack t)
     :custom
     (org-roam-directory (file-truename "~/Documents/Org/zettel/"))
     :bind
     (("C-c n f" . org-roam-node-find)
      ("C-c n r" . org-roam-node-random)
      ("C-c n g" . org-roam-graph)
      ("C-c n c" . org-roam-capture)
      ("C-c n j" . org-roam-dailies-capture-today)
      (:map org-mode-map
            (("C-c n l" . org-roam-buffer-toggle)
             ("C-c n a" . org-roam-alias-add)
             ("C-c n i" . org-roam-node-insert)
             ("C-c n I" . org-roam-insert-immediate)))
      (:map org-roam-mode-map
            (("C-c n l" . org-roam)
             ("C-c n t" . org-roam-dailies-find-today)
             ("C-c n w" . org-roam-dailies-find-tomorrow)
             ("C-c n d" . org-roam-date)
             ("C-c n f" . org-roam-find-file)
             ("C-c n g" . org-roam-show-graph)))))
 #+end_src

**** Org QL :PENDING:

 The Org Query Language helps walk through a builder interface to
 find, filter, and sort org entries.

 #+begin_src emacs-lisp
   (use-package org-ql
     :after org
     :commands (org-ql-search org-ql-view-sidebar)
     :bind
     ("C-c q s" . org-ql-search)
     ("C-c q b" . org-ql-view-sidebar)
     ("C-c q v" . org-ql-view)
     ("C-c q t" . org-ql-sparse-tree)
     ("C-c q r" . org-ql-view-recent-items)
     (:map org-mode-map
           ("C-c q f" . org-ql-find))
     :ensure t
     :demand t)
 #+end_src

 This package is built on a library of searching functions, so it
 also has some neat tricks like easily specifying agenda views and
 building code blocks.

 For example, to get a link to a dynamic list of pending items (in
 this file), click on this: [[org-ql-search:tags:PENDING]].

*** PDF Tools

This replaces the built-in DocView for PDF files. Find out the
details [[https://pdftools.wiki/][on the wiki]].

The part that I like over DocView is the ability to add
annotations. They all live on =C-c C-a=.

| Key       | Action                   |
|-----------+--------------------------|
| =C-c C-a D= | delete annotation        |
| =C-c C-a a= | attachment dired         |
| =C-c C-a h= | add highlight            |
| =C-c C-a l= | list annotations         |
| =C-c C-a m= | add markup               |
| =C-c C-a o= | add strikeout annotation |
| =C-c C-a s= | add squiggly annotation  |
| =C-c C-a t= | add text annotation      |
| =C-c C-a u= | add underline annotation |


#+begin_src emacs-lisp
  (defcustom bnb/homebrew-prefix ""
    "Prefix to use for an alternative path to homebrew items"
    :type 'string
    :group 'bnb)

  (setenv "PKG_CONFIG_PATH"
          (let ((hbp bnb/homebrew-prefix))
            (setq pdf-info-epdfinfo-program (concat hbp "/usr/local/bin/epdfinfo"))
            (mapconcat
             'identity
             (list (concat hbp "/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig")
                   (concat hbp "/usr/local/Cellar/zlib/1.2.8/lib/pkgconfig")
                   (concat hbp "/usr/local/lib/pkgconfig")
                   "/opt/X11/lib/pkgconfig")
             ":")))

  (use-package pdf-tools
    :defer t
    :ensure t
    :config
    (custom-set-variables '(pdf-tools-handle-upgrades nil))
    (setq-default pdf-view-display-size 'fit-page)
    (pdf-loader-install))
#+end_src

** Miscellaneous

This sections holds configuration details for some of the uncategorized major modes.

*** Calc

Working in computer land, I add these additional units to ~calc~.

#+begin_src emacs-lisp
  (use-package calc
    :ensure nil
    :commands (calc)
    :init
    (setq math-additional-units
          '((GiB "1024 * MiB" "Giga Byte")
            (MiB "1024 * KiB" "Mega Byte")
            (KiB "1024 * B"   "Kilo Byte")
            (B   nil          "Byte")
            (Gib "1024 * Mib" "Giga bit")
            (Mib "1024 * Kib" "Mega bit")
            (Kib "1024 * b"   "Kilo bit")
            (b   nil          "bit")
            )))
#+end_src

*** Dashboard

Instead of the normal "splash" screen, show a [[https://github.com/emacs-dashboard/emacs-dashboard][dashboard]] instead.

#+begin_src emacs-lisp
  (use-package dashboard
:unless (daemonp)
:ensure t
:hook
(elpaca-after-init . #'dashboard-insert-startupify-lists)
(elpaca-after-init . #'dashboard-initialize)
:custom
(dashboard-set-file-icons t)
(dashboard-icon-type 'nerd-icons)
(dashboard-set-heading-icons t)
(dashboard-projects-backend 'project-el)
(dashboard-items '((recents . 5)
		   (agenda . 10)
		   (projects . 5)
		   (bookmarks . 10)
		   (registers . 10)))
:config
(dashboard-modify-heading-icons
 '((recents   . "nf-oct-pin")      ;; ๏ต
   (agenda    . "nf-oct-goal")     ;; ๏“ž
   (projects  . "nf-oct-project")  ;; ๏”‚
   (bookmarks . "nf-oct-bookmark") ;; ๏‘ก
   (registers . "nf-oct-rows")))   ;; ๏”‹
(dashboard-setup-startup-hook))
#+end_src

*** Hyperbole :PENDING:

[[https://www.gnu.org/software/hyperbole/][GNU Hyperbole]] enriches buffers with links like hypertext.  Try =C-h
h= for the binding.  And =M-RET= for links (explicit and implicit).

#+begin_src emacs-lisp
  (use-package hyperbole
    :ensure t
    :config (hyperbole-mode 1))
#+end_src

** Programming Languages

Hardly needing an introduction, this section holds the modes and settings related to authoring in, and connecting to my favorite (and necessary) programming languages and interpreters.

*** C++

I don't need much extra for C++ support, but the following snippet
makes compilation nicer.

**** Compilation Buffers

 I forget where I snarfed this from, but it does a great job
 fixing the ANSI escape sequences in compilation buffers.

 #+begin_src emacs-lisp
   (use-package ansi-color
     :ensure nil
     :hook ((compliation-filter . colorize-compilation-buffer))
     :config
     (defun colorize-compilation-buffer ()
       (toggle-read-only)
       (ansi-color-apply-on-region compilation-filter-start (point))
       (toggle-read-only)))
 #+end_src

*** Elisp

When modified =emacs-lisp=, it is most helpful to use [[*Paredit][paredit]],
[[*Paxedit][paxedit]], and [[*Eldoc][eldoc]].

#+begin_src emacs-lisp
  (use-package elisp-mode
    :ensure nil
    :after (major-mode-hydra)
    :mode-hydra
    (emacs-lisp-mode
     (:title "Elisp Commands")
     ("Eval"
      (("b" eval-buffer "buffer")
       ("e" eval-defun "defun")
       ("r" eval-region "region")
       ("d" edebug-defun "edebug-defun"))
      "REPL"
      (("I" ielm "ielm"))
      "Test"
      (("t" ert "prompt")
       ("T" (ert t) "all")
       ("F" (ert :failed) "failed"))
      "Doc"
      (("." describe-foo-at-point "thing-at-pt")
       ("f" describe-function "function")
       ("v" descrive-variable "variable")
       ("i" info-lookup-symbol "info lookup"))))
    :hook
    (emacs-lisp-mode . paredit-mode)
    (emacs-lisp-mode . paxedit-mode)
    (emacs-lisp-mode . turn-on-eldoc-mode))
#+end_src

When programming in =elisp=, a [[https://www.masteringemacs.org/article/emacs-builtin-elisp-cheat-sheet][cheat sheet]] of functions can be very
useful. New to Emacs 28, [[help:shortdoc][shortdoc]] provides that useful, quick,
navigatable list of documentation.

*** Javascript

For javascript, the only global setting is to shorten the
indentation level to 2.

#+begin_src emacs-lisp
  (setq js-indent-level 2)
#+end_src

*** Plantuml

Not a /programming language/, but certainly a language. I typically
use this in Org document blocks to generate diagrams. The
[[https://plantuml.com/guide][reference guide]] is available online.

#+begin_src emacs-lisp
  (use-package plantuml-mode
    :ensure t)
#+end_src

*** Python

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (bnb/prettify
     "python-base-mode"
     '(;; Syntax
       ("def"      . ?โ„ฑ)
       ("not"      . ?โ—)
       ("in"       . ?โˆˆ)
       ("not in"   . ?โˆ‰)
       ("return"   . ?โŸผ)
       ("yield"    . ?โŸป)
       ("for"      . ?โˆ€)
       ;; Base Types
       ("int"      . ?โ„ค)
       ("float"    . ?โ„)
       ("str"      . ?๐•Š)
       ("True"     . ?๐•‹)
       ("False"    . ?๐”ฝ)
       ;; Mypy
       ("Dict"     . ?๐”‡)
       ("List"     . ?โ„’)
       ("Tuple"    . ?โจ‚)
       ("Set"      . ?โ„ฆ)
       ("Iterable" . ?๐”Š)
       ("Any"      . ?โ”)
       ("Union"    . ?โˆช)))

    (add-to-list
     'major-mode-remap-alist
     '(python-mode . python-ts-mode)))
#+end_src

**** PET

 The [[https://github.com/wyuenho/emacs-pet][Python Executable Tracker]] seeks to solve the issue of LSP and
 python virtual environments.

 #+begin_src emacs-lisp
   (defun bnb/pet-setup ()
     (setq-local python-shell-interpreter (pet-executable-find "python")
                 python-sehll-virtualenv-root (pet-virtualenv-root))
     (pet-eglot-setup)
     (eglot-ensure)
     (pet-flycheck-setup)
     (flycheck-mode))

   (use-package pet
     :hook
     (python-base-mode . bnb/pet-setup)
     (python-base-mode . pet-mode))
 #+end_src

*** Rust

#+begin_src emacs-lisp
  (use-package rust-mode
    :ensure t
    :custom
    (rust-mode-treesitter-derive t)
    :config
    (add-to-list 'eglot-server-programs
               '((rust-ts-mode rust-mode) .
                 ("rust-analyzer" :initializationOptions (:check (:command "clippy"))))))
#+end_src


#+begin_src emacs-lisp
  (use-package flycheck-rust
    :after rust-mode
    :hook
    (flycheck-mode-hook . flycheck-rust-setup))
#+end_src


#+begin_src emacs-lisp
  (use-package toml-mode
    :ensure (toml-mode :host github :repo "dryman/toml-mode.el")
    :mode "\\.toml\\'")
#+end_src


I also snuck in [[https://toml.io/en/][TOML]] support for the Cargo.toml files.

*** Emacs Speaks Statistics (ESS)

For my data crunching tasks, I use R and [[https://ess.r-project.org/][ESS]] (emacs speaks
statistics) provides an interface (repl) for developing analysis
and charts.

#+begin_src emacs-lisp
  (use-package ess
    :ensure t
    :commands (R)
    :custom
    (ess-default-style 'Rstudio-)
    :init (require 'ess-site))
#+end_src

*** Utilities

These utilities make the programming experience easier across many
languages.

**** Flycheck

 Similar to spellchecking, [[https://www.flycheck.org/en/latest/][Flycheck]] performs on-the-fly syntax
 checking. I don't have it globally on, but easily available
 through =H-!=.
 
 #+begin_src emacs-lisp
   (use-package flycheck
     :ensure t
                                           ;:init (global-flycheck-mode)
     :init
     (pretty-hydra-define hydra-flycheck (:color amaranth :quit-key "q" :title "๎˜ฟ FlyCheck")
       ("Action"
        (("c" flycheck-mode "Buffer flycheck")
         ("g" global-flycheck-mode "Global flycheck mode"))
        "Errors"
        (("n" flycheck-next-error "Next error")
         ("p" flycheck-previous-error "Previous error")
         ("l" flycheck-list-errors "List errors")
         ("C" flycheck-clear-errors "Clear errors"))
        "Explanation"
        (("x" flycheck-explain-error-at-point "Explain error")
         ("h" flycheck-display-error-at-point "Dieplay error")
         ("s" flycheck-select-checker "Select checker")
         ("?" flycheck-describe-checker "Describe checker"))))
     :bind
     ("H-!" . hydra-flycheck/body))
 #+end_src

**** Prog fill

 To go from wide lines to vertical, [[https://github.com/ahungry/prog-fill][prog-fill]] comes into the
 rescue.
 
 #+begin_src emacs-lisp
   (use-package prog-fill
     :ensure t
     :commands (prog-fill)
     :hook
     (prog-mode . (lambda () (local-set-key (kbd "M-q") #'prog-fill)))
     :bind
     ("H-q" . prog-fill)
     :custom
     (prog-fill-floating-close-paren-p nil)
     (prog-fill-break-method-immediate-p t))
 #+end_src

**** Smart Tabs

 [[http://www.emacswiki.org/emacs-en/SmartTabs][SmartTabs]] try to do the right thing regarding tabs/spaces in
 indentation/alignment. It installs through the package interface. Look for
 =smart-tabs-mode=.

 By default, I'm enabling it in all modes that I can.
 
 Since we are dealing with tabs here, I also take the time to set
 the default width to 4. Because of the way this mode works, any
 change in the default width will result in code that still aligns.

 #+begin_src emacs-lisp
   (use-package smart-tabs-mode
     :defer 10
     :ensure t
     :init
     (setq-default indent-tabs-mode nil)
     (smart-tabs-insinuate 'c 'cperl 'c++))
 #+end_src

***** Notes

  To re-tab the whole file, use =C-x h C-M-\=.

**** Treesit

 Now built into Emacs 29, Tree-Sitter is a new parsing
 library. [[https://www.masteringemacs.org/article/how-to-get-started-tree-sitter][Read more about it online.]] This code sets up the library
 for Emacs 29 and greater, and installs come common grammars.
 
 #+begin_src emacs-lisp
   (use-package treesit
     :ensure nil ;; built-in
     :if (version<= "29" emacs-version)
     :init
     (defun bnb/treesit-setup-install-grammars ()
       "Install Tree-sitter grammars if they are absent."
       (interactive)
       (dolist (grammar
                 '((css        . ("https://github.com/tree-sitter/tree-sitter-css" "v0.20.0"))
                   (html       . ("https://github.com/tree-sitter/tree-sitter-html" "v0.20.1"))
                   (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.20.1" "src"))
                   (json       . ("https://github.com/tree-sitter/tree-sitter-json" "v0.20.2"))
                   (python     . ("https://github.com/tree-sitter/tree-sitter-python" "v0.20.4"))
                   (toml       . ("https://github.com/tree-sitter/tree-sitter-toml" "v0.5.1"))
                   (rust       . ("https://github.com/tree-sitter/tree-sitter-rust" "v0.21.2" "src"))
                   (yaml       . ("https://github.com/ikatyang/tree-sitter-yaml" "v0.5.0"))))
         (add-to-list 'treesit-language-source-alist grammar)
         ;; Only install `grammar' if we don't already have it
         ;; installed. However, if you want to *update* a grammar then
         ;; this obviously prevents that from happening.
         (unless (treesit-language-available-p (car grammar))
           (treesit-install-language-grammar (car grammar)))))

     ;; Optional, but recommended. Tree-sitter enabled major modes are
     ;; distinct from their ordinary counterparts.
     ;;
     ;; You can remap major modes with `major-mode-remap-alist'. Note
     ;; that this does *not* extend to hooks! Make sure you migrate them
     ;; also
     (dolist (mapping
            '((python-mode     . python-ts-mode)
              (css-mode        . css-ts-mode)
              (js2-mode        . js-ts-mode)
              (bash-mode       . bash-ts-mode)
              (css-mode        . css-ts-mode)
              (json-mode       . json-ts-mode)
              (js-json-mode    . json-ts-mode)))
       (add-to-list 'major-mode-remap-alist mapping))
     :config
     (bnb/treesit-setup-install-grammars))
 #+end_src

**** Combobulate :PENDING:

 Enable structured editing and movement with [[https://github.com/mickeynp/combobulate][Combobulate]].
 
 #+begin_src emacs-lisp
   (use-package combobulate
     :after treesit
     :if (version<= "29" emacs-version)
     :ensure (combobulate :host github :repo "mickeynp/combobulate")
     :custom
     ;; You can customize Combobulate's key prefix here.
     ;; Note that you may have to restart Emacs for this to take effect!
     (combobulate-key-prefix "C-c o")

     ;; Optional, but recommended.
     ;;
     ;; You can manually enable Combobulate with `M-x
     ;; combobulate-mode'.
     :hook
     ((python-ts-mode . combobulate-mode)
      (js-ts-mode     . combobulate-mode)
      (html-ts-mode   . combobulate-mode)
      (css-ts-mode    . combobulate-mode)
      (yaml-ts-mode   . combobulate-mode)
      (json-ts-mode   . combobulate-mode)))
 #+end_src

*** Web Mode

For all of the webish-stuff, this mode works well. Let's enable it
on the right things.

#+begin_src emacs-lisp
  (use-package web-mode
    :defer
    :mode "\\.html\\'"
    :ensure t
    :bind ("H-b" . browse-url-of-file)
    :custom
    (web-mode-markup-indent-offset 2)
    (web-mode-css-indent-offset 2)
    (web-mode-code-indent-offset 2)
    (web-mode-engines-alist '(("handlebars" . "\\.hbs\\'")))
    :config
    (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'"  . web-mode))
    (add-to-list 'auto-mode-alist '("\\.erb\\'"      . web-mode))
    (add-to-list 'auto-mode-alist '("\\.hbs\\'"      . web-mode))
    (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.djhtml\\'"   . web-mode))
    (add-to-list 'auto-mode-alist '("\\.svelte\\'"   . web-mode)))
#+end_src

** Shells

There are two useful shells in emacs: =eshell= and =ansi-term=.

*** Ansi Term

These settings close =ansi-term= when I exit the shell. They also
default to just launching =zsh= instead of asking me
(preferred). Then it closes by setting up a hook to ensure some
nice functionality in the terminal mode window.

#+begin_src emacs-lisp
  (defun bnb/term-mode-hook ()
    "Setup `term-mode`."
    (goto-address-mode)
    (setq-local term-buffer-maximum-size 10000))

  (use-package term
    :ensure nil
    :hook (term-mode . bnb/term-mode-hook)
    :init
    (defalias 'zsh 'ansi-term)
    :custom
    (ansi-term-color-vector  [term term-color-black term-color-red term-color-green term-color-yellow term-color-blue term-color-magenta term-color-cyan term-color-white])
    (ansi-color-faces-vector [default bold shadow italic underline bold bold-italic bold]))
#+end_src


My hook above makes it easy to click on links in any output and
protects the buffer from runaway printing.

*** Eshell

Built-in Eshell can provide a shell that works the same on windows
or GNU/Linux. One of the really cool features is that you can
define commands to use (like aliases) within the shell and have
them directly integrate with emacs.

**** Eshell Settings

 Turn off any =$PAGER= settings inherited in the
 environment. Because this is running in Emacs, there is no need
 for a pager.

 #+begin_src emacs-lisp
   (setenv "PAGER" "cat")

   (defun bnb/setup-eshell ()
     "Setup functions to run in the eshell hook"
     (eshell/alias "em" "emacs")
     (eshell/alias "ll" "ls -Aloh")
     (pcase system-type
       ('darwin (eshell/alias "llc" "*ls -AlohG"))
       (-       (eshell/alias "llc" "*ls -AlohG --color=always"))))

   (use-package eshell
     :ensure nil
     :commands eshell
     :hook (eshell-mode . bnb/setup-eshell))
 #+end_src

**** Eshell Commands

 Like many shells, =eshell= allows for the definition of custom
 commands.  The following settings add extra functionality for
 command-line use.

 Fast fingers are used to typing =emacs= at a prompt to open a file.
 This gives the same behavior in =eshell=.

 #+begin_src emacs-lisp
   (defun eshell/emacs (&rest args)
     "Open a file in emacs the natural way"
     (if (null args)
         ;; If emacs is called by itself, then just go to emacs directly
         (bury-buffer)
       ;; If opening multiple files with a directory name, e.g.
       ;; > emacs bar/bar.txt foo.txt
       ;; then the names must be expanded to complete file paths.
       ;; Otherwise, find-file will look in the current directory which
       ;; would fail for 'foo.txt' in the example above.
       (mapc #'find-file (mapcar #'expand-file-name (eshell-flatten-list (reverse args))))))
 #+end_src

 One can also keep the shell active and open files in the other
 window. (Mnemonic here is emacs other window)
 
 #+begin_src emacs-lisp
   (defun eshell/emo (&rest args)
     (mapc
      (lambda (f)
        (save-selected-window
          (find-file-other-window f)))
      (mapcar #'expand-file-name (eshell-flatten-list (reverse args)))))
 #+end_src

 On a windows box, setup grep to be a cygwin version.

 #+begin_src emacs-lisp
   (when (eq system-type 'windows-nt)
     (with-eval-after-load "eshell"
       (defun eshell/grep (&rest args)
         (eshell-grep "c:/cygwin/bin/grep.exe" args t))))
 #+end_src

 For Magit, there are some niceties to add.

 #+begin_src emacs-lisp
   (defun eshell/gst (&rest args)
     (magit-status-setup-buffer (pop args))
     (eshell/echo))

   (defun eshell/gd (&rest args)
     (magit-diff-unstaged)
     (eshell/echo))

   (defun eshell/gds (&rest args)
     (magit-diff-staged)
     (eshell/echo))
 #+end_src

**** Plan 9 Smart Shells

 See [[http://www.masteringemacs.org/article/complete-guide-mastering-eshell][the complete guide to mastering Eshell]] for more on this.
 Basically, the cursor stays on the command for editing if
 necessary.

 #+begin_src emacs-lisp
   (with-after-elpaca-init
     (with-eval-after-load 'eshell
       (require 'eshell)
       (require 'em-smart)

       (setq eshell-where-to-jump 'begin
             eshell-review-quick-commands nil
             eshell-smart-space-goes-to-end t)
       (add-hook  'eshell-mode-hook 'eshell-smart-initialize)))
 #+end_src

** Visual

This section contains settings and packages relevant to visual elements. The theming of emacs is in [[*Style][the style section]].

*** Nerd Icons

The set of [[https://github.com/rainstormstudio/nerd-icons.el][nerd icons]] depends on an installed compatible font, but
there are [[https://www.nerdfonts.com/font-downloads][many alternatives]]. Because it is font-based, this will
work graphically and in the terminal.

Be sure to run [[elisp:(nerd-icons-install-fonts)][nerd-icons-install-fonts]] for this to work well.

#+begin_src emacs-lisp
  (use-package nerd-icons
    :ensure t)
#+end_src

**** Icons in Corfu

 [[https://github.com/LuigiPiucco/nerd-icons-corfu?tab=readme-ov-file][This package]] adds icons to th [[*Corfu][Corfu]] completion list.
 
 #+begin_src emacs-lisp
   (use-package nerd-icons-corfu
     :after corfu
     :ensure t
     :config
     (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))
 #+end_src

**** Icons in dired

 Setup [[*Dired][dired]] to [[https://github.com/rainstormstudio/nerd-icons-dired][use icons]] next to the file names.

 #+begin_src emacs-lisp
   (use-package nerd-icons-dired
     :ensure t
     :hook
     (dired-mode . nerd-icons-dired-mode))
 #+end_src

**** Icons in Ibuffer

 Add [[https://github.com/seagle0128/nerd-icons-ibuffer][icons]] to [[*IBuffer][ibuffer]].

 #+begin_src emacs-lisp
   (use-package nerd-icons-ibuffer
     :ensure t
     :custom
     (nerd-icons-ibuffer-human-readable-size t)
     :hook (ibuffer-mode . nerd-icons-ibuffer-mode))
 #+end_src

**** Icons in completion

 [[https://github.com/rainstormstudio/nerd-icons-completion][Use icons]] in the completion systems.

 #+begin_src emacs-lisp
   (use-package nerd-icons-completion
     :ensure t
     :after marginalia
     :hook
     (marginalia-mode . nerd-icons-completion-marginalia-setup)
     :init
     (nerd-icons-completion-mode))
 #+end_src
  • Style

    The following sections describe items that affect the visual elements of Emacs.

** Frame Changes

These following items make Emacs really beautiful on every platform. I remove the menu bar, tool bar and the scroll bar for starters.

#+begin_src emacs-lisp :tangle "~/.emacs.d/early-init.el" :exports code :results silent ;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early. (push '(menu-bar-lines . 0) default-frame-alist) (push '(tool-bar-lines . 0) default-frame-alist) (push '(vertical-scroll-bars) default-frame-alist) #+end_src

** Window Changes

In the fringe area, I like to have markers to show me where the buffer begins/ends on the right. On the left, I have emacs show little dashes where empty lines exist.

In the title bar, I have it print the buffer name, full file name and size.

#+begin_src emacs-lisp (setq-default indicate-buffer-boundaries 'right) (setq-default indicate-empty-lines t) (setq-default frame-title-format '("%b %f %I")) #+end_src

** Faces

Emacs [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Faces.html][faces]] are text styled with attributes including font, slant, weight, color, etc. These sections go over the necessary settings to make them exactly right in all circumstances.

For configuration and debugging, [[help:list-faces-display][list-faces-display]] is useful.

*** Default Fonts

#+begin_src emacs-lisp
  (with-after-elpaca-init
    (when window-system
      (defun bnb/filter-existing-fonts (fl)
        "Filter the list for only existing fonts"
        (seq-filter #'font-info fl))
      (setq bnb/fontlist
            '("-*-LunarMono Nerd Font-regular-normal-condensed-*-*-*-*-*-p-0-iso10646-1"
              "LunarMono Nerd Font-12"
              "Fira Code-12"
              "Fira Code-13"
              "Source Code Pro-13"
              "Menlo-12"
              "Consolas-12")
            bnb/font-ring
            (ring-convert-sequence-to-ring (seq-filter #'font-info bnb/fontlist))
            bnb/font
            (ring-ref bnb/font-ring 0))
      (defun bnb/font-apply (font)
        "Change the default font to FONT."
        (set-frame-font (setq bnb/font font))
        (message "Set default font to %s" bnb/font))
      (defun bnb/font-next ()
        "Cycle the default font to the next in the ring."
        (interactive)
        (bnb/font-apply (ring-next bnb/font-ring bnb/font)))
      (defun bnb/font-prev ()
        "Cycle the default font to the previous in the ring."
        (interactive)
        (bnb/font-apply (ring-prev bnb/font-ring bnb/font)))
      (set-frame-font bnb/font)
      (bind-keys
       ("H-f" . bnb/font-next)
       ("H-F" . bnb/font-prev))))
#+end_src

*** Unicode :PENDING:

Support unicode fonts throughout the system. Be sure to [[https://github.com/rolandwalker/unicode-fonts][install
recommended fonts for support]].

#+begin_src emacs-lisp
  (use-package unicode-fonts
    :disabled t
    :ensure t
    :defer 10
    :init
    (unicode-fonts-setup))
#+end_src

*** Trying out fonts on Windows

On Windows, this function shows a font selection screen and sets
the default face. This will not persist between sessions, but is
great for test driving.

#+begin_src emacs-lisp
  (defun bnb/windows-set-font ()
    "Use Windows font selection to set the default font."
    (interactive)
    (set-face-attribute 'default nil :font (w32-select-font)))
#+end_src

*** Dynamic Font sizes

Changing font sizes in presentations is crucial to have at hand. I
use the following keybindings. =C--= overrides the negative argument
function, but that one is also accessible by =M--=.

#+begin_src emacs-lisp
  (defun bnb/change-frame-font-size (fn)
    "Change the frame font size according to function FN."
    (let* ((font-name (frame-parameter nil 'font))
           (decomposed-font-name (x-decompose-font-name font-name))
           (font-size (string-to-number (aref decomposed-font-name 5))))
      (aset decomposed-font-name 5 (int-to-string (funcall fn font-size)))
      (set-frame-font (x-compose-font-name decomposed-font-name))))

  (defun bnb/frame-text-scale-increase ()
    "Increase the frame font size by 1."
    (interactive)
    (bnb/change-frame-font-size '1+))

  (defun bnb/frame-text-scale-decrease ()
    "Decrease the frame font size by 1."
    (interactive)
    (bnb/change-frame-font-size '1-))

  (with-after-elpaca-init
    (bind-keys
     ("C-+" . text-scale-increase)
     ("C--" . text-scale-decrease)
     ("s--" . bnb/frame-text-scale-decrease)
     ("s-+" . bnb/frame-text-scale-increase)
     ("s-=" . bnb/frame-text-scale-increase)))
#+end_src

*** Mode Line Style

I dislike the box around the =mode-line= making it look like a
button. I disable (set to =nil=) the =box= face attribute to get a
flat feel. Be sure to do it to all =mode-line= faces that have this
attribute.

#+begin_src emacs-lisp
  (set-face-attribute 'mode-line nil :box nil)
  (set-face-attribute 'mode-line-inactive nil :box nil)
  (set-face-attribute 'mode-line-highlight nil :box nil)
#+end_src

*** Missing Glyphs

If I ever use a font with a missing glyph, this will let Emacs
check the /Symbola/ font for the missing data.

[[http://users.teilar.gr/~g1951d/][Download Symbola]] if you do not have it.

#+begin_src emacs-lisp
  (set-fontset-font "fontset-default" nil
                    (font-spec :size 20 :name "Symbola"))
#+end_src

*** Cursor width

Make the cursor the full width of the character at point.

#+begin_src emacs-lisp
  (setq x-stretch-cursor t)
#+end_src

** Themes

This function ensures that all enabled themes are shut down -- not just the most current one.

#+begin_src emacs-lisp (defun bnb/disable-all-themes () "Disable all enabled themes." (interactive) (mapc #'disable-theme custom-enabled-themes)) #+end_src

On creating themes: https://www.gnu.org/software/emacs/manual/html_node/emacs/Creating-Custom-Themes.html#Creating-Custom-Themes

*** Extra Themes

I like to have a few options for themes easily available. This set
respresents my favorite go-to combinations.

#+begin_src emacs-lisp
  (use-package minimal-theme :ensure t :defer t)
  (use-package gruvbox-theme :ensure t :defer t)
  (use-package material-theme :ensure t :defer t)
  (use-package tango-plus-theme :ensure t :defer t)
  (use-package color-theme-sanityinc-tomorrow :ensure t :defer t)
  ;; dichromacy
  ;; adwaita
#+end_src

** Sky Color Clock

[[https://github.com/zk-phi/sky-color-clock][This is a nice addition]] to any modeline. In a little block, it shows the date, time, moon phase

#+begin_src emacs-lisp (use-package sky-color-clock :ensure (sky-color-clock :host github :repo "zk-phi/sky-color-clock") :commands (sky-color-clock) :custom (sky-color-clock-enable-emoji-icon t) :config (sky-color-clock-initialize 40) (sky-color-clock-initialize-openweathermap-client bnb/openweathermap-api-key bnb/openweathermap-city-id)) #+end_src

The variables containging my city and API key are stored in [[*Local customizations (user-login-name)][local customizations]].

** Doom Modeline

Keeping with the goal of a clean and tidy Emacs, [[https://seagle0128.github.io/doom-modeline/][Doom modeline]] provides that fancy, fast, and minimal design.

I only customize the height to hug the font and keep everythig small.

#+begin_src emacs-lisp (use-package doom-modeline :ensure t :init (doom-modeline-mode t) :custom (doom-modeline-height 0)) #+end_src

** Asterism (โ‚) Mode :PENDING:

Let's try โ‚-mode for an interesting mini-buffer line. It writes information into the minibuffer. Here I have it set to show the output of [[*Sky Color Clock][sky color clock]].

#+begin_src emacs-lisp (use-package asterism-mode :after sky-color-clock :ensure (asterism-mode :host gitlab :repo "lunar.studio/asterism-mode") :init (defun bnb/smaller-sky-color () (let* ((scc (sky-color-clock)) (len (length scc))) (add-face-text-property 0 len '(:height 90) t scc) ;(add-face-text-property 0 len '(:justification right) t scc) scc)) :config (setq โ‚-format '((:eval (bnb/smaller-sky-color))))) #+end_src

** Prettify Symbols

Emacs can be so pretty sometimes. The modes that follow are great for [[https://www.modernemacs.com/post/prettify-mode/][mathematical notation in Emacs]].

The built-in [[help:prettify-symbols-mode][prettify-symbols-mode]] is easy to use. Check out what it does (and how it can be adjusted) in [[help:prettify-symbols-alist][prettify-symbols-alist]].

I have additional python settings to make it look sharp.

#+begin_src emacs-lisp
  (setq global-prettify-symbols-mode t
        prettify-symbols-unprettify-at-point 'right-edge)
#+end_src

Some resources for additional customization:
- http://endlessparentheses.com/using-prettify-symbols-in-clojure-and-elisp-without-breaking-indentation.html
- https://www.emacswiki.org/emacs/PrettySymbolsForLanguages

** Color

Having nice colors can help understand status, types, symbols, or even nesting.

*** Rainbow Mode

In order to see the colors /in the buffer/ this mode higlights
color words and definitions with their values.

#+begin_src emacs-lisp
  (use-package rainbow-mode
    :commands (rainbow-mode)
    :ensure t)
#+end_src

*** KureColor

Color helper KureColor allows easy modifications of hue,
saturation and brightness.

#+begin_src emacs-lisp
  (use-package kurecolor
    :bind (("H-k" . kurecolor-increase-hue-by-step)
           ("H-j" . kurecolor-decrease-hue-by-step)
           ("s-k" . kurecolor-increase-saturation-by-step)
           ("s-j" . kurecolor-decrease-saturation-by-step)
           ("s-l" . kurecolor-increase-brightness-by-step)
           ("s-h" . kurecolor-decrease-brightness-by-step))
    :ensure t)
#+end_src
  • Postamble

    These elements are at the end to keep all customizations tidy.

** Local customizations (custom.el)

I typically use the customize interface to generate any local
settings such as proxies, paths, fonts, etc. that may vary from
machine to machine.

#+begin_src emacs-lisp (setq custom-file "~/.emacs.d/custom.el") (load-file custom-file) #+end_src

** Local customizations (user-login-name)

I also intend to have a generic call to an installed local file that may need to behave differently from =custom.el=. This loads last so that it can modify any existing setting made here to work on the specific system in question.

In the code below, I add =~/.emacs.d/= to the load path and have a protected call to =load-library=. If the file exists, it gets loaded, otherwise the error normally returned if the file is non-existent gets ignored.

#+begin_src emacs-lisp (condition-case err (progn (load-file (format "~/.emacs.d/%s.el" user-login-name)) (message "Loaded local settings file %s.el" user-login-name)) (file-error (message "Skipping %s library as it does not exist." user-login-name)) nil) #+end_src

** Housekeeping

This message prints when Elpaca loading is complete

#+begin_src emacs-lisp (message "README EVALUATION DURATION: %3.2f seconds" (- (float-time) bnb/start-time)) (with-after-elpaca-init (message "ELPACA LOADING COMPLETE: %s" (emacs-init-time))) #+end_src

The local variables here setup a save hook (just in this buffer) that will create [[file:~/.emacs.d/full.el][full.el]] for loading.

I used to use Org to tangle on the fly during initialization, but this method supports a pre-tangling that speeds up initialization.

Local Variables:

eval: (add-hook 'after-save-hook (lambda () (org-babel-tangle nil "~/.emacs.d/full.el" "emacs-lisp")) 0 t)

End: