Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
7904 lines (6405 sloc) 278 KB

Literal Emacs Configuration

Emacs Configuration

This is my version of Joost Diepenmaat’s Org-Babel and a literate programming style emacs configuration. I forked his original Github repository on 1st November 2013.

On 2th July 2017 I adapted Holger Shurig’s tangling code that dramatically improves tangling speed. The org code block order of now corresponds directly to the code order in the generated el file.

Also, code blocks do not need to be named. You can disable tangling of any code by setting the org todo-state to PENDING that is one my custom values. A block can also be exempted from tangling code ‘:tangle no’.

How to use this configuration

Obtaining the source

You can find the latest public version of the configuration in my Github repository. The meat of it (and the source of this document) is the emacs.org file.

Package management

The lisp code uses use-package to configure and automatically install packages. The use-package package and some libraries are installed from within init.el. Code there also defines a global variable that does away the need to use :ensure t anywhere. The opposite can be true: There are cases when it is necessary to say :ensure nil to prevent loading of non-existing packages.

System dependencies are defined using use-package-ensure-system-package from waymondo.

For some reason, OSX is not detected, so I am setting brew manually.

(use-package use-package-ensure-system-package
  :init
  (setq system-packages-package-manager 'brew))

Installation

This configuration is installable from scratch. It uses Cask to specify the package dependencies. Pallet syncs the actual installed packages with the dependency spec.

Installation procedure

  • Install GNU Emacs 24 or higher
  • Install Cask from https://github.com/cask/cask
  • Clone the repository as $HOME/.emacs.d (or symlink it to that directory).
  • Run cask install in $HOME/.emacs.d
  • Make sure $HOME/.emacs.el does not exist
  • Start Emacs

Issues installing

  • Emacs failing to load pallet can indicate that cask is attempting to install packages using a different Emacs version than the one you’re starting. Check your $PATH and/or aliases.
  • Emacs should load this configuration without errors in a vanilla environment. Let me know it this is not the case.

Upgrading and installing emacs packages

You should be periodically upgrading your emacs packages. Some packages get almost daily fixes. It should be enough to update them once a month with M-x pallet-update. However, see Paradox updates below.

Every time you make major changes to this document (see [Editing this Document]) or upgrade your packages, you are strongly advised to note it down to a changelog file (see [ChangeLog mode]).

New packages are usually installed using command package-install that is given the package name as an argument. This automatically adds them to the Cask file for tracking.

A new version of this file is detected by emacs at start up. The file file:~/.emacs.d/init.el contains the code for using cask and converting this org file to the corresponding emacs listp file, file:~/.emacs.d/emacs.el. Conversion takes some time, but it is only done when the file has changed.

Sometimes you have to manually edit the cask file. It is at file:~/.emacs.d/Cask. There is a major mode for it.

(use-package cask-mode)

Paradox

The emacs module paradox adds package ratings to the listing, new shortcuts, and customization to package listings. Invoke by C-x l p (“Emacs, launch paradox”) to run paradox-list-packages. Press h to see all keys. Tip: v opens the package’s home page.

This is also a convenient place to update packages with U x. Paradox uses the async package to run updates at the background in parallel. You do not even have to call up the paradox window to upgrade packages if you run paradox-upgrade-packages.

You can give feedback if you set up the paradox-github-token variable to your github token. See the variable’s info (C-h v) for instructions.

Lastly, org-mode is now part of emacs and having to restart or reload org-mode after upgrade seems to be thing of the past.

(use-package paradox
  :defer nil
  :config
  (setq paradox-github-token t)
  (setq paradox-execute-asynchronously t)
  (setq paradox-automatically-star t))

Trying packages without installing

You can try out a package without changing you setup by using the try package. Use it instead of package-install: M-x try some-package.

(use-package try
  :defer t)

Editing this document

Use emacs and version >8 of org-mode for editing. To do that effectively, you need to understand how this documents works.

When emacs starts, code in $HOME/init.el loads first the prerequisites and then this org document. The code in the configuration section (see Chapter Configuration file layout) scans the code blocks and extracts (tangles in literate programming talk) them into the emacs.el file and evaluates it. The name and the order of blocks in this document determine the final order statements. Blocks without names are not tangled.

The text and its headers can be in any order that best helps understanding the structure. These elements are not read by emacs at all. The emacs lisp code that configures emacs is in emacs-lisp code blocks.

The best way to edit existing code blocks is to open a separate buffer for it by placing the cursor in it and pressing C-c '​. After editing, activate the code with M-x eval-buffer and exit the buffer with C-c '​.

If you want to get a better understanding what any lisp code below do, view it in a lisp buffer, place the cursor at the word, and press C-h f on a function or C-h v on a variable.

Environment

First we configure the environment emacs is running in for speed, custom file system hierarchy, and the operating system.

Hooks and modes

This section defines some functionality used elsewhere in this configuration.

(defun my/->string (str)
  (cond
   ((stringp str) str)
   ((symbolp str) (symbol-name str))))

(defun my/->mode-hook (name)
  "Turn mode name into hook symbol"
  (intern (replace-regexp-in-string "\\(-mode\\)?\\(-hook\\)?$"
                                    "-mode-hook"
                                    (my/->string name))))

(defun my/->mode (name)
  "Turn mode name into mode symbol"
  (intern (replace-regexp-in-string "\\(-mode\\)?$"
                                    "-mode"
                                    (my/->string name))))

(defun my/turn-on (&rest mode-list)
  "Turn on the given (minor) modes."
  (dolist (m mode-list)
    (funcall (my/->mode m) +1)))

(defvar my/normal-base-modes
  (mapcar 'my/->mode '(text prog))
  "The list of modes that are considered base modes for
  programming and text editing. In an ideal world, this should
  just be text-mode and prog-mode, however, some modes that
  should derive from prog-mode derive from fundamental-mode
  instead. They are added here.")

(defun my/normal-mode-hooks ()
  "Returns the mode-hooks for `my/normal-base-modes`"
  (mapcar 'my/->mode-hook my/normal-base-modes))

Lisp libraries

dash.el is a library of modern list functions.

(use-package dash
  :config
  (if (>= emacs-major-version 24)
      (use-package dash-functional)
    (message "Warning: dash-functional needs Emacs v24")))

Options set using the customize interface

By default, Emacs saves the options you set via the `customize-*` functions in the user init file, which is file:~/.emacs.d/init.el in this setup. I prefer to have these data in a separate file, custom.el that gets created if it does not exist. In this setup customizations are only collected to custom.el and you should later move and reorganize them to this main document.

(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(unless (file-exists-p custom-file)
  (write-region "" nil custom-file))
(load custom-file)

Keyboards

Let emacs react faster to keystrokes.

(setq echo-keystrokes 0.1)              ; default is 0.25
(setq idle-update-delay 0.35)           ; default is 0.5

Performance

Modern computers have considerable larger amounts of memory than a little while ago. I reduce garbage collection overhead by giving it more memory. Garbage is purged only when the cache is full.

According to this blog post setting threshold to 100MB is on the limits of noticibility. So my 20MB should be fine. The code below prevents garbage collection during the most interactive part of the emacs, the minibuffer.

(setq gc-cons-threshold 20000000)

(defun my-minibuffer-setup-hook ()
  (setq gc-cons-threshold most-positive-fixnum))

(defun my-minibuffer-exit-hook ()
  (setq gc-cons-threshold 20000000))

(add-hook 'minibuffer-setup-hook #'my-minibuffer-setup-hook)
(add-hook 'minibuffer-exit-hook #'my-minibuffer-exit-hook)

Custom lisp package directory

There are still lisp packages that you have to copy manually and import to emacs. This defines $HOME/.emacs.d/elisp directory as the place for them.

(add-to-list 'load-path
             (concat user-emacs-directory
                     (convert-standard-filename "elisp/")))

Helpful

A replacement for the Emacs **help** buffer.

(use-package helpful
  :bind (("C-h o" . helpful-at-point)
         ("C-h k" . helpful-key)))

Load secrets

I keep slightly more sensitive information in a separate file so that I can easily publish my main configuration.

It is kept in directory file:~/.emacs.p

(load "~/.emacs.p/secrets" t)

OS X

Key bindings

When I installed an emacs-plus from brew and OS X keybindings all changed. This code block restored the most important ones. It is disabled since I am back to standard emacs.

(when (eq system-type 'darwin)
  ;; Control keys
  ;; make cmd key do Meta
  (setq mac-command-modifier 'super)
  ;; make opt key do Super
  (setq mac-option-modifier 'meta)
  ;; make Fn key do Hyper
  (setq ns-function-modifier 'hyper)
  ;; make Control key do Control
  (setq mac-control-modifier 'control)

  ;; cut, copy paste, undo
  (cua-mode t) ;; make sure cua mode is active
  ;; paste
  (bind-key "s-v" 'cua-paste)
  ;; copy
  (bind-key "s-c" 'cua-copy-region)
  ;; cut
  (bind-key "s-x" 'kill-ring-save)
  ;; undo
  (bind-key "s-z" 'undo-tree-undo))  ; undo-tree installed elsewhere

Turns out hyper is not mapped to anything unless I follow this advice: A Hyper Key for the Mac | Irreal. Surprisingly, it still works at OS X system level as intended.

;; make Fn key do Hyper
(setq ns-function-modifier 'hyper)

PATH

OS X doesn’t set the environment from the shell init files for graphical applications, but I set PATH and a bunch of other stuff there. The exec-path-from-shell package will take care of that. Thanks to Ting-Yu Lin for pointing it out.

Although I have been using the fish shell for while, I was only recently bitten by a problem of loosing PATH. The fix comes from here. Unfortunatelly there are still issues.

No, fish as the default shell does not work. I am now using bash as the default shell and both tramp mode and magit pushing that were problem previously just work. I configured the terminal program to use fish as my interactive shell.

(when (eq system-type 'darwin)
  (use-package exec-path-from-shell
    :config
    (if (equal (file-name-nondirectory (getenv "SHELL")) "fish")
        (progn
          (setq path-separator " ")
          (exec-path-from-shell-initialize)
          (setq path-separator ":"))
      (exec-path-from-shell-initialize))))

locate

The locate command is not available in OS X so alias it to mdfind.

(when (eq system-type 'darwin)
  (setq locate-command "mdfind"))

Alerts

jwiegley/alert: A Growl-like alerts notifier for Emacs

When on OS X, use system notification, otherwise use the default Emacs message facility.

(use-package alert
  :init
  (when (eq system-type 'darwin)
    (setq alert-default-style 'osx-notifier)))

dired

The emacs dired uses the output from the ls command that is somewhat limited in the BSD version in OS X. Install GNU programs with homebrew and point dired to gls.

Also, I prefer human readable file sizes.

The dired-narrow is bound the / key for a handy filter function that can be cancelled with g.

The peep-dired is bound to P to open a(n image) file while in dired.

The dired-ranger makes it easy to copy (W) files and then copy (Y) or move (X) them to a new directory.

See Ediff section to see code that binds calling of ediff on two selected files.

Speedy sorting in dired with dired-quick-sort | Pragmatic Emacs. Hit S to see a handy hydra menu for sorting. Pressing s is standard key binding to toggle between the default alphabetical and time based sorting.

Automatically revert dired when files change.

EmacsWiki: Dired Details instructs installing dired-details+ tha hides all the details and binds bracket keys ( and ) to toggling the display.

Tree-style directory views in dired with dired-subtree | Pragmatic Emacs

(when (eq system-type 'darwin)
  (setq insert-directory-program (executable-find "gls")))

(use-package dired
  :ensure nil
  :ensure-system-package coreutils
  :hook auto-revert    ; auto refresh dired when file changes
  :config
  (setq dired-listing-switches "-alh")

  ;; single prompt for deletion
  (setq dired-recursive-deletes 'always)

  (use-package dired-details+
    :init
    (setq dired-details-hidden-string ""))

  (use-package dired-narrow
    :defer t
    :bind (:map dired-mode-map ("/" . dired-narrow)))

  ;;preview files in dired
  (use-package peep-dired
    :defer t ; don't access `dired-mode-map' until `peep-dired' is loaded
    :bind (:map dired-mode-map
                ("P" . peep-dired)
                ;;("e" . (eshell t))
                )
    :config
    (setq peep-dired-cleanup-on-disable t))

  (use-package dired-ranger
    :bind (:map dired-mode-map
                ("W" . dired-ranger-copy)
                ("X" . dired-ranger-move)
                ("Y" . dired-ranger-paste)))

  (use-package dired-quick-sort
    :config
    (dired-quick-sort-setup))

  (use-package dired-subtree
    :config
    (bind-keys :map dired-mode-map
               ("i" . dired-subtree-insert)
               (";" . dired-subtree-remove))))

Printing

Printing under OS X does not work in default emacs. EmacsWiki has slightly outdated instructions:

  1. Copy mac-print-mode.el into file:~/.emacs.d/elisp directory
  2. htmlize package should be already installed
  3. Install latest version of Coral (1.3)
    • Download and open the image file
    • cp -r /Volumes/Coral1.3/bin/coral.app /Applications/
    • cp /Volumes/Coral1.3/bin/coral /usr/local/bin/ and edit it so that it calls /Applications/coral.app/Contents/MacOS/coral
  4. Run the following code:
    ;;(use-package mac-print-mode
    ;;  :disabled t
    ;;  :if (eq system-type 'darwin)
    ;;  :bind ("s-p" . mac-print-buffer)
    ;;  :config
    ;;  (mac-print-mode 1))
    
    ;; (require 'mac-print-mode)
    ;; (bind-key "s-p" 'mac-print-buffer)
    ;; (mac-print-mode 1)
    ;; (when (require 'mac-print-mode nil t)
    ;; (mac-print-mode 1)
    ;; (global-set-key (kbd "M-p") #'mac-print-buffer))
    
        

    Command-p now exports the current page as HTML and prints using the system dialog.

URL copying

The package org-mac-link grabs links from open applications and pastes them to current org-buffer. Great for org capture notes C-c c n=. Type the note title, move the cursor to the body, and press C-x l l “Emacs, launch link”. I only use chrome, so I ignore other apps and use directly the chrome link through command org-mac-chrome-insert-frontmost-url=.

I’ve combined all those commands and bound them to C-c v.

(when (eq system-type 'darwin)
  (use-package org-mac-link
    :ensure nil
    :after org
    :config
    (defun my/quick-url-note ()
      "Fastest way to capture a web page link"
      (interactive)
      (org-capture nil "n")
      (org-mac-chrome-insert-frontmost-url)
      (org-capture-finalize))
    (bind-key "C-c v" 'my/quick-url-note)))

iTerm2

Applescript tools to change focus to iTerm2 application. from here.

(when (eq system-type 'darwin)
  (defun iterm-goto-filedir-or-home ()
    "Go to present working dir and focus iterm"
    (interactive)
    (do-applescript
     (concat
      " tell application \"iTerm\"\n"
      "   tell the current session of current window\n"
      (format "     write text \"cd %s\" \n"
              ;; string escaping madness for applescript
              (replace-regexp-in-string
               "\\\\" "\\\\\\\\"
               (shell-quote-argument (or default-directory "~"))))
      "   end tell\n"
      " end tell\n"
      " do shell script \"open -a iTerm\"\n")))

  (defun iterm-focus ()
    (interactive)
    (do-applescript
     " tell application \"iTerm\" to activate\n"))

  (bind-key "s-t" 'iterm-goto-filedir-or-home)
  (bind-key "s-T" 'iterm-focus))

Emacsclient

In OS X command line and GUI versions of emacs are not the same thing and opening a file in a running GUI program is not automatic. In the case of emacs, the way around this is emacsclient (see man emacsclient). The emacs needs to run in server mode for the emacsclient to open a new frame to edit the file. Only one instance of the server can run, so it is best that only the GUI emacs launches it.

Edit-server is the emacs code for the Chrome/Chromium extension for editing text areas in a better environment.

(when (display-graphic-p)
  (server-start))

(use-package edit-server
  :defer t
  :if window-system
  :init
  (add-hook 'after-init-hook 'edit-server-start t)
  :config
  (use-package edit-server-htmlize
    :config
    ;; gmail fix
    (autoload 'edit-server-maybe-dehtmlize-buffer
      "edit-server-htmlize" "edit-server-htmlize" t)
    (autoload 'edit-server-maybe-htmlize-buffer
      "edit-server-htmlize" "edit-server-htmlize" t))
  (add-hook 'edit-server-start-hook 'edit-server-maybe-dehtmlize-buffer)
  (add-hook 'edit-server-done-hook  'edit-server-maybe-htmlize-buffer))

A commandline alias em (alias em=emacsclient) then calls emacsclient instead of emacs on the terminal. This will open a new emacs frame with the text to edit. To finish editing, save and press C-x # or C-x C-3. This works beautifully with fish shell command funced.

(bind-key "C-x C-3" 'server-edit)

Graphics and looks

Font

The new OS X standard front, Menlo, is amazingly good to eye. It is almost the same as DejaVu Sans Mono. I have suspended the use of Inconsolata (Download) while keeping Symbola (Download) as a Unicode backup (see EndlessParentheses).

I am trying out the new Hack 2.0 font.

;;(set-face-attribute 'default nil
;;                    :family "Inconsolata"
;;                    :height 140
;;                    :weight 'normal
;;                    :width 'normal)
;;     (set-fontset-font "fontset-default" nil
;;                       (font-spec :size 20 :name "Symbola:"))
(when (eq system-type 'darwin)
  (set-face-attribute 'default nil :family "Hack" :height 120))
  ;; (set-frame-font "-*-Hack-normal-normal-normal-*-13-*-*-*-m-0-iso10646-1")
  ;; (set-fontset-font "fontset-default" nil
  ;;                     (font-spec :size 20 :name "Noto Emoji"))

You can use C-x C-+ and C-x C-- (‘text-scale-adjust’) to increase or decrease the buffer text size in the current buffer (+ or - to repeat). To restore the default (global) face height, type C-x C-0. (From EmacsWiki)

The best way to get information about cursor location is to run what-cursor-position with prefix argument: C-u C-x =. It will open a Help window and show information about character, encoding, fonts and highlights. Also, see M-x what-face.

Emojis

Since 2016, there is political decision not to show color fonts under OS X, although it would be possible, simply because free ISS are not able to! Emojis, when displayed, are show as mono-color icons.

There is a workaround in the emojify package that renders emojis as PNG images when the emojify-mode is turned on.

(use-package emojify)

Unicode

  • Xah Lee’s Unicode page for easy copy and paste.
  • Draw Unicode characters online.
  • Enter Unicode characters in hexadecimal or named: C-x 8<Enter>.
    (defun my/insert-unicode (unicode-name)
      "Same as C-x 8 enter UNICODE-NAME."
      (insert (string (gethash unicode-name (ucs-names)))))
    
        (bind-key "C-x 9" 'hydra-unicode/body)
        (defhydra hydra-unicode (:hint nil)
          "
         Unicode  _e_ €  _s_ 0 w SPACE   _2_ ²   _n_amed select
                  _f_ ♀  _o_ °   _m_ µ   _3_ ³
                  _r_ ♂  _a_ →           _t_ ₂
                "
          ("e" (my/insert-unicode "EURO SIGN"))
          ("r" (my/insert-unicode "MALE SIGN"))
          ("f" (my/insert-unicode "FEMALE SIGN"))
          ("s" (my/insert-unicode "ZERO WIDTH SPACE"))
          ("o" (my/insert-unicode "DEGREE SIGN"))
          ("a" (my/insert-unicode "RIGHTWARDS ARROW"))
          ("m" (my/insert-unicode "MICRO SIGN"))
          ("2" (my/insert-unicode "SUPERSCRIPT TWO"))
          ("3" (my/insert-unicode "SUPERSCRIPT THREE"))
          ("t" (my/insert-unicode "SUBSCRIPT TWO"))
          ("n" counsel-unicode-char))
        

    Note: For most plain text writing I use Org mode that has a very useful binding for org-self-insert-command that allows combining mnemonic keys to make accented characters. For example, C-x 8 ' i inserts character í, and C-x 8 " a, character ä.

Reduce clutter

Remove the toolbar. It’s ugly and I never use it. Scroll bars in emacs frame are useless. Remove.

(when (display-graphic-p)
  ;;(menu-bar-mode -1)
  (tool-bar-mode -1)
  (scroll-bar-mode -1))

Disable dialog boxes

Even mouse commands use echo area to ask confirmations

(setq use-dialog-box nil)

Symbols

Show written out symbols as they should be. This is available only in emacs 24.4 and above. The replacements are in variable prettify-symbols-alist. Currently it displays “lambda” as “λ” in lisp code and hundreds of symbols in LaTeX mode.

For more, check out the documentation on prettify-symbols-mode using

  • the new (for 25.1) key binding C-h o.
    (global-prettify-symbols-mode 1)
    (setq prettify-symbols-unprettify-at-point 'right-edge)
        

Fringe decorations

The fringe is the vertical region at the right and left of the buffer. Emacs lets you customize it of course.

Here I set up git differences and buffer boundaries in the left fringe.

(when (display-graphic-p)
  (use-package git-gutter-fringe
    :defer t
    :diminish (git-gutter-mode . "")
    :init
    (global-git-gutter-mode +1)
    (setq-default indicate-buffer-boundaries 'left)
    (setq-default indicate-empty-lines +1)))

Mode line

The default emacs mode line is confusing and boring. This setup makes it clear and easy to eye. Some might argue that the amount of code used is excessive for such a small feature, but since I was able to copy, paste and modify, why not.

Futher, package diminish makes it easy to remove or change any minor mode indicators on the mode line. The code using diminish is placed where the corresponding minor mode is set up.

I tried package smart-mode-line but gave up configuring it. I could not make it look the way I wanted.

(setq-default mode-line-format
              '(;; Position, including warning for 80 columns
                (:propertize " %6l:" face mode-line-position-face)
                (:eval (propertize "%3c" 'face
                                   (if (>= (current-column) 80)
                                       'mode-line-80col-face
                                     'mode-line-position-face)))
                ;; emacsclient [default -- keep?]
                mode-line-client
                " "
                ;; read-only or modified status
                (:eval
                 (cond (buffer-read-only
                        (propertize " RO " 'face 'mode-line-read-only-face))
                       ((buffer-modified-p)
                        (propertize " ** " 'face 'mode-line-modified-face))
                       (t "    ")))
                " "
                ;; directory and buffer/file name
                (:propertize (:eval (shorten-directory default-directory 30))
                             face mode-line-folder-face)
                (:propertize "%b"
                             face mode-line-filename-face)
                ;; narrow [default -- keep?]
                " %n "

                ;; mode indicators:
                ;; vc, recursive edit, major mode, minor modes, process, global
                (vc-mode vc-mode)
                "  %["
                (:propertize mode-name
                             face mode-line-mode-face)
                "%] "
                (:eval (propertize (format-mode-line minor-mode-alist)
                                   'face 'mode-line-minor-mode-face))
                " "
                (:propertize mode-line-process
                             face mode-line-process-face)
                (global-mode-string global-mode-string)

                ))

;; Helper function
(defun shorten-directory (dir max-length)
  "Show up to `max-length' characters of a directory name `dir'."
  (let ((path (reverse (split-string (abbreviate-file-name dir) "/")))
        (output ""))
    (when (and path (equal "" (car path)))
      (setq path (cdr path)))
    (while (and path (< (length output) (- max-length 4)))
      (setq output (concat (car path) "/" output))
      (setq path (cdr path)))
    (when path
      (setq output (concat ".../" output)))
    output))

;; Extra mode line faces
(make-face 'mode-line-read-only-face)
(make-face 'mode-line-modified-face)
(make-face 'mode-line-folder-face)
(make-face 'mode-line-filename-face)
(make-face 'mode-line-position-face)
(make-face 'mode-line-mode-face)
(make-face 'mode-line-minor-mode-face)
(make-face 'mode-line-process-face)
(make-face 'mode-line-80col-face)


(set-face-attribute 'mode-line nil
                    :foreground "gray60" :background "gray20"
                    :inverse-video nil
                    :box '(:line-width 6 :color "gray20" :style nil))
(set-face-attribute 'mode-line-inactive nil
                    :foreground "gray80" :background "gray40"
                    :inverse-video nil
                    :box '(:line-width 6 :color "gray40" :style nil))
(set-face-attribute 'mode-line-read-only-face nil
                    :inherit 'mode-line-face
                    :foreground "grey80"
                    :box '(:line-width 2 :color "#4271ae"))
(set-face-attribute 'mode-line-modified-face nil
                    :inherit 'mode-line-face
                    :foreground "#c82829"
                    :background "#ffffff"
                    :box '(:line-width 2 :color "#c82829"))
(set-face-attribute 'mode-line-folder-face nil
                    :inherit 'mode-line-face
                    :foreground "gray60")
(set-face-attribute 'mode-line-filename-face nil
                    :inherit 'mode-line-face
                    :foreground "#eab700"
                    :weight 'bold)
(set-face-attribute 'mode-line-position-face nil
                    :inherit 'mode-line-face
                    :height 130)
(set-face-attribute 'mode-line-mode-face nil
                    :inherit 'mode-line-face
                    :foreground "gray80")
(set-face-attribute 'mode-line-minor-mode-face nil
                    :inherit 'mode-line-mode-face
                    :foreground "gray60"
                    :height 100)
(set-face-attribute 'mode-line-process-face nil
                    :inherit 'mode-line-face
                    :foreground "grey80")
(set-face-attribute 'mode-line-80col-face nil
                    :inherit 'mode-line-position-face
                    :foreground "black" :background "#eab700")

Feebleline

Removing the mode-line and using echo-area (smartly) instead.🔊Minimalistic mode line replacement.

  (use-package feebleline
    :load-path "elisp/" ; elisp dir under ~/.emacs.d
:init
(setq feebleline-mode-line-text
  '(
    ("%s"  ((string-to-number (format-mode-line "%l"))) (face feebleline-linum-face))
    ("%s"   (":" ) (face default))
    ("%s " ((current-column)) (face feebleline-linum-face))
    ("%s"   ("") (face default))
    ("%s "   ((if (buffer-modified-p) "**" "" )) (face feebleline-asterisk-face))
    ("%s"   ((if buffer-read-only "RO " ""  )) (face feebleline-asterisk-face))
    ("%s "   ((buffer-file-name)) (face feebleline-filename-face))
    ("%s"   ("") (face default))
    (" %s "   ((if mode-name mode-name)) (face feebleline-time-face))
    ("%s"   ("") (face default))
    ))
    :config
    (set-face-attribute 'feebleline-filename-face nil
                        :foreground "black" :weight 'bold)
    (set-face-attribute 'feebleline-asterisk-face nil
                        :foreground "salmon" :background "white")
    (set-face-attribute 'feebleline-time-face nil
                        :foreground "grey50" :background "white")
    (feebleline-default-settings))

Visual bell

Getting boings from emacs when you scroll to the end of the buffer is annoying. Turning that noise into visual clue is much better. The following code blinks the message area before displaying the error message.

The mode-line-bell-string is not displayed which is disappointing.

;; nice little alternative visual bell; Miles Bader <miles /at/ gnu.org>
(defcustom echo-area-bell-string "♪ ♪ ♪"
  "Message displayed in echo area by `echo-area-bell' function."
  :group 'user)

(defcustom echo-area-bell-delay 0.1
  "Number of seconds `echo-area-bell' displays its message."
  :group 'user)

;; internal variables
(defvar echo-area-bell-cached-string nil)
(defvar echo-area-bell-propertized-string nil)

(defun echo-area-bell ()
  "Briefly display a highlighted message in the echo-area.
    The string displayed is the value of `echo-area-bell-string',
    with a red background; the background highlighting extends to the
    right margin.  The string is displayed for `echo-area-bell-delay'
    seconds.
    This function is intended to be used as a value of `ring-bell-function'."
  (unless (equal echo-area-bell-string echo-area-bell-cached-string)
    (setq echo-area-bell-propertized-string
          (propertize
           (concat
            (propertize
             "*DING* "
             'display
             `(space :align-to (- right ,(+ 2 (length echo-area-bell-string)))))
            echo-area-bell-string)
           'face '(:background "red")))
    (setq echo-area-bell-cached-string echo-area-bell-string))
  (message echo-area-bell-propertized-string)
  (sit-for echo-area-bell-delay)
  (message ""))

(setq ring-bell-function 'echo-area-bell)

Frame title

More useful frame title, that shows either a file or a buffer name (if the buffer isn’t visiting a file).

(setq frame-title-format
      '((:eval (if (buffer-file-name)
                   (abbreviate-file-name (buffer-file-name))
                 "%b"))))

Windows

Scrolling behavior

Emacs’s default scrolling behavior, like a lot of the default Emacs experience, is pretty idiosyncratic. The following snippet makes for a smoother scrolling behavior when using keyboard navigation.

(setq scroll-margin 1
      scroll-step 1
      scroll-conservatively 10000
      scroll-preserve-screen-position 1)

This snippet makes mouse wheel and trackpad scrolling bearable. Scroll in 1-line increments the buffer under the mouse.

(setq mouse-wheel-follow-mouse 't)
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1)))

The other aspect of scrolling is centering. C-l is bound to command recenter-top-bottom that places the current line vertically in the center of the page. A less known feature of it is that you cycle the placement between middle, top, and bottom. This can be reordered and I’ve followed the suggestion to place the current line first to the top of the frame.

When recentering, the default margin is one line. Increasing that to three, shows a little more context around the cursor line.

(setq recenter-positions '(top middle bottom))
(setq scroll-margin 3)

Scroll other window

Often you are working in one window and reading instructions from an other window. This defines key bindings to scroll this and the other window using M-s-<arrow>.

(bind-key "M-s-<up>" 'scroll-down)
(bind-key "M-s-<down>" 'scroll-up)
(bind-key "M-s-<right>" 'scroll-other-window)
(bind-key "M-s-<left>" #'(lambda () (interactive) (scroll-other-window '-)))

The default keybindings are complex or do not work under OS X and a laptop keyboard. Correction: C-M-v and C-M-V do work for scrolling the other window!

Help window focus

Jump to the help window when it’s opened. Press q to close it and restore the view to the previous buffer.

(setq help-window-select t)

Automatic windows splitting preference

While emacs tends to do automatic splitting of the frame horizontally, I prefer it to happen vertically. See Stack Overflow for discussion.

(setq split-height-threshold nil
      split-width-threshold 0)

Cursor

The cursor shows the location between characters.

(modify-all-frames-parameters (list (cons 'cursor-type 'bar)))
(setq blink-cursor-mode nil)
;; show tab length
(setq-default x-stretch-cursor t)
;; Set cursor color to white
;; (set-cursor-color "#ffffff")

Stop cursor going into minibuffer prompt

;; don't let the cursor go into minibuffer prompt
(setq minibuffer-prompt-properties
      (quote (read-only t point-entered minibuffer-avoid-prompt
                        face minibuffer-prompt)))

The beacon package flashes colored light to the cursor when it changes place and window scrolls.

(use-package beacon
  :diminish ""
  :config
  (setq beacon-color "firebrick")
  (setq beacon-size 20)         ; smaller than default 40
  (setq beacon-blink-delay 0.1) ; faster than default 0.3 ms
  (setq beacon-blink-when-focused t)
  (beacon-mode 1))

Current line

Current line is subtly highlighted in pale blue.

(when (display-graphic-p)
  (global-hl-line-mode 1)
  ;;(set-face-background hl-line-face "Grey20")
  (set-face-background hl-line-face "LightCyan"))

Global key bindings

As far as reasonable, I try to keep my custom key bindings within the “official” restraints. Specifically, I want my global key bindings to start with C-c [lower case letter]. Implementations are in appropriate sections below.

Themes

I find the emacs default white background the best. I’ve installed bbatsov’s solarized-emacs theme since I read that it has a good org mode support. Paper theme an other one geared for org mode users.

;; (use-package solarized-theme
;;   :defer t
;;   :init (setq solarized-scale-org-headlines nil))
;; (use-package paper-theme
;;   :defer t
;;   :init (setq paper-tint-factor 85))
;; (use-package danneskjold-theme
;;   :defer t)

You are supposed to invoke themes with M-x load-theme. Strangely, loading a theme does not disable the previous one. You have to manually disable them all one by one using disable-theme. My own function theme first disables existing ones and then interactively calls load-theme.

TODO: Write a function that loads a theme but first disables all active themes.

(defun theme (uarg)
  "Disable all active themes and then load one interactively.

Use default theme if universal argument UARG is given."
  (interactive "p")
  (dolist (i custom-enabled-themes)
    (disable-theme i))
  (if (/= uarg 4)
      (call-interactively 'load-theme)))

Mouse

Mouse and trackpad are best inactivated when inside an emacs window. Note that the OS menu system is still working normally. Also, it is possible to click on and follow links.

Just in case I need mouse at some point, I’ve added the global-disable-mouse-mode to my universal toggle hydra: C-x t m. Indeed, I now need an active mouse pointer for PDF annotations.

When active, mouse-wheel acts on the hovered window rather than the one where the typing focus is.

(use-package disable-mouse
  :defer t
  :diminish global-disable-mouse-mode
  :init (global-disable-mouse-mode))

(setq mouse-wheel-follow-mouse t)

Rainbow-mode

Rainbow-mode sets the background of any color name in a buffer. Turn it on in CSS buffers but elsewhere is can toggled on with C-x t u. Note that it interferes with my current line highlighting. See Current line.

(use-package rainbow-delimiters)

(use-package rainbow-mode
  :defer t
  :diminish ""
  :hook css-mode)

Start-up

Start with the scratch buffer; no start-up screen. Restore previous window and file setup including window placement. Restore cursor position and minibuffer history.

Direct custom modifications to be ignored in emacs v. 25.1 (How do I get emacs to stop adding “Custom” fields to the end of my .emacs file? : emacs).

(setq inhibit-startup-screen +1
      inhibit-startup-message t
      initial-scratch-message nil)

;; emacs 24.4 feature, call on main windowed emacs
(when (display-graphic-p)
  (desktop-save-mode t))

;; save cursor position
;; remember cursor position, for emacs 25.1 or later
(save-place-mode 1)

;; ignore custom modifications
(setq custom-file "/tmp/null")

;; Save minibuffer history
;;(savehist-mode)

Encryption

While emacs knows how to decrypt encrypted files on the fly, the supporting programmes need to be installed. This solves the recent problem I was having, Emacs 25 EasyPG Issue:

GnuPGP need to be upgraded to v.2.1 that is not backward compatible:

brew unlink gnupg2 gpg-agent dirmngr
brew uninstall gnupg2 gpg-agent dirmngr
brew install gnupg21
killall gpg-agent
gpg-agent --daemon
ln -s /usr/local/bin/gpg2 /usr/local/bin/gpg

Tell emacs not to use any external programs for entering the passphrase.

(setf epa-pinentry-mode 'loopback)

Identify yourself

Many emacs modes produce output that includes user’s name and email address. Set your full name (using plain ASCII to guard against conflicts with old modes).

You can tell emacs your preferred email address by hard coding it. An alternative is to add it to your global shell environment (you are using *NIX operating system, aren’t you?) where emacs will pick it up (from file:~/.zshenv or file:~/.bash_profile):

export EMAIL=heikki.lehvaslaiho@gmail.com"
(setq user-full-name "Heikki Lehväslaiho")
(setq user-mail-address "heikki.lehvaslaiho@gmail.com")

Backups

Default emacs behaviour is to clutter document directories with its backup files. The following creates numbered backups, limits the number of backups kept, and directs them all into $HOME/.emacs.d/backups/ directory.

Lockfiles with names prefixed with “.#” are an other type of Emacs clutter. I am not afraid of double editing, so I disable that.

  (setq my/backup-dir "~/.emacs.d/backups/")
  (setq backup-directory-alist '((".*" . "~/.emacs.d/backups/")))

  (setq delete-by-moving-to-trash t
        trash-directory "~/.Trash/emacs")

  (setq make-backup-files t      ; backup of a file the first time it is saved.
        backup-by-copying t      ; don't clobber symlinks
        version-control t        ; version numbers for backup files
        delete-old-versions t    ; delete excess backup files silently
        kept-old-versions 6      ; oldest versions to keep when a new numbered backup is made (default: 2)
        kept-new-versions 20     ; newest versions to keep when a new numbered backup is made (default: 2)
        auto-save-default t      ; auto-save every buffer that visits a file
        auto-save-timeout 20     ; number of seconds idle time before auto-save (default: 30)
        auto-save-interval 200   ; number of keystrokes between auto-saves (default: 300)
        )

(use-package savehist
  :ensure nil ; built-in
  :config
  (setq savehist-additional-variables
        ;; search entries
        '(search-ring regexp-search-ring)
        ;; save every minute
        savehist-autosave-interval 60
        ;; keep the home clean
        savehist-file (expand-file-name "savehist" my/backup-dir))
  (savehist-mode +1))

;; disable lockfiles
(setq create-lockfiles nil)

Confirmations and exiting emacs

Set short y/n abbreviations for all confirmations and ask for confirmation before quiting emacs.

;; don’t open files from the workspace in a new frame
(setq ns-pop-up-frames nil)

(fset 'yes-or-no-p 'y-or-n-p)
(setq confirm-kill-emacs 'y-or-n-p)

Emacs pops up an annoying buffer when big chunks of text get replaced overflowing the undo buffer. Prevent that.

Emacs can crash if it tries to open a too large file. If it detects a one, it will ask: “file foo is large (12MB); really open?”. My elfeed index is regularly over the default 10MB, so lets increase the limit to 100 MB. Modern computers can easily handle that.

(setq warning-suppress-types (quote ((undo discard-info))))
(setq large-file-warning-threshold 100000000)

Prevent annoying “Active processes exist” query when you quit Emacs. From Programming: Seven specialty Emacs settings with big payoffs

(defadvice save-buffers-kill-emacs (around no-query-kill-emacs activate)
  (cl-flet ((process-list ())) ad-do-it))

The restart-emacs package makes it possible not only to quit emacs (C-x C-c) but restart it from within emacs with function restart-emacs.

(use-package restart-emacs)

Use prefix arguments to modify:

C-uEmacs flag
count
1–debug-init
2-Q
3<prompt>

Key bindings

Redefining default keys

what-cursor-position is bound to C-x = and shows position and character information in echo space. I reuse the binding to describe-char that has more detailed output to separate buffer.

(bind-key* "C-x =" 'describe-char)

Free default bindings

Numerical arguments to commands are passed with C-3, M-3, C-M-3 for all digits 0-9. Free single modifier key bindings for other uses in the future (Use your digits and a personal key map for super shortcuts | Pragmatic Emacs)

;; unset C- and M- digit keys
(dotimes (n 10)
  (global-unset-key (kbd (format "C-%d" n)))
  (global-unset-key (kbd (format "M-%d" n))))

PENDING Show bindings

Emacs commands are defined by their names. Many interactive commands have default keybindings but they are supposed to be modified by the user. which-key is a package that shows currently available key bindings interactively after a delay of 1 second.

My settings use a large separate frame to show the key bindings. If keys exceed available space, C-h scrolls the list.

(use-package which-key
  :diminish ""
  :defer t
  :init
  (which-key-mode))
  ;;(setq which-key-popup-type 'frame)
  ;;(setq which-key-frame-max-width 160)  ; number of columns
  ;;(setq which-key-frame-max-height 40)) ; number of lines

I used to maintain a table of C-c bindings but which-key made it obsolete.

Mnemonic key bindings with hydra

The Endless Parentheses blog shows how to set up mnemonic keymaps. You just do the incantation “Emacs, toggle narrowing” by pressing C-x t n!

This is now done even better with hydra, a package to create sticky key bindings with help displayed in the echo area.

Using bind-key function adds the key bindings to a list that can be shown with M-x describe-personal-keybindings.

(defun toggle-overwrite-mode ()
  (interactive)
  (if (bound-and-true-p overwrite-mode)
      (overwrite-mode -1) (overwrite-mode)))

(bind-key "C-x t" 'hydra-toggle/body)
(defhydra hydra-toggle (:color blue :hint nil)
  "
           toggle _a_bbrev-mode          _h_tml preview for org   _o_rg link display     neo_t_ree
                  _c_: word-count mode   _i_edit                  _p_retty entities      _v_: string inflection
                  _d_ebug-on-error       _k_: spelling language   _b_: overwrite mode    _w_ritegood-mode
                  _e_ros                 _l_ine numbers           t_r_uncate-lines       _q_uit
                  _f_olding              _n_arrowing              _m_ouse                white_s_pace-mode
                  _g_roup digits         ^ ^                      _u_: rainbow mode
                "
  ("a" abbrev-mode)
  ("b" toggle-overwrite-mode)
  ("d" toggle-debug-on-error)
  ("c" wc-mode)
  ("e" eros-mode)
  ("f" toggle-selective-display)
  ("g" digit-groups-mode)
  ("h" org-preview-html-mode)
  ("i" iedit-mode)
  ("n" narrow-or-widen-dwim)
  ("m" global-disable-mouse-mode)
  ("k" cycle-ispell-languages :color red)
  ("l" display-line-numbers-mode)
  ("o" org-toggle-link-display)
  ("p" org-toggle-pretty-entities)
  ("r" toggle-truncate-lines)
  ("s" whitespace-mode)
  ("t" neotree-toggle)
  ("u" rainbow-mode)
  ("v" string-inflection-toggle :color red)
  ("w" writegood-mode)
  ("q" nil))

;; http://oremacs.com/2015/03/15/search-with-apropos/
(bind-key "C-c h" 'hydra-apropos/body)
(defhydra hydra-apropos (:color blue :hint nil)
  "
        apropos   _a_propos        _c_ommand
                  _d_ocumentation  _l_ibrary
                  _v_ariable       _u_ser-option
                  ^ ^              _e_: value"
  ("a" apropos)
  ("d" apropos-documentation)
  ("v" apropos-variable)
  ("c" apropos-command)
  ("l" apropos-library)
  ("u" apropos-user-option)
  ("e" apropos-value))

The second key map is for launching standalone features. This is like casting a spell “Emacs, launch shell”, C-x l s. The hydra implementing this is self-documenting.

(bind-key "C-x l" 'hydra-launch/body)
(defhydra hydra-launch (:color blue :hint nil :idle 1.0)
  "
launch _2_048            _l_ink chrome       _s_ynonyms            _w_3m at point
       _b_: gscholar-bib _k_eybindings       _p_ass                G_\+_ emacs
       _c_: calfw        _n_ato-region       _P_aradox             _?_: emacsExchange
       _e_diff-buffers   de_N_ato            _q_: paradox upgrade  _=_: quick-calc
       _f_ilename2clipb  _m_y/move-file-here _t_imemachine git     _0_: repeat elisp
       _h_owdoi          _r_e-builder        _u_: us2fi chars
       tw_i_tter         ^ ^                 _z_: timezones        _x_: eshell
       _j_: org entities ^ ^                 _y_: binclock
      "

  ("2" 2048-game)
  ("b" gscholar-bibtex)
  ("c" my/calendar)
  ("e" ediff-buffers)
  ("f" copy-file-name-to-clipboard)
  ("g" langtool-correct-buffer)
  ("h" howdoi-query)
  ("i" twit)
  ("j" ivy-insert-org-entity)
  ("k" describe-personal-keybindings)
  ("l" org-mac-chrome-insert-frontmost-url)
  ("m" my/move-file-here)
  ("n" nato-region)
  ("N" denato-region)
  ("p" pass)
  ("P" paradox-list-packages)
  ("q" paradox-upgrade-packages)
  ("r" re-builder)
  ("s" synosaurus-choose-and-replace)
  ("t" git-timemachine)
  ("u" my/us2fi)
  ("w" browse-url-at-point)
  ("x" eshell)
  ("y" binclock)
  ("z" display-time-world)
  ("=" quick-calc)
  ("?" (browse-url "http://emacs.stackexchange.com/"))
  ("+" (browse-url "https://plus.google.com/communities/114815898697665598016"))
  ("0" repeat-complex-command))

Key bindings in current buffer

Here is the definition to keys-describe-prefixes function from Elisp newbie-style blog to print out all key bindings active in the current buffer. I do not use greek letters in keys, so I’ve removed them.

;;###autoload
(defun keys-describe-prefixes ()
  (interactive)
  (with-output-to-temp-buffer "*Bindings*"
    (dolist (letter-group (list
                           (cl-loop for c from ?a to ?z
                                    collect (string c))
                           (cl-loop for c from ?A to ?Z
                                    collect (string c))))
      (dolist (prefix '("" "C-" "M-" "C-M-"))
        (princ (mapconcat
                (lambda (letter)
                  (let ((key (concat prefix letter)))
                    (format ";; (global-set-key (kbd \"%s\") #'%S)"
                            key
                            (key-binding (kbd key)))))
                letter-group
                "\n"))
        (princ "\n\n")))))

Org entities with ivy

Kitchin on Org Entities | Irreal

For example, if I want a ‘U’ with an umlaut, I bring up the function, type “uu” and Ivy narrows the choices down to the two entries (capital and lower case) with an umlauted U, Ü. If I just type Return, the UTF glyph is inserted. If I type Meta+o (in Ivy, Helm, presumably, has a similar mechanism) I get a menu that allows me to enter the org-entity, LATEX, or HTML encodings.

It is bound to launch hydra key C-x l j.

(defun ivy-insert-org-entity ()
  "Insert an org-entity using ivy."
  (interactive)
  (ivy-read "Entity: " (loop for element in (append org-entities org-entities-user)
                             when (not (stringp element))
                             collect
                             (cons
                              (format "%10s | %s | %s | %s"
                                      (car element) ;name
                                      (nth 1 element) ; latex
                                      (nth 3 element) ; html
                                      (nth 6 element)) ;utf-8
                              element))
            :require-match t
            :action '(1
                      ("u" (lambda (element) (insert (nth 6 (cdr element)))) "utf-8")
                      ("o" (lambda (element) (insert "\\" (cadr element))) "org-entity")
                      ("l" (lambda (element) (insert (nth 1 (cdr element)))) "latex")
                      ("h" (lambda (element) (insert (nth 3 (cdr element)))) "html"))))

Formatting and white-space

View read-only

The built-in view-mode gives a consistent paging (<Space>/<Back>) and browsing environment to read-only files. It is now enabled in all read-only files.

(setq view-read-only t)

Character encoding

Character encoding in files and emacs buffers is an important topic for anyone dealing with anything other than plain ASCII English. The best approach is to assume UTF-8 and deal with anything else (Latin-1, UTF-16) only if you absolutely have to.

I have been having problems with pasting Finnish non-ascii text into org capture buffer and having the whole buffer inadvertently converted to iso-latin-1. This page (Emacs Windows org-mode encoding - Stack Overflow) gives a solution.

I still had occasional problems until I added a header to problem files:

# -*- coding: utf-8 -*-

In cases where text files come from Windows environment, it is useful to strip carriage returns from line endings to view the file using command line. Mnemonic function name dos2unix follows common conventions.

(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-language-environment "utf-8")
(setq locale-coding-system 'utf-8)
;; (set-terminal-coding-system 'utf-8) ; set by prefer-coding-system
;; (set-keyboard-coding-system 'utf-8) ; set by prefer-coding-system
;; (set-terminal-coding-system 'utf-8) ; set by prefer-coding-system
(set-selection-coding-system 'utf-8)

(when (display-graphic-p)
  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))
(modify-coding-system-alist 'file "" 'utf-8)
(set-charset-priority 'unicode)
(setq default-process-coding-system '(utf-8 . utf-8))

(bind-key "C-c u"
          (lambda () (interactive)
            (set-buffer-file-coding-system 'utf-8-unix t)))

;; does mostly same as above
(defun dos2unix ()
  "Not exactly but it's easier to remember"
  (interactive)
  (set-buffer-file-coding-system 'unix 't) )

Fixing wrong character encodings

It happens now and then that the character encoding is wrong in buffer. The main thing is not to panic and start doing global replacements to make non-ASCII characters look like they should. All the information is there; the character encoding just needs to be changed. See How to switch back text encoding to UTF-8 with emacs?

The most common wrong encoding shows \344 instead of ä. Then your encoding is latin-1. Run M-x revert-buffer-with-coding-system, and select e.g. utf-8-auto-mac.

If you still see strange characters after conversion, you have continued writing using latin-1 encoding and that portion of your text needs to be converted again. Select that text, and run M-x recode-region and give iso-latin-1 at the first prompt and utf-8-mac as the second.

Whitespace

There is but one case where trailing whitespace is syntactically important (in markdown). Since I do not use it, I can always strip whitespace on save. The same function removes trailing empty lines at the end of the buffer.

(add-hook 'before-save-hook 'delete-trailing-whitespace)

Tabs are automatically converted to spaces and trailing white space is shown. Global key C-c n indents and removes trailing white space from the buffer.

(setq-default indent-tabs-mode nil)
;; smart tab behavior - indent or complete
;; (setq tab-always-indent 'complete)

(defun my/clean-buffer-formatting ()
  "Indent and clean up the buffer"
  (interactive)
  (indent-region (point-min) (point-max))
  (whitespace-cleanup))

(bind-key "C-c n" 'my/clean-buffer-formatting)

(defun my/general-formatting-hooks ()
  ;;(setq show-trailing-whitespace 't)
  )

(dolist (mode-hook (my/normal-mode-hooks))
  (add-hook mode-hook 'my/general-formatting-hooks))

UNIXy text files should always end in a newline character. This tells emacs to take care of it so that you do not have to.

(setq require-final-newline t)

Emacs knows about natural language sentences and can navigate and mark them. The default emacs expects sentences that are separated by double space like in old typewriter text. Not any more. Note that this may lead to some ambiguity in detecting sentences.

(setq sentence-end-double-space nil)

Page breaks

Display page-break-lines page breaks (normally visible as ^L, create with C-q C-l) as horisontal lines.

(use-package page-break-lines
  :diminish ""
  :defer t
  :config
  (global-page-break-lines-mode))

Text (non-code) formatting

For writing text, I prefer Emacs to do line wrapping for me.

(defun my/text-formatting-hooks ()
  (my/turn-on 'auto-fill)) ; turn on automatic hard line wraps
(add-hook 'text-mode-hook 'my/text-formatting-hooks)

If the line wrapping (explicitely M-q) needs to be reversed, use unfill-paragraph that is bound to M-Q.

A handy free feature from Endless Parentheses does away the need to have a separate function for unfilling paragraphs: Now you can press M-q twice to unwrap.

(defun endless/fill-or-unfill ()
  "Like `fill-paragraph', but unfill if used twice."
  (interactive)
  (let ((fill-column
         (if (eq last-command 'endless/fill-or-unfill)
             (progn (setq this-command nil)
                    (point-max))
           fill-column)))
    (call-interactively #'fill-paragraph)))

(global-set-key [remap fill-paragraph]
                #'endless/fill-or-unfill)
;;(define-key org-mode-map [remap org-fill-paragraph] #'endless/fill-or-unfill)
;; org-fill-paragraph
;;; Stefan Monnier <foo at acm.org>. It is the opposite of fill-paragraph
(defun unfill-paragraph (&optional region)
  "Takes a multi-line paragraph and makes it into a single line of text."
  (interactive (progn (barf-if-buffer-read-only) '(t)))
  (let ((fill-column (point-max))
        ;; This would override `fill-column' if it's an integer.
        (emacs-lisp-docstring-fill-column t))
    (fill-paragraph nil region)))
;; Handy key definition
(define-key global-map "\M-Q" 'unfill-paragraph)

Filling, either manual or automatic using auto-fill-mode wraps lines that are longer than fill-column. This is usually modified by function set-fill-column that is bound to C-x f. This key combination is close to other common keys that I’ve frequently found myself accidentally modifying the fill-column value from its default 70. Hopefully this paragraph helps me to remember how to reset it.

An other confusing feature is the fill-prefix variable that can be set as buffer-local by function set-fill-prefix or C-x .. To return it to its default nil value, call the function on a empty line.

Understand compressed files

This allows emacs to handle opening and saving .gz files automatically.

(auto-compression-mode)

Auto refresh buffers

Automatically update file-associated buffers on file change. Also, auto refresh dired files.

(global-auto-revert-mode)
;; (diminish 'auto-revert-mode)
(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose t)

Editing

File management

Moving files

Move files is not something emacs does out of the box. You can rename a file with #'rename-file but the old file will still be there. This function makes it happen:

(defun move-file (new-location)
  "Write this file to NEW-LOCATION, and delete the old one."
  (interactive (list (if buffer-file-name
                         (read-file-name "Move file to: ")
                       (read-file-name "Move file to: "
                                       default-directory
                                       (expand-file-name (file-name-nondirectory (buffer-name))
                                                         default-directory)))))
  (when (file-exists-p new-location)
    (delete-file new-location))
  (let ((old-location (buffer-file-name)))
    (write-file new-location t)
    (when (and old-location
               (file-exists-p new-location)
               (not (string-equal old-location new-location)))
      (delete-file old-location))))

Moving a downloaded file

Quickly move a file to the current directory, an excellent function from Pragmatic Emacs. I added commands to copy the short filename into clipboard – something I found I was doing needing frequently to paste it into a document I was editing.

;; move file here
;; (require 'dash)
;; (require 'swiper)

;; start directory
(defvar my/move-file-here-start-dir (expand-file-name "~/Downloads"))

(defun my/move-file-here ()
  "Move file from somewhere else to here.

The file is taken from a start directory set by
`my/move-file-here-start-dir' and moved to the current directory
if invoked in dired, or else the directory containing current
buffer. The user is presented with a list of files in the start
directory, from which to select the file to move, sorted by most
recent first.

The short filename is copied to clipboard.

Quickly move a file to the current directory | Pragmatic Emacs
http://pragmaticemacs.com/emacs/quickly-move-a-file-to-the-current-directory/
"
  (interactive)
  (let (file-list target-dir file-list-sorted start-file start-file-full)
    ;; clean directories from list but keep times
    (setq file-list
          (-remove (lambda (x) (nth 1 x))
                   (directory-files-and-attributes my/move-file-here-start-dir)))

    ;; get target directory
    ;; http://ergoemacs.org/emacs/emacs_copy_file_path.html
    (setq target-dir
          (if (equal major-mode 'dired-mode)
              (expand-file-name default-directory)
            (if (null (buffer-file-name))
                (user-error "ERROR: current buffer is not associated with a file.")
              (file-name-directory (buffer-file-name)))))

    ;; sort list by most recent
    ;; http://stackoverflow.com/questions/26514437/emacs-sort-list-of-directories-files-by-modification-date
    (setq file-list-sorted
          (mapcar #'car
                  (sort file-list
                        #'(lambda (x y) (time-less-p (nth 6 y) (nth 6 x))))))

    ;; use ivy to select start-file
    (setq start-file (ivy-read
                      (concat "Move selected file to " target-dir ":")
                      file-list-sorted
                      :re-builder #'ivy--regex
                      :sort nil
                      :initial-input nil))

    ;; add full path to start file and end-file
    (setq start-file-full
          (expand-file-name start-file my/move-file-here-start-dir))
    (setq end-file
          (expand-file-name (file-name-nondirectory start-file) target-dir))
    (rename-file start-file-full end-file)
    ;; copy short filename to clipboard
    (kill-new start-file)
    (gui-set-selection 'PRIMARY start-file)
    (message "moved %s to %s" start-file-full end-file)))

Editing file lists with wdired

Editable dired is part of standard emacs. Once you are in dired C-x d, directory editing, mode, you can press C-x C-q to edit file names like any text. The familiar C-c C-c commits the changes.

;;http://mbork.pl/2015-04-25_Some_Dired_goodies
;;
;; file type association to a program
(setq dired-guess-shell-alist-user
      '(("\\.pdf\\'" "skim")
        ("\\.tex\\'" "pdflatex")
        ("\\.ods\\'\\|\\.xlsx?\\'\\|\\.docx?\\'\\|\\.csv\\'" "libreoffice")))
;; open a file replacing the current dired buffer
(put 'dired-find-alternate-file 'disabled nil)

Saving automatically

The super-save package saves files when the buffer looses focus. You never have to save manually.

Increased idle time to prevent idle saving messing up org mode edit-special buffers.

(use-package super-save
  :diminish ""
  :init
  (setq super-save-auto-save-when-idle t)
  (setq super-save-idle-duration 30)  ; def 5 sec
  :config (super-save-initialize))

Image mode

Recent emacsen can show images in directly in buffers. The following code adds the image+ minor mode to any image buffer and scales the picture to the current frame.

(use-package image
  :ensure nil
  :defer t
  :config
  (use-package image+
    :defer t
    :config (imagex-auto-adjust-mode 1)))

Editing as root

If you open a file that you do not have permissions to edit, you can call this function edit-current-file-as-root to invoke sudo rights within emacs. Kudos to Wenshan.

(defun edit-current-file-as-root ()
  "Edit as root the file associated with the current buffer"
  (interactive)
  (if (buffer-file-name)
      (progn
        (setq file (concat "/sudo:root@localhost:" (buffer-file-name)))
        (find-file file))
    (message "Buffer is not associated to a file.")))

Overwrite selected text

… like in any other editor.

(delete-selection-mode nil)

Incidently, this does work in org-mode. Beats me why not.

White-space

The default binding of M-Space is ==, but that function can be replaced by shrink-whitespace to progressively removing multiple new-lines or spaces to one or none.

(use-package shrink-whitespace
  :bind ("M-SPC" . shrink-whitespace))

The Pragmatic Emacs blog has a nifty function for aligning text. to columns. This is easy to modify for any separator character: For example, change the final \\s- into a comma to work on comma separated fields. An & is used in LaTeX tables.

(defun align-whitespace (start end)
  "Align columns by whitespace"
  (interactive "r")
  (align-regexp start end
                "\\(\\s-*\\)\\s-" 1 0 t))

Align text

A more general application of the previous function is to align text or code with any interactively selected separator character. Bound to C-x \ which was surprisingly unused.

(global-set-key (kbd "C-x \\") #'align-regexp)

Selecting text

Usually, you can selected (“mark”) text by S-<arrow> keys, but in my emacs that is disabled everywhere.

The main reason for that is the org mode. Org mode uses S-<arrow> keys for special functions in lists and headers and disables them in other text areas.

The S-<arrow> are now exclusively used for switching windows within an emacs frame.

The preferred way to select text is to press C-<space> followed by arrow keys to define the region, (but see below).

I am now using OS X in my main laptop computer and this choice had knock-on effects. By default, C-<space> pops up the Spotlight search field. To circumvent that, I’ve changed Spotlight key to Cmnd-<space>. That, in turn, disabled the default key for toggling of the active keyboard languages, so the key for that is now Cmnd-alt-<space>.

CUA mode

The biggest advantage modern emacs has over older ones is CUA-mode. It enables common C-x, C-c, C-v keyboard combinations in emacs buffers. It also adds an ability to do rectangle (column) editing. Press C-<Return> to enter it, use arrow keys to select, copy, and exit the rectangle editing mode by C-c.

(cua-mode t)

Expand region

You can select text incrementally using semantic units with by using expand-region: e.g. word, sentence, URL, quotes, paragraph, and section. Just press C-= and expand \= and contract - the selection! This works in all text modes including most programming languages, and is really convenient!

(use-package expand-region
  :bind ("C-=" . er/expand-region))

Change inner

An other Magnar’s package change-inner builds on expand-region and gives vi-like change-inner and change-outer commands that are recommended to be bound to M-i and M-o.

(use-package change-inner
  :bind ("M-i" . change-inner)
  :bind ("M-o" . change-outer))

PENDING Cut and copy

Note: This, nor previous code from Xah did not work for me!

Default cut and copy behaviour in emacs when nothing is selected is to do nothing. These functions modify cut or copy to work the current line instead.

(defun slick-cut (beg end)
  (interactive
   (if mark-active
       (list (region-beginning) (region-end))
     (list (line-beginning-position) (line-beginning-position 2)))))

(advice-add 'kill-region :before #'slick-cut)

(defun slick-copy (beg end)
  (interactive
   (if mark-active
       (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position) (line-beginning-position 2)))))

(advice-add 'kill-ring-save :before #'slick-copy)

TODO: An other way of doing the same: http://pragmaticemacs.com/emacs/cut-or-copy-current-line-with-easy-kill/

Undo-tree

The emacs undo behaviour can be confusing. Every undo get added to the stack just like any other editing event. If you end up going back and forth, you’ll find yourself lost quick quickly. Undo tree has commands and a visualizer to put you back on the map. Hit C-M-z see where you are.

Hydras are just great (simple but super useful hydra inside!) : emacs

(use-package undo-tree
  :diminish ""
  :bind
  ("C-z" . undo)
  ("M-z" . hydra-undo-tree/body)
  ("C-M-z" . undo-tree-visualize)
  :config
  ;; autosave the undo-tree history
  (setq undo-tree-history-directory-alist
      `((".*" . ,temporary-file-directory)))
  (setq undo-tree-auto-save-history t)
  (global-undo-tree-mode)

  (setq undo-tree-visualizer-diff t)
  (defhydra hydra-undo-tree (:color yellow :hint nil)
    "
    undo-tree
  -----------------------------------------------------
                _p_: undo   _s_: save   _v_: visualize
                _n_: redo   _l_: load   _q_: quit
      "
    ("p"   undo-tree-undo)
    ("n"   undo-tree-redo)
    ("s"   undo-tree-save-history)
    ("l"   undo-tree-load-history)
    ("v"   undo-tree-visualize :color blue)
    ("q"   nil :color blue)))

Abbreviations

Emacs comes with abbrev-mode that is able to replace typed strings in context sensitive way. I use it to correct typos (teh -> the) and replace short strings with long, multiline texts in modes that I use frequently. I turn this mode on globally. Any changes to abbrevs are silently saved.

While there are commands to modify abbreviations, I have added a link to

(use-package abbrev
  :diminish "Abbr"
  :ensure nil
  :defer t
  :commands abbrev-mode
  :custom
  (abbrev-mode 1 "enable globally")
  (save-abbrevs 'silently)
  :config
  (if (file-exists-p abbrev-file-name)
      (quietly-read-abbrev-file))
  (add-hook 'expand-load-hook
            (lambda ()
              (add-hook 'expand-expand-hook 'indent-according-to-mode)
              (add-hook 'expand-jump-hook 'indent-according-to-mode))))

A special form of abbreviation is a time stamp in a file. I do not want to see AM/PM time stamps.

(add-hook 'before-save-hook 'time-stamp)
(setq display-time-24hr-format t)

To use it, you place a template using bracket or quotes in the first 8 lines of a file. The time stamp value will be automatically added and updated between these delimiters. Often, the line is started with a comment character to mask it from the program processing the file, e.g.:

Time-stamp: <>
# Time-stamp: " "

insert-buffer-name does what the name says. This sort of metafunction does not really fit in any other category, so I list it here among abbreviations. Incidently, renaming a buffer is simply M-x rename-buffer.

(defun insert-buffer-name ()
  "Inserts file name of the buffer on the current buffer."
  (interactive)
  (insert (buffer-name)))
(bind-key "s-i" 'insert-buffer-name)

Similarly, you might want to remove both the current buffer and its file (from Emacs Redux). C-c d now does it for you in one step and it works correctly even when a version control system tracks the file.

(defun delete-file-and-buffer ()
  "Kill the current buffer and deletes the file it is visiting."
  (interactive)
  (let ((filename (buffer-file-name)))
    (when filename
      (if (vc-backend filename)
          (vc-delete-file filename)
        (progn
          (delete-file filename)
          (message "Deleted file %s" filename)
          (kill-buffer))))))
(bind-key "C-c d" 'delete-file-and-buffer)

Kill This Buffer (Irreal) with the key binding “C-x k” without asking. Giving it an universal argument (C-u) calls the standard kill-buffer function.

(defun my/kill-a-buffer (askp)
  (interactive "P")
  (if askp
      (kill-buffer (funcall completing-read-function
                            "Kill buffer: "
                            (mapcar #'buffer-name (buffer-list))))
    (kill-this-buffer)))
(bind-key "C-x k" 'my/kill-a-buffer)

PENDING Yasnippet

Add your own snippets to file:~/.emacs.d/snippets by placing files there or invoking yas-new-snippet.

Yas is enabled in programming and org modes.

(use-package yasnippet
  :disabled nil
  :defer t
  :init
  (add-hook 'prog-mode-hook #'yas-minor-mode)
  (add-hook 'org-mode-hook #'yas-minor-mode)
  (add-hook 'emacs-lisp-mode-hook #'yas-minor-mode)
  :config
  (yas-reload-all))

Fixing DOuble capitals

Painless way to avoid double capitals in the beginning of words from Endless Parentheses and Emacs StackExchange.

(defun dcaps-to-scaps ()
  "Convert word in DOuble CApitals to Single Capitals."
  (interactive)
  (and (= ?w (char-syntax (char-before)))
       (save-excursion
         (and (if (called-interactively-p 'interactive)
                  (skip-syntax-backward "w")
                (= -3 (skip-syntax-backward "w")))
              (let (case-fold-search)
                (looking-at "\\b[[:upper:]]\\{2\\}[[:lower:]]"))
              (capitalize-word 1)))))

(define-minor-mode dubcaps-mode
  "Toggle `dubcaps-mode'.  Converts words in DOuble CApitals to
Single Capitals as you type."
  :init-value t
  :lighter ("")
  (if dubcaps-mode
      (add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)
    (remove-hook 'post-self-insert-hook #'dcaps-to-scaps 'local)))

(add-hook 'text-mode-hook #'dubcaps-mode)

Fixing text written with wrong keyboard layout

My default keyboard layout is US, but I also write in Finnish language that differs from US for some special characters. Quite often, I start writing in Finnish with US keyboard layout. These functions allow me to fix the wrong characters in one go in the paragraph I am writing. Bound to the launch hydra: M-x l u.

(defun translate-characters (from-string to-string begin end)
  "Translate characters in the current buffer.

FROM-STRING and TO-STRING are equal length strings that contain
translatable characters in order like in the tr command line tool.

Works on a given region between BEGIN and END."

  (let ((from-regexp (concat "[" (regexp-quote from-string) "]"))
        (tr-alist (pairlis (split-string from-string "" t)
                           (split-string to-string "" t))))
    (save-excursion
      (goto-char begin)
      (while (and
              (re-search-forward from-regexp nil t)
              (<= (point) end))
        (goto-char (match-beginning 0))
        (if (match-string 0)
            (replace-match (cdr (assoc (match-string 0) tr-alist)) t))
        (goto-char (match-end 0))))))

(defun my/us2fi (&optional begin end)
  "Convert characters written with US keyboard layout to matching Finnish ones.

Converts only characters that translate to Scandinavian letters
åäöÅÄÖ. All other characters are ignored.

Works on the current paragraph or text selection (between BEGIN
and END.

Calls `translate-characters' to do the work.

In Finnish text, the character ä occurs roughly as every 20th
character, ö only every 200 and å is only used in Swedish derived
words."

  (interactive
   (if (use-region-p)
       (list (region-beginning) (region-end))
     (let ((bds (bounds-of-thing-at-point 'paragraph)))
       (list (car bds) (cdr bds)))))

  (let* ((us-string ";'[:\"{")
         (fi-string "öäåÖÄÅ"))
    (translate-characters us-string fi-string begin end)))

Transposing characters

Pragmatic Emacs has an improvement on character transposing function. The original function transposes characters on both sides of the cursor. The new one acts on two previous characters.

(defun my/transpose-chars ()
  "Transpose two previous characters"
  (interactive)
  (backward-char)
  (transpose-chars 1))
(bind-key "C-t" 'my/transpose-chars)

Adding comma before space

In natural languages a comma separates sentences or list items but it always comes before any space. This code automatically moves cursor to the right place when the comma key is pressed.

(defun my/smart-self-insert-punctuation (count)
  "If COUNT=1 and the point is after a space, insert the relevant
character before any spaces."
  (interactive "p")
  (if (and (= count 1)
           (eq (char-before) ?\s))
      (save-excursion
        (skip-chars-backward " ")
        (self-insert-command 1))
    (self-insert-command count)))
(bind-key "," #'my/smart-self-insert-punctuation)

String inflection

String inflection cycles variable names between camel case and underscore-separated states. The mnemonic is “Emacs, toggle variable”, C-x t v.

(use-package string-inflection
  :defer t)

iedit mode

Activate the Iedit mode by placing the cursor to a word and pressing C-x t i. All occurrences of that word in the buffer are selected and can be simultaneously edited.

(use-package iedit
  :defer t)

PENDING Multiple cursors

is an alternative to iedit. See this dot files for more configuration options and a sample hydra, also here.

  (use-package multiple-cursors
  :config
  (defhydra hydra-mc (:hint nil)
    "
        ^Up^            ^Down^        ^All^                ^Lines^               ^Edit^                 ^Other^
  ----------------------------------------------------------------------------------------------------
  [_p_]   Next    [_n_]   Next    [_a_] All like this  [_l_] Edit lines      [_i_] Insert numbers   [_t_] Tag pair
  [_P_]   Skip    [_N_]   Skip    [_r_] All by regexp  [_L_] Edit line beg.  [_s_] Sort regions      ^ ^
  [_M-p_] Unmark  [_M-n_] Unmark  [_d_] All DWIM        ^ ^                  [_R_] Reverse regions  [_q_] Quit
  "
    ("p" mc/mark-previous-like-this)
    ("P" mc/skip-to-previous-like-this)
    ("M-p" mc/unmark-previous-like-this)

    ("n" mc/mark-next-like-this)
    ("N" mc/skip-to-next-like-this)
    ("M-n" mc/unmark-next-like-this)

    ("a" mc/mark-all-like-this :exit t)
    ("r" mc/mark-all-in-region-regexp :exit t)
    ("d" mc/mark-all-dwim :exit t)

    ("l" mc/edit-lines :exit t)
    ("L" mc/edit-beginnings-of-lines :exit t)

    ("i" mc/insert-numbers)
    ("s" mc/sort-regions)
    ("R" mc/reverse-regions)

    ("t" mc/mark-sgml-tag-pair)
    ("q" nil)

    ("<mouse-1>" mc/add-cursor-on-click)
    ("<down-mouse-1>" ignore)
    ("<drag-mouse-1>" ignore)))

(global-unset-key (kbd "M-<down-mouse-1>"))
(global-set-key (kbd "M-<mouse-1>") 'mc/add-cursor-on-click)

;;  a(unbind-key "C-c c" python-mode-map))
;;  (bind-key "C-c C-z" 'python-shell python-mode-map)
;;  (global-unset-key (kbd "M-<down-mouse-1>"))
;;  (global-set-key (kbd "M-<mouse-1>") 'mc/add-cursor-on-click)

Count words in a buffer

;; word-count
(defun word-count nil "Count words in buffer" (interactive)
       (shell-command-on-region (point-min) (point-max) "wc -w"))

(defun count-words (start end)
  "Print number of words in the region."
  (interactive "r")
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (count-matches "\\sw+"))))

Text editing by external programs

It used to be quicker for me to write perl scripts to format text than do it any other way. These functions demonstrate how a standard command line program that reads from STDIN and write to STDOUT is easily included into emacs workflow. Markdown and SmartyPants are equally antiquated functions.

Programs need to be available in your shell path. txt2para.pl serves as a good example of these programs that are here documented only for historical reasons. They are no more active.

(defun txt2xhtml ()
  "Turn consecutive non-empty lines of plain text into HTML <p> elements."
  (interactive)
  (shell-command-on-region (point)
                           (mark) "txt2xhtml.pl" nil t))

(defun txt2header ()
  "Turn consecutive non-empty lines of plain text into HTML <h2> elements."
  (interactive)
  (shell-command-on-region (point)
                           (mark) "txt2header.pl" nil t))

(defun txt2para ()
  "Turn consecutive non-empty lines of plain text into paragraphs."
  (interactive)
  (shell-command-on-region (point)
                           (mark) "txt2para.pl" nil t))

(defun do-mark-down (start end)
  "Invoke the Markdown algorithm on region."
  (interactive "r")
  (shell-command-on-region start end "Markdown.pl" t t))
;;(global-set-key "\C-cm" #'do-mark-down)

(defun do-smarty-pants (start end)
  "Invoke the SmartyPants algorithm on region."
  (interactive "r")
  (shell-command-on-region start end "SmartyPants.pl" t t))
;;(global-set-key "\C-cs" #'do-smarty-pants)

Commenting

The default emacs line commenting used to a lot of things out. This was fixed in emacs version 25, but the new function was bound to C-x C-;. I remap it to the usual C-; but leave the replacement function for the older emacsen.

A replacement package comment-dwim-2 allows uncommenting and cycling of different behaviors. C-u M-; in an empty line adds comment markers to the line. In a line with comments, C-u M-; removes the whole comment line.

Alternative is smart-comment: Smarter commenting for Emacs.

;;  (if (>= emacs-major-version 25)
;;      (bind-key "M-;" #'comment-line)
;;    (use-package comment-dwim-2
;;      :bind "M-;"))

(use-package smart-comment
  :bind ("M-;" . smart-comment))

Remember: C-x ; sets the comment column (comment-set-column)

This following function draws a comment box that is the width of the fill column around the selected region.

;;http://irreal.org/blog/?p=374
(defun jcs-comment-box (b e)
  "Draw a box comment around the region but arrange for the region
to extend to at least the fill column. Place the point after the
comment box."
  (interactive "r")
  (let ((e (copy-marker e t)))
    (goto-char b)
    (end-of-line)
    (insert-char ?  (- fill-column (current-column)))
    (comment-box b e 1)
    (goto-char e)
    (set-marker e nil)))

Macros

Emacs has a powerful keyboard macro system. However, it has its own internal notation. The elmacro minor mode converts these macros into emacs lisp functions. Start the elmacro mode (M-x elmacro-mode) before recording the macro, and once it has been defined, use M-x elmacro-show-last-macro to give the generated function a name, and see it in a new buffer.

The function key shortcuts for macros are not useful under OS X, but these commands work well:

  • C-x ( kmacro-start-macro
  • C-x ) kmacro-end-macro
  • C-x e kmacro-end-and-call-macro
  • e call macro if pressed right after previous function
  • C-u n C-x e run the macro n times
  • C-x C-k C-e edit last macro

Buffers

A more functional buffer listing comes from ibuffer. The following makes normal list-buffer or C-x C-b call ibuffer. Check the new menu lists Operate, View and Mark.

(defalias 'list-buffers 'ibuffer) ; make ibuffer default

Version control

Magit

The only version control system worth using is git and magit is the emacs interface to it. Most important files in git have their dedicated modes: git-commit-mode, gitconfig-mode, git-rebase-mode, and gitignore-mode.

From any buffer linked to a git controlled file, press C-c g to enter magit status window. Pressing q restores the previous window(s).

Magit automatically updates the buffer of each file that changes at commit.

See this post for a tutorial of commit message editing with magit.

Irreal gives hints how to configure the latest (2.1) magit.

One of the best features of magit is its ability to show changes in a single file in chunks. Even better is that you can discard the chunk from the file by pressing key k. Great for discarding typos.

If the chunk is too large, you can just select part of it and press s to stage it.

magithub adds interfaces to talk to Github. It uses the command line utility hub to do its work. The magit command is @. hub needs to be installed (e.g. brew install hub in OS X).

(use-package magit
  :bind ("C-c g" . magit-status)
  :config
  (setq magit-push-always-verify nil)
  ;; ignore whitespace
  (setq magit-diff-options '("-b")))

(use-package magithub
  :disabled t
  :ensure-system-package hub
  :after magit
  :config
  (magithub-feature-autoinject t))

(use-package git-commit :defer t)
(use-package git-gutter :defer t
  :diminish "")

(use-package gitattributes-mode :defer t)
(use-package gitconfig-mode :defer t)
(use-package gitignore-mode :defer t)

git-timemachine

git-timemachine lets you browse previous versions of a file. Start it with C-x l t or C-x git-timemachine.

keydescription
pvisit previous version
nvisit next version
wcopy the short version hash
Wcopy the full version hash
qquit
(use-package git-timemachine
  :diminish ""
  :defer t)

Text files

Natural languages

Spell checking

Flyspell checks words as I write against the GNU aspell dictionaries.

You might have to install aspell for your computer. For OS X, do it using Homebrew brew install aspell. This installs several varieties of English. To add more languages, you have to specify them as arguments.

Words added to personal word list are stored in ~/.aspell.{LANG}.pws, e.g. file:~/.aspell.en.pws.

Alternatively, call flyspell-goto-next-error by pressing C-,= and press =C-c k to select the correct word from dictionary and write it to abbreviations for automatic correction permanently. Adapted from Endless Parentheses.

Other possibilities are C-. (flyspell-auto-correct-word) and C-; (flyspell-auto-correct-previous-word) that proposes various successive corrections for the current word. Combining C-,= with =C-. is especially efficient.

aspell

 (setq ispell-program-name "aspell") ; checker engine
;; (setq ispell-program-name "enchant-2") ; checker engine

 ;; Speed up aspell: ultra | fast | normal
 (setq ispell-extra-args '("--sug-mode=ultra"))

 ;; Flyspell activation for text modes
 (add-hook 'text-mode-hook
           (lambda () (flyspell-mode 1)
             (define-key flyspell-mode-map (kbd "C-M-i") nil)
             ;;(diminish 'flyspell-mode " ✓")
             ))
 ;; Flyspell activation for programming modes
 (add-hook 'prog-mode-hook 'flyspell-prog-mode)

 ;; fix ispell for org mode
 ;; http://endlessparentheses.com/ispell-and-org-mode.html
 (defun endless/org-ispell ()
   "Configure `ispell-skip-region-alist' for `org-mode'."
   (make-local-variable 'ispell-skip-region-alist)
   (add-to-list 'ispell-skip-region-alist '(org-property-drawer-re))
   (add-to-list 'ispell-skip-region-alist '("~" "~"))
   (add-to-list 'ispell-skip-region-alist '("=" "="))
   (add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_SRC" . "^#\\+END_SRC")))
 (add-hook 'org-mode-hook #'endless/org-ispell)

 ;; 3. ignore tex commands
 (add-hook 'org-mode-hook (lambda () (setq ispell-parser 'tex)))
 (defun flyspell-ignore-tex ()
   (interactive)
   (set (make-variable-buffer-local 'ispell-parser) 'tex))
 (add-hook 'org-mode-hook 'flyspell-ignore-tex)


 ;; Remove Flyspell from some sub modes of text mode
 (dolist (hook '(change-log-mode-hook
                 log-edit-mode-hook))
   (add-hook hook (lambda () (flyspell-mode -1))))

 ;; switching languages
 ;; code adapted from http://www.emacswiki.org/emacs/FlySpell
 ;; default is 'american'
 (setq ispell-dictionary "american")

 (let ((langs '( "english" "finnish" "american" )))
   (setq lang-ring (make-ring (length langs)))
   (dolist (elem langs) (ring-insert lang-ring elem)))

 (defun cycle-ispell-languages ()
   (interactive)
   (let* ((dict ispell-current-dictionary)
          (lang (ring-ref lang-ring -1)))
     (ring-insert lang-ring lang)
     (ispell-change-dictionary lang)
     (message "Dictionary switched from %s to %s" dict lang)))

 ;; from http://endlessparentheses.com/ispell-and-abbrev-the-perfect-auto-correct.html
 (defun my/ispell-word-then-abbrev (p)
   "Call `ispell-word', then create an abbrev for it.
 With prefix P, create local abbrev. Otherwise it will
 be global.
 If there's nothing wrong with the word at point, keep
 looking for a typo until the beginning of buffer. You can
 skip typos you don't want to fix with `SPC', and you can
 abort completely with `C-g'."
   (interactive "P")
   (let (bef aft)
     (save-excursion
       (while (if (setq bef (thing-at-point 'word))
                  ;; Word was corrected or used quit.
                  (if (ispell-word nil 'quiet)
                      nil ; End the loop.
                    ;; Also end if we reach `bob'.
                    (not (bobp)))
                ;; If there's no word at point, keep looking
                ;; until `bob'.
                (not (bobp)))
         (backward-word))
       (setq aft (thing-at-point 'word)))
     (if (and aft bef (not (equal aft bef)))
         (let ((aft (downcase aft))
               (bef (downcase bef)))
           (define-abbrev
             (if p local-abbrev-table global-abbrev-table)
             bef aft)
           (message "\"%s\" now expands to \"%s\" %sally"
                    bef aft (if p "loc" "glob")))
       (user-error "No typo at or before point"))))
 (bind-key "C-c k" 'my/ispell-word-then-abbrev)

 ;; original copied from
 ;; http://stackoverflow.com/questions/22107182/in-emacs-flyspell-mode-how-to-add-new-word-to-dictionary
 (defun my/flyspell-save-word (&optional save-lowercase)
   "Save word to a personal dictionary.

                      The dictionary file depends on the used spell program. If the the first
                      argument SAVE-LOWERCASE is non-nil, save also lowercased word.
                     "
   (interactive)
   (let ((current-location (point))
         (word (flyspell-get-word)))
     (when (consp word)
       (when (boundp save-lowercase)
         (flyspell-do-correct
          'save nil (downcase (car word)) current-location (cadr word)
          (downcase (caddr word)) current-location))
       (flyspell-do-correct
        'save nil (car word) current-location (cadr word)
        (caddr word) current-location))))


 ;; move point to previous error
 ;; based on code by hatschipuh at
 ;; http://emacs.stackexchange.com/a/14912/2017
 (defun flyspell-goto-previous-error (arg)
   "Go to arg previous spelling error."
   (interactive "p")
   (while (not (= 0 arg))
     (let ((pos (point))
           (min (point-min)))
       (if (and (eq (current-buffer) flyspell-old-buffer-error)
                (eq pos flyspell-old-pos-error))
           (progn
             (if (= flyspell-old-pos-error min)
                 ;; goto beginning of buffer
                 (progn
                   (message "Restarting from end of buffer")
                   (goto-char (point-max)))
               (backward-word 1))
             (setq pos (point))))
       ;; seek the next error
       (while (and (> pos min)
                   (let ((ovs (overlays-at pos))
                         (r '()))
                     (while (and (not r) (consp ovs))
                       (if (flyspell-overlay-p (car ovs))
                           (setq r t)
                         (setq ovs (cdr ovs))))
                     (not r)))
         (backward-word 1)
         (setq pos (point)))
       ;; save the current location for next invocation
       (setq arg (1- arg))
       (setq flyspell-old-pos-error pos)
       (setq flyspell-old-buffer-error (current-buffer))
       (goto-char pos)
       (if (= pos min)
           (progn
             (message "No more miss-spelled word!")
             (setq arg 0))
         (forward-word)))))
 (bind-key "C-," 'flyspell-goto-previous-error)

 ;; speed up file open
 (setq flyspell-issue-message-flag nil)

 (bind-key "C-x '" 'hydra-flyspell/body)
 (defhydra hydra-flyspell (:color pink :hint nil)
   "
                  ^Flyspell^             ^Check^      [Language: %`ispell-current-dictionary]
                ^^-----------------------------------------------------------
                  _n_: next error        _c_: correct
                  _t_: cycle languages   _k_: correct and add to abbrev
                  _q_uit                 _i_: insert to personal list
                  ^ ^                    _u_: insert, uncapitalize and insert
                "
   ("n" flyspell-goto-next-error)
   ("t" cycle-ispell-languages)
   ("q" nil :color blue)

   ("c" ispell-word)
   ("k" my/ispell-word-then-abbrev)
   ("i" my/flyspell-save-word)
   ("u" (my/flyspell-save-word t)))

PENDING wcheck mode

A level up in spell checking abstractions is Wcheck Mode that understands programs for proper inflection of words in Finnish in addition to standard flyspell.

Sources:

  • http://www.hillenius.com/blog/2013/11/09_writers-need-spell-checkers-wcheck-mode.html
    (setq ispell-program-name "aspell")
    
    (defvar my-finnish-syntax-table
      (copy-syntax-table text-mode-syntax-table))
    
    (modify-syntax-entry ?- "w" my-finnish-syntax-table)
    
    (setq wcheck-language-data
          '(("British English"
             (program . "/usr/local/bin/aspell")
             (args "-a"  "-l" "-d" "british")
             (action-program . "/usr/local/bin/aspell")
             (action-args "-a" "-d" "british")
             (action-parser . wcheck-parser-ispell-suggestions))
            ("Finnish"
             (program . "/usr/local/bin/enchant")
             (args "-l" "-d" "fi")
             (syntax . my-finnish-syntax-table)
             (action-program . "/usr/local/bin/enchant")
             (action-args "-a" "-d" "fi")
             (action-parser . wcheck-parser-ispell-suggestions))))
        

https://github.com/tlikonen/wcheck-mode is the next level of abstraction in spell checking. It can work with standard ispell, aspell and hunspell, but also with enchant that can deal with languages that have more complex rules of inflection than typical Germanic languages. Finnish has a freeware program Voikko that can deal with its intricacies.

  • http://www.hillenius.com/blog/2013/11/09_writers-need-spell-checkers-wcheck-mode.html
  • https://github.com/philc/emacs-config
    (autoload 'wcheck-mode "wcheck-mode"
      "Toggle wcheck-mode." t)
    (autoload 'wcheck-change-language "wcheck-mode"
      "Switch wcheck-mode languages." t)
    (autoload 'wcheck-actions "wcheck-mode"
      "Open actions menu." t)
    (autoload 'wcheck-jump-forward "wcheck-mode"
      "Move point forward to next marked text area." t)
    (autoload 'wcheck-jump-backward "wcheck-mode"
      "Move point backward to previous marked text area." t)
    
    ;; these two sexps set up a functional wcheck
    (setq-default wcheck-language "english")
    (setq-default wcheck-language-data
                  '(("english"
                     (program . "/usr/local/bin/aspell")
                     (args "list") ; -l: list only the mispellings.
                     (face . hi-yellow)
                     (connection . pty)
                     ;; Note that I don't use this functionality of providing suggested spelling corrects, and
                     ;; this config is untested. I just like to highlight mispelled words.
                     (action-program . "/usr/local/bin/aspell")
                     (action-args "-a") ; -a: lists alternatives.
                     (action-parser . wcheck-parser-ispell-suggestions))))
    
    
    
    (defvar my-finnish-syntax-table
      (copy-syntax-table text-mode-syntax-table))
    (modify-syntax-entry ?- "w" my-finnish-syntax-table)
    (setq-default wcheck-language "finnish")
    
    (setq wcheck-language-data
          '(("english"
             (program . "/usr/local/bin/aspell")
             (args "list") ; -l: list only the mispellings.
             (face . hi-yellow)
             (connection . pty)
             (action-program . "/usr/local/bin/aspell")
             (action-args "-a") ; -a: lists alternatives.
             (action-parser . wcheck-parser-ispell-suggestions))
            ("british"
             (program . "/usr/local/bin/aspell")
             (args "list" "-l" "en_BR") ; list: list only the mispellings.
             (face . hi-yellow)
             (connection . pty)
             (action-program . "/usr/local/bin/aspell")
             (action-args "-a" "-l" "en_BR") ; -a: lists alternatives.
             (action-parser . wcheck-parser-ispell-suggestions))
            ("finnish"
             (program . "/usr/local/bin/enchant")
             (args "-l" "-d" "fi")
             (syntax . my-finnish-syntax-table)
             (action-program . "/usr/local/bin/enchant")
             (action-args "-a" "-d" "fi")
             (action-parser . wcheck-parser-ispell-suggestions))
            ))
    
    
    
    ;; Set aspell as the spell program
    (setq ispell-program-name "aspell")
    
    ;; Speed up aspell: ultra | fast | normal
    (setq ispell-extra-args '("--sug-mode=ultra"))
    
    (setq ispell-dictionary "british")
    
    (let ((langs '( "english" "finnish" "american" )))
      (setq lang-ring (make-ring (length langs)))
      (dolist (elem langs) (ring-insert lang-ring elem)))
    
    ;;     ("British English"
    ;;      (program . "/usr/local/bin/enchant")
    ;;      (args "-l" "-d" "en_GB")
    ;;      (face . hi-yellow)
    ;;      (connection . pty)
    ;;      (action-program . "/usr/local/bin/enchant")
    ;;      (action-args "-a" "-d" "en_GB")
    ;;      (action-parser . wcheck-parser-ispell-suggestions))))
    
    
    ;; (setq wcheck-language-data
    ;;       '(("british"
    ;;          (program . "/usr/local/bin/aspell")
    ;;          (args "-l" "-d" "british")
    ;;          (action-program . "/usr/local/bin/aspell")
    ;;          (action-args "-a" "-d" "british")
    ;;          (action-parser . wcheck-parser-ispell-suggestions))
    ;;         ("Finnish"
    ;;          (program . "/usr/local/bin/enchant")
    ;;          (args "-l" "-d" "fi")
    ;;          (syntax . my-finnish-syntax-table)
    ;;          (action-program . "/usr/local/bin/enchant")
    ;;          (action-args "-a" "-d" "fi")
    ;;          (action-parser . wcheck-parser-ispell-suggestions))
    ;;         ("cat" ((program . "/bin/cat")))))
    
    (bind-key "C-c s" 'wcheck-mode)
    (bind-key "C-c l" 'wcheck-change-language)
    (bind-key "C-c c" 'wcheck-actions)
    ;;(bind-key "C-c n" 'wcheck-jump-forward)
    ;;(bind-key "C-c p" 'wcheck-jump-backward)
    
    (bind-key "C-c w" 'hydra-wcheck/body)
    (defhydra hydra-wcheck (:color pink :hint nil)
      "
            ^Wcheck^             ^Check^      [Language: %`ispell-current-dictionary]
          ^^-----------------------------------------------------------
            _t_: toggle            _n_: next error
            _c_: change language   _k_: correct and add to abbrev
             a   actions           _i_: insert to personal list
            _q_uit                 _u_: insert, uncapitalize and insert
                   "
      ("n" flyspell-goto-next-error)
      ("t" cycle-ispell-languages)
      ("q" nil :color blue)
    
      ("c" ispell-word)
      ("k" my/ispell-word-then-abbrev)
      ("i" my/flyspell-save-word)
      ("u" (my/flyspell-save-word t)))
        

Writing style: writegood

Writegood mode, C-x t w, highlights common writing problems in English text. It highlights weasel words, passive voice, and duplicate words. Additionally, it can show Flesch-Kincaid scoring and grade-level estimates.

(use-package writegood-mode
  :bind  (("C-c C-g g" . writegood-grade-level)
          ("C-c C-g e" . writegood-reading-ease)))

Grammar: languagetool

LanguageTool now works with the latest release. I start with British English, but that can be changed when needed. I’ve disabled spell checking that gives too many spurious hits in org mode. Besides, flyspell does it better anyway. The main way to launch langtool is to hit C-x l g that is short for “Emacs, launch grammar”.

  (use-package langtool
    :bind (("C-x 4 w" . langtool-check)
           ("C-x 4 W" . langtool-check-done)
           ("C-x 4 l" . langtool-switch-default-language)
           ("C-x 4 4" . langtool-show-message-at-point)
           ("C-x 4 c" . langtool-correct-buffer))
    :init
    (setq langtool-language-tool-jar
          "/usr/local/Cellar/languagetool/4.1/libexec/languagetool-commandline.jar")
    (setq langtool-default-language "en")
   ;; (setq langtool-user-arguments '(\"--languagemodel ~/data/lt\"))
    (setq langtool-user-arguments '("--languagemodel" "~/data/lt")) ; try!
    ;;(setq langtool-user-arguments "--languagemodel ~/data/lt")
;;    (setq langtool-java-user-arguments nil)
    (setq langtool-mother-tongue "en")
    (setq langtool-disabled-rules '("WHITESPACE_RULE"
                                    "EN_UNPAIRED_BRACKETS"
                                    "COMMA_PARENTHESIS_WHITESPACE"
                                    "EN_QUOTES"
                                    "MORFOLOGIK_RULE_EN_GB"
                                    "MORFOLOGIK_RULE_US")))

Word definition

Define-word (blog) gives English definitions to words under cursor using on-line Wordnik service. Use C-c J to search the word under the cursor. M-x define-word lets you type a word in.

For situations without net, osx-dictionary accesses the local OS X Dictionary application. Use C-c j, or M-x osx-dictionary-search-pointer.

Since I am using several dictionaries from different sources and syntax, I have turned off syntax highlighting for osx-dictionary-mode.

(use-package define-word
  :bind (("C-c J" . define-word-at-point)))

(when (eq system-type 'darwin)
  (use-package osx-dictionary
    :bind (("C-c j" . osx-dictionary-search-pointer))))

Note to self: Using j as a key is not at all mnemonic but I am running out of letters.

Synonyms: synosaurus

Synosaurus uses WordNet for offline functionality. Install Wordnet first: In OSX brew install wordnet. The interaction is through command line tool wn.

I enable synosaurus-mode in text files and define the key combination C-x l s for “Emacs, launch synonyms”. The default setup uses popups to show alternative words.

(use-package synosaurus
  :defer t
  :init
  ;;(setq synosaurus-backend)
  (setq synosaurus-choose-method 'popup)
  :config
  (add-hook 'text-mode-hook #'synosaurus-mode))

Webster’s

The old Webster’s 1913 Dictionary is a rare beast where definitions of words are poetic, informative and thought provoking.

I’ve installed a local copy the Webster’s dictionary to my Mac and set it up as the first dictionary to search. Now the above key binding C-c j searches first Webster’s.

The downloaded sdcv-mode and its sdcv-search command remains unused.

(use-package sdcv-mode
  :disabled t
  :ensure nil)

Text folding

Origami folding minor mode recognises programming modes and works on other modes

(use-package origami
:bind (("C-c y" . hydra-origami/body))
:config
 (defhydra hydra-origami (:color red :hint nil)
   "
  ╭────────────┐
  │ Origami    │
 ╭┴────────────╯───────────────────────────────────────────────────
  _o_pen node    _n_ext fold             toggle _f_orward
  _c_lose node   _p_revious fold         toggle _a_ll
  _t_oggle node  _N_ext and toggle       _s_how point only
  ^ ^            _P_revious and toggle   _u_ndo
  _q_uit         ^ ^                     _r_edo
 "
   ("o" origami-open-node)
   ("c" origami-close-node)
   ("t" origami-recursively-toggle-node)
   ("f" origami-next-fold)
   ("n" origami-forward-fold)
   ("N" (progn
          (origami-toggle-node (current-buffer) (point))
          (origami-forward-fold (current-buffer) (point))
          (origami-toggle-node (current-buffer) (point))))
   ("p" origami-previous-fold)
   ("P" (progn
          (origami-toggle-node (current-buffer) (point))
          (origami-previous-fold (current-buffer) (point))
          (origami-toggle-node  (current-buffer) (point))))
   ("u" origami-undo)
   ("r" origami-redo)

   ("a" origami-toggle-all-nodes)
   ("s" origami-show-only-node)
   ("q" nil :color blue)))

Number groups

Large numbers made easier to read by highlighting groups of three.

(use-package digit-groups
  :init (setq digit-groups-global-mode t))

This was added to the toggle hydra and can be invoked with C-x t g, “Emacs, toggle groups”.

Highlighting

rolandwalker/button-lock: clickable text in Emacs provides clickable text for text files.

(use-package button-lock
:config
(global-button-lock-mode 1))

Poetry mode

Bob Newell’s poetry mode is available from http://www.bobnewell.net/filez/poetry.el .

;;(require 'poetry)

Whitespace

Whitespace mode makes whitespace characters visible in a buffer. This tones down the colors and uses good looking Unicode characters. Toggle it with “Emacs, toggle (white)Space” C-x t s.

;; make whitespace-mode use just basic coloring
(setq whitespace-style
      (quote (face spaces tabs newline space-mark tab-mark newline-mark trailing)))

;; use better unicode characters for whitespace
(setq whitespace-display-mappings
      ;; all numbers are Unicode codepoint in decimal. try (insert-char 182 ) to see it
      '((space-mark 32 [183] [46]) ; 32 SPACE, 183 MIDDLE DOT 「·」, 46 FULL STOP 「.」
        (newline-mark 10 [182 10]) ; 10 LINE FEED
        (tab-mark 9 [9655 9] [92 9]) ; 9 TAB, 9655 WHITE RIGHT-POINTING TRIANGLE 「▷」
        ))

Line numbers

My fingers still know the old shortcut C-x ,= for jumping to a line number. The function =goto-line-with-feedback automatically turns line numbers on and shows them in normal mode for the duration of the command. It assumes that line numbers are off to start with.

This version of the function needs the built-in display-line-numbers-mode that was added in emacs version 26.1 replasing the linum packages.

;; emacs-version 26.1
(defun goto-line-with-feedback ()
  "Show line numbers temporarily, while prompting for the line number input"
  (interactive)
  (unwind-protect
      (progn
        (display-line-numbers-mode)
        (goto-line (read-number "Goto line: ")))
    (display-line-numbers-mode 0)))

(bind-key "C-x ," 'goto-line)
(bind-key [remap goto-line] 'goto-line-with-feedback)

LaTeX

Use AUCTex for all LaTeX. There is an extensive info documentation that you do not read to get started C-h i m auctex.

LaTeX-extra gives additional features like code folding. The AUXTeX-latexmk package uses the latexmk to compile. Set it to produce PDF by running the following code block:

cat > ~/.latexmkrc
# .latexmkrc starts
$pdf_mode = 1;
# .latexmkrc ends

latex-preview-panel package enables preview within Emacs. I could add (latex-preview-panel-enable) here but it I can enable it on the fly with M-x latex-preview-pane-mode

Endless Parentheses tackles long lines by modifying the longlines mode to make emacs more compatible with other LaTeX editors. StackExchange gives a solution below using the package adaptive-wrap.

My LaTeX setup wraps long lines at the word boundary on window edge (visual-line-mode on) and prevents automatic word wrapping using hard newlines (auto-fill-mode off) when buffer is in LaTeX mode. This is exactly opposite to behaviors in most other text modes.

Hit C-c C-c to compile, C-c C-v to view.

More AUCTeX tips. Irreal blog. A conf example.

(use-package tex
  :disabled nil
  :defer t
  :ensure auctex
  :config

  (use-package auctex-latexmk
    :defer t
    :config
    (auctex-latexmk-setup))

  (when (fboundp 'adaptive-wrap-prefix-mode)
    (defun my-activate-adaptive-wrap-prefix-mode ()
      "Toggle `visual-line-mode' and `adaptive-wrap-prefix-mode' together,
                  and auto-fill-mode the opposite way."
      (adaptive-wrap-prefix-mode (if visual-line-mode 1 -1))
      (auto-fill-mode (if visual-line-mode -1 1)))
    (add-hook 'visual-line-mode-hook 'my-activate-adaptive-wrap-prefix-mode))

  (setq TeX-auto-save t)
  (setq TeX-parse-self t)
  (setq-default TeX-master nil)           ;
  ;; I think this is needed because the variable is not buffer local until Auctex is active
  (make-variable-buffer-local 'TeX-master)
  (setq reftex-plug-into-AUCTeX t)        ;
  (setq TeX-PDF-mode t)                   ; default processing to pdflatex
  (setq TeX-electric-sub-and-superscript t) ;Inserts {} automatically on _ and ^
  (setq TeX-save-query nil)               ; always save without asking when compiling

  ;; remove auto-fill
  (defun my/latex-hooks ()
    (my/turn-on 'visual-line         ; now turns off auto-fill
                'flyspell))
  (add-hook 'latex-mode-hook 'my/latex-hooks) ; needs testing!!!
  (add-hook 'latex-mode-hook 'turn-on-reftex) ; no -mode in the end

  ;; spell checking on LaTeX buffers
  ;;(add-hook 'latex-mode-hook 'flyspell-mode)
  (add-hook 'latex-mode-hook 'flyspell-buffer)

  (use-package latex-preview-pane
    :defer t)

  ;; latex-extra
  (use-package latex-extra
    :defer t
    :hook latex-mode)

  ;; cdlatex input for math
  (use-package cdlatex
    :defer t
    :disabled nil))

XML

I am using the builtin nXML mode for XML editing and turning off automatic line wrapping.

(defun my/nXML-hooks ()
  (auto-fill-mode -1))

(add-hook 'nXML-mode-hook 'my/nXML-hooks)

Zsh and fish

Zsh is a command line shell that is a superset of Bash. Tell emacs that its *.zsh config files are shell scripts. I use the pretzo configuration framework for it.

Fish, Friendly Interactive SHell, is faster and cleaner than Zsh, It is now my main interective shell. I use Oh My Fish! management framework for it.

(setq auto-mode-alist
      (cons '("\\.zsh$" . shell-script-mode) auto-mode-alist))
(use-package fish-mode
  :defer t
  :init (setq-default indent-tabs-mode nil)
  (add-hook 'fish-mode-hook
            (lambda ()
              (add-hook 'before-save-hook 'fish_indent-before-save))))

MarkDown

Github and especially BitBucket use markdown-mode for documentation, so my Emacs knows about it. GitHub knows how to render org-mode documents, too, so this mode is not getting much use. pandoc-mode is a general purpose export formatter and uses hydra C-c 4.

My org-mode is configured to export to markdown format.

(use-package pandoc-mode
  :bind ("C-c 4" . pandoc-main-hydra/body))

(use-package markdown-mode
  :mode  ("\\.md" "\\.markdown")
  :commands (markdown-mode gfm-mode)
  ;;:hook pandoc-mode
  :config
  (setq markdown-command "multimarkdown")
  (add-hook 'markdown-mode-hook 'pandoc-mode)
  (use-package markdown-preview-mode
    :hook markdown-mode))

See markdown-preview-mode.

Ledger

Ledger is a command line accounting program with strong emacs support.

The following tells ledger to use ISO dates and sets some default reports. There does not seem to be consensus on ledger file extension. I am using led.

The ledger mode has been getting a lot of bug fixes recently. These changes are affecting font coloring, too. Many of the font faces are inherited which are good in principle, but at the moment they clash badly. I try to set them back to somewhat calmer palette.

(use-package ledger-mode
  :mode "\\.led\\'"
  :interpreter "ledger"
  ;;:bind (:map ledger-mode-map
  ;;            ("M-m" . ledger-next-misc))
  :init
  ;; date format
  (setq ledger-use-iso-dates t)
  ;; reports
  (setq ledger-reports
        (quote (("test" "ledger ")
                ("bal" "ledger -f %(ledger-file) bal")
                ("reg" "ledger -f %(ledger-file) reg")
                ("payee" "ledger -f %(ledger-file) reg @%(payee)")
                ("account" "ledger -f %(ledger-file) reg %(account)"))))
  :config
  ;; font changes
  (set-face-attribute 'ledger-font-comment-face nil :foreground "gray50")
  (set-face-attribute 'ledger-occur-xact-face nil :inherit t :background "cornsilk")
  (set-face-attribute 'ledger-occur-xact-face nil :inherit t :background "LightCyan")

  (defun ledger-next-misc ()
    "Find next ledger Misc category."
    (interactive)
    (let ((tag "Misc"))
      (forward-char (length tag))
      (search-forward tag)
      (search-backward tag)
      (delete-char (length tag))))
  (bind-key "M-m" 'ledger-next-misc ledger-mode-map)

  (defun ledger-add-note ()
    "Add a note to the current ledger entry.

  Adds a new comment line starting with ' ; note: ' and places
  point to the end. The new line is always placed after other
  comments."
    (interactive)
    (ledger-navigate-beginning-of-xact)
    (let ((beg-of-xact (point)))
      (ledger-navigate-end-of-xact)
      (unless (re-search-backward "^ +;" beg-of-xact t)
        (goto-char beg-of-xact))
      (end-of-line)
      (insert "\n\t; note: ")
      (ledger-magic-tab)))
  (bind-key "M-." 'ledger-add-note ledger-mode-map))

;; flycheck-ledger does syntax checking
;;(eval-after-load 'ledger-mode '(require 'flycheck-ledger))

Ssh config

ssh-config-mode-el highlights valid keys in ssh configuration files.

(use-package ssh-config-mode
  :mode (("\\.ssh/config\\'"      . ssh-config-mode)
         ("/sshd?_config\\'"      . ssh-config-mode)
         ("/known_hosts\\'"       . ssh-known-hosts-mode)
         ("/authorized_keys2?\\'" . ssh-authorized-keys-mode))
  :bind (:map ssh-config-mode-map
              ("C-p" . ssh-config-host-prev)
              ("C-n" . ssh-config-host-next))
  :config
  (add-hook 'ssh-config-mode-hook 'turn-on-font-lock))

Programming

Shared programming tools

Make shebang files executable

This applies to any scripting language file that starts with a shebang: the code makes those files executable on saving.

(add-hook 'after-save-hook
          'executable-make-buffer-file-executable-if-script-p)

Aggressive indent mode

Malabarba/aggressive-indent-mode continuously updates indentation as you type. I’ve enabled this only on some programming languages.

(use-package aggressive-indent)

Flycheck

Flycheck does global syntax checking for most programming languages. See MasterEmacs for a good article. This code adds support for perl6.

avy-flycheck makes flyckeck to use avy interface and defines a key binding C-c t for finding next error.

proselint: A linter for prose emacs plugin is part of flycheck-package, but it needs the backend executable installed. It is written in python and can be installed with pip but I used brew install =proselint to get automatic updates. See also proselint.

Best used with flycheck-list errors (C-c ! l) that shows a linked pair of windows.

  (use-package flycheck
    :diminish ""
    :defer t
    :config
    (add-hook 'after-init-hook #'global-flycheck-mode)
    (use-package avy-flycheck
      :bind ("C-c t" . avy-flycheck-goto-error))
    (use-package flycheck-perl6
      :defer t))

  (use-package flycheck-proselint
    :disabled t    ;
    :ensure nil
    :defer t
    :after (flycheck)
    :config
    ;; org-mode added
    (flycheck-define-checker proselint
      "Flycheck checker using Proselint.

See URL `http://proselint.com/'."
      :command ("proselint" "--json" "-")
      :standard-input t
      :error-parser flycheck-proselint-parse-errors
      :modes (text-mode markdown-mode gfm-mode message-mode org-mode)))

Quickrun

quickrun-package makes it easy to run any buffer with code in it. I do not use system perl, so I redefine the perl command to use plenv-installed perl. As avid org user, I map C-c C-c to run quickrun in modes that use frequently.

(use-package quickrun
  :config
  (quickrun-add-command "perl"
    '((:command . "~/.plenv/shims/perl")
      '((:exec . ("%c -wc %s")))
      :override t))
  (quickrun-add-command "python"
    '((:command . "~/miniconda/bin/python")
      '((:exec . ("%c -wc %s")))
      :override t))
  (eval-after-load 'python-mode
    '(bind-key  "C-c C-c" 'quickrun python-mode-map))
  (eval-after-load 'cperl-mode
    '(bind-key  "C-c C-c" 'quickrun cperl-mode-map))
  (eval-after-load 'perl6-mode
    '(bind-key  "C-c C-c" 'quickrun perl6-mode-map)))

electric-operator

The electric-operator is an emacs minor mode to automatically add spacing around operators. There is no global mode, so it needs to be enabled for each programming language.

(use-package electric-operator
  :defer t)

dump-jump

To be tested:

Irreal keeps mentioning dumb-jump, the “jump to definition” package. It is a no configure, no stored indexes replacement to cumbersome TAGS. It supports a long list of programming languages.

It works within project folder structure.

(use-package dumb-jump
  :ensure t
  :bind (("M-g o" . dumb-jump-go-other-window)
         ("M-g j" . dumb-jump-go)
         ("M-g b" . dumb-jump-back)
         ("M-g q" . dumb-jump-quick-look)
         ("M-g x" . dumb-jump-go-prefer-external)
         ("M-g z" . dumb-jump-go-prefer-external-other-window))
  :config (setq dumb-jump-selector 'ivy))

Parens

I call show-paren-mode on several programming modes to highlight matching parens. Before it is turned on, the delay needs to made shorter:

(setq show-paren-delay 0)

Find missing and mismatching parens with check-parens.

Paredit

The most useful paredit key combinations use C-<arrow> that are taken by OS X to switch between desktops. Use the Cmd key (s for super in emacs), instead.

EmacsWiki: Paredit Cheatsheet gives a good overview of paredit keys. To fill in, a more comprehensive list of navigation keys are at EmacsWiki: Navigating Parentheses. Remember: C-M-{n|p|f|b}.

(use-package paredit
  :no-require t
  :if (eq system-type 'darwin)
  :bind (:map paredit-mode-map
              ;;("s-<left>" . paredit-forward-barf-sexp)
              ;;("s-<right>" . paredit-forward-slurp-sexp)
              ("M-s-<left>" . paredit-backward-slurp-sexp)
              ("M-s-<right>" . paredit-backward-barf-sexp)))

Eglot, Emacs PolyGlot

joaotavora/eglot: A client for Language Server Protocol servers

Needs emacs 26!

(use-package eglot)

Needs language specific servers. Installed:

+ palantir/python-language-server: An implementation of the Language Server Protocol for Python

Perl

I recently moved from perlbrew to plenv as a system that provides user controlled perl environment that is separate from vendor perl.

For OS X, install plenv with brew install plenv; brew install perl-build and install your favorite version of perl and put into plenv-global below.

(use-package plenv
  :defer t
  :config
  (condition-case nil
      (plenv-global "5.22.1")
    (error (message "ERROR: unknown perl version. Is your plenv configured right?")))
  (use-package flymake
    :defer t
    :config
    (defun flymake-perl-init ()
      (let* ((temp-file (flymake-init-create-temp-buffer-copy
                         'flymake-create-temp-with-folder-structure))
             (local-file (file-relative-name
                          temp-file
                          (file-name-directory buffer-file-name))))
        (list (guess-plenv-perl-path) (list "-wc" local-file))))

    (push '(".+\\.p[ml]$" flymake-perl-init) flymake-allowed-file-name-masks)
    (push '(".+\\.psgi$" flymake-perl-init) flymake-allowed-file-name-masks)
    (push '(".+\\.t$" flymake-perl-init) flymake-allowed-file-name-masks)))

Use the built-in cperl-mode instead of the default perl-mode

(use-package cperl-mode
  :mode "\\.\\([pP][Llm]\\|al\\)\\'"
  :interpreter ("perl" "perl5" "miniperl")
  :init
  (setq cperl-indent-level 4
        cperl-close-paren-offset -4
        cperl-continued-statement-offset 4
        cperl-indent-parens-as-block t
        cperl-tab-always-indent t)
  :config
  (defun my/cperl-mode-hook ()
    (my/turn-on 'show-paren
                'abbrev
                'electric-pair
                'electric-operator
                'aggressive-indent))
  (add-hook 'cperl-mode-hook 'my/cperl-mode-hook t))

Call perltidy with C-c t from emacs to indent and beautify perl code in the current buffer. This code calls the command line perltidy utility that is part of Perl::Tidy CPAN module.

The C-c t key for perltidy is defined in the most efficient way: the code is loaded only once when the cperl-mode is first called.

(defun perltidy ()
  "Run perltidy on the current region or buffer."
  (interactive)
                                        ; Inexplicably, save-excursion doesn't work here.
  (let ((orig-point (point)))
    (unless mark-active (mark-defun))
    (shell-command-on-region (point) (mark) "perltidy -q" nil t)
    (goto-char orig-point)))

(eval-after-load 'cperl-mode
  '(bind-key  "C-c t" 'perltidy cperl-mode-map))

perl6

The major mode will be autoloaded whenever a Perl 6 file is visited. This includes any file with perl6 in the shebang, as well as any file with a .p6, .pm6, or .pl6 extension. It also applies to any .pm, .pl, and .t files whose first line of code looks like Perl 6.

(use-package perl6-mode
  :defer t)

Call pod-mode on POD documentation files and enable spell checking.

The pod-mode is outdated and needs to be manually installed to the Custom lisp package directory from its CPAN repository.

(use-package pod-mode
  :disabled t
  :ensure nil
  :mode ("\\.pod\\'" . pod-mode)
  :config
  (add-hook 'pod-mode-hook
            '(lambda ( )
               (progn (font-lock-mode)   ; = syntax highlighting
                      (auto-fill-mode 1) ; = wordwrap
                      (flyspell-mode 1)  ; = spellchecking
                      ))))

Lisps

For lisp code, I want ParEdit and realtime “aggressive” indenting. ElDoc shows arguments to function under cursor in the minibuffer.

(setq my/lisps
      '(emacs-lisp lisp clojure extempore racket lisp-interaction))

(defun my/general-lisp-hooks ()
  (my/turn-on 'paredit
              'rainbow-delimiters
              'electric-pair
              'show-paren
              'aggressive-indent
              'eldoc
              'abbrev
              ;;'highlight-parentheses
              ))
(dolist (mode (mapcar 'my/->mode-hook my/lisps))
  (add-hook mode
            'my/general-lisp-hooks))

Racket

greghendershott/racket-mode: GNU Emacs major modes for Racket: Edit and REPL.

Pollen, the racket pbook publishing, needs a special character for marking command lines. The chosen character is lozenge .

(use-package racket-mode
  :init
  (add-hook 'racket-mode-hook      #'racket-unicode-input-method-enable)
  (add-hook 'racket-repl-mode-hook #'racket-unicode-input-method-enable))

;; global binding
(bind-key  "M-\\" "")

Names

In my emacs lisp programming I am using the Names package that enables namespaces. The following sets up debugging tools to recognize these namespaces:

(use-package names
  :defer t)

PENDING Nameless

Nameless is an alternative to Names. The elisp text file is not in any way different from normal, but this minor mode hides the name space and replaces it with :. C-c C-- adds the namespace when the mode is on.

(use-package nameless
  :hook emacs-lisp-mode)

Macrostep

Now that I am using use-package macro to configure packages, it is useful to see what the configuration macro actually does. Macrostep package defines keys to expand and collapse macros one level at a time. Run macrostep-expand with C-c m.

KeysDescription
e, =, RETexpand
c, u, DELcollapse
q, C-c C-ccollapse all and exit
n, TABnext macro
p, M-TABprevious macro
(use-package macrostep
  :bind ("C-c M" . macrostep-expand))

Suggest

The suggest.el shows common elisp functions that produce a given output from given input. Start it with M-x suggest.

(use-package suggest)

ielm

ielm is a REPL for elips that is built in emacs. See Evaluating Elisp in Emacs - Mastering Emacs for more.

(use-package auto-complete
  :hook ielm-mode
  :config
  (defun ielm-auto-complete ()
    "Enables `auto-complete' support in \\[ielm]."
    (setq ac-sources '(ac-source-functions
                       ac-source-variables
                       ac-source-features
                       ac-source-symbols
                       ac-source-words-in-same-mode-buffers))
    (add-to-list 'ac-modes 'inferior-emacs-lisp-mode)
    (auto-complete-mode 1)))

Flycheck-package

flycheck-package is a Flycheck checker for elisp package metadata.

(use-package flycheck-package)

Needed only occationally, so better run manually on the buffer to check: flycheck-package-setup.

eros

Minor mode for Evaluation Result OverlayS for Emacs Lisp. Shows ==C-x C-e= elisp evaluations at point. Set on by default, toggle with hydra C-x t e. Simply ingenious!

(use-package eros
  :config
  (eros-mode 1))

SQL

Automatically uppercase SQL keywords in sql-mode.

(use-package sqlup-mode
  :hook sql-mode)

Clojure

I’m using CIDER for clojure source/repl interaction. Start it with incantation “Emacs, launch cider” C-x l c.

Cider installation requires that the current version =M-x cider-version=is passed through leiningen to clojure. Minimal file:~/.lein/profiles.clj file:

{:user {:plugins [[cider/cider-nrepl "0.11.0"]]}}

I treat the REPL mode specially, since certain hooks that work in clojure-mode won’t make sense or break functionality in cider-repl-mode. See here for more configuration options.

Meta-up and -down to move in the REPL history are taken by paredit, so I bind the functions to Command (Super) key: s-up> and s-down.

(use-package cider
  :disabled t
  :defer t
  :init (add-hook 'cider-mode-hook #'clj-refactor-mode)
  :config
  (setq nrepl-log-messages t
        cider-repl-display-in-current-window t
        cider-repl-use-clojure-font-lock t
        cider-prompt-save-file-on-load 'always-save
        cider-font-lock-dynamically '(macro core function var)
        nrepl-hide-special-buffers t
        cider-overlays-use-font-lock t)
  (cider-repl-toggle-pretty-printing)

  (defun my/cider-repl-mode-hooks ()
    (my/turn-on 'paredit
                ;;'rainbow-delimiters
                'show-paren
                'highlight-parentheses))

  (add-hook 'cider-repl-mode-hook
            'my/cider-repl-mode-hooks)

  (use-package clj-refactor
    :defer t
    :diminish ""
    :config (cljr-add-keybindings-with-prefix "C-c C-m"))

  ;; M-up -> s-up
  (bind-key "s-<up>" 'cider-repl-previous-input cider-repl-mode-map)
  ;; M-down -> s-down
  (bind-key "s-<down>" 'cider-repl-next-input cider-repl-mode-map))

Web mode

(use-package web-mode
  :mode (("\\.html\\'" . web-mode)
         ("\\.html\\.erb\\'" . web-mode)
         ("\\.mustache\\'" . web-mode)
         ("\\.php\\'" . web-mode))
  :init
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-code-indent-offset 2)
  (setq web-mode-css-indent-offset 2)

  (setq web-mode-enable-auto-pairing t)
  (setq web-mode-enable-auto-expanding t)
  (setq web-mode-enable-css-colorization t)

  (setq web-mode-enable-current-element-highlight nil)
  (setq web-mode-enable-current-column-highlight nil))

Also, check out emmet-mode.

PENDING Python

Python setup is copied from here. Work in progress.

First make sure you have installed your python dependencies runtime environment:

pip install elpy
pip install rope
pip install jedi
(add-to-list 'auto-mode-alist '("/requirements\\.txt\\'" . conf-mode))

;;     (use-package python-mode
;;       :mode ("\\.py\\'" . python-mode)
;;       :interpreter ("python" . python-mode)
;;       :config
;;       (progn
;;         (defvar python-mode-initialized nil)
;;
;;         (defun my-python-mode-hook ()
;;           (unless python-mode-initialized
;;             (setq python-mode-initialized t)
;;
;;             (info-lookup-add-help
;;              :mode 'python-mode
;;              :regexp "[a-zA-Z_0-9.]+"
;;              :doc-spec
;;              '(("(python)Python Module Index" )
;;                ("(python)Index"
;;                 (lambda (item)
;;                   (cond
;;                    ((string-match
;;                      "\\([A-Za-z0-9_]+\\)() (in module \\([A-Za-z0-9_.]+\\))" item)
;;                     (format "%s.%s" (match-string 2 item)
;;                             (match-string 1 item)))))))))
;;
;;           (setq indicate-empty-lines t)
;;           (set (make-local-variable 'parens-require-spaces) nil)
;;           (setq indent-tabs-mode nil)
;;
;;           (bind-key "C-c C-z" 'python-shell python-mode-map)
;;           (unbind-key "C-c c" python-mode-map))
;;
;;         (add-hook 'python-mode-hook 'my-python-mode-hook)))

(use-package elpy
  :init
  (elpy-enable))

(defun my/setup-python-mode ()
  "Custom command to setup python-mode"
  (interactive)
  (let ((max-column 99))
    (setq python-shell-interpreter "~/miniconda3/bin/python"
          python-shell-interpreter-args "-i"
          ;;venv-location "~/.virtualenvs"
          whitespace-line-column max-column
          fill-column max-column
          flycheck-flake8-maximum-line-length max-column
          elpy-rpc-backend "jedi"
          ;;elpy-rpc-backend "rope"
          ;;elpy-default-minor-modes '(eldoc-mode)
          elpy-rpc-project-specific t))
  (setq python-indent-offset 4)
  (setq jedi:complete-on-dot t)
  (flycheck-mode)
  ;;(pyenv-mode)
  ;;(add-hook 'focus-out-hook 'save-buffer)
  ;;(highlight-lines-matching-regexp "import i?pdb")
  ;;(highlight-lines-matching-regexp "i?pdb.set_trace()")
  (turn-on-fci-mode)  ; fill-column-indicator
  (elpy-enable)
  ;;(elpy-mode)
  ;;(elpy-clean-modeline)
  (highlight-indentation-mode))

(add-hook 'python-mode-hook 'my/setup-python-mode)
(add-hook 'python-mode-hook 'jedi:ac-setup)
(add-hook 'python-mode-hook (lambda ()
                              (use-package sphinx-doc
                                :defer t
                                :config
                                (sphinx-doc-mode t))))

Sphinx-doc adds a function inserting docstring skeleton for Python functions and methods. Inside a Python file move the cursor to some function/method definition and hit C-c M-d.

PENDING C++

This is just causing warnings. Disabled.

;; Use the GDB visual debugging mode
(setq gdb-many-windows t)
;; Turn Semantic on
;;(require 'semantic/sb)
(semantic-mode 1)
;; Try to make completions when not typing
(global-semantic-idle-completions-mode 1)
;; Use the Semantic speedbar additions
;; (add-hook 'speedbar-load-hook
;;           (lambda () (use-package semantic/sb :defer t)))
;; treat .h files as C++ files (instead of C)
(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
;; Run compile when you press F5
;;(global-set-key (kbd "<f5>") #'compile)

PENDING go

See dotemacs/go-config.el

(defun load-file-from-gopath (fname)
  (let ((gopath-items (split-string (getenv "GOPATH") ":")))
    (loop for prefix in gopath-items
          if (file-exists-p (concat prefix "/src/" fname))
          return (load-file (concat prefix "/src/" fname)))))

(defun load-file-from-gopath-or-download (pkg file)
  (let ((fname (concat pkg "/" file)))
    (unless (load-file-from-gopath fname)
      (progn
        (mkdir pkg)
        (shell-command (format "go get -u %s" pkg)))
      (load-file-from-gopath fname))))

(use-package company :defer t)

(use-package company-go
  :defer t
  :config (setq company-go-show-annotation t))

(use-package go-mode
  :config
  ;;(load-file-from-gopath-or-download "goflymake" "go-flymake.el")
  ;;(load-file-from-gopath-or-download "lint" "misc/emacs/golint.el")

  (bind-key "M-." 'godef-jump go-mode-map)

  (use-package go-flymake
    :disabled t
    :defer t
    :config
    ;; Use goimports instead of go-fmt
    (setq gofmt-command "goimports")
    ;; Call Gofmt before saving
    (add-hook 'before-save-hook 'gofmt-before-save t)

    ;; Customize compile command to run go build
    (if (not (and (stringp compile-command)
                  (string-match "go" compile-command)))
        (set (make-local-variable 'compile-command)
             "go build -v && go test -v && go vet && golint")))

  (use-package go-eldoc
    :defer t
    :config (go-eldoc-setup)))

Applescript

Apples-mode is a major mode for applescript.

(use-package apples-mode
  :defer t)

TOML

toml-mode is a major mode for the TOML configuration language.

(use-package toml-mode
  :defer t)

YAML

yaml-mode is a major mode for the YAML data language.

(use-package yaml-mode
  :defer t)

Music

PENDING alda

alda - A music programming language for musicians. Needs binary installed first.

(use-package alda-mode
  :defer t
  :ensure-system-package alda
  :config
  (eval-after-load 'alda-mode
    '(bind-key  "C-c C-c" 'alda-play-region alda-mode-map)))

Extempore

Audio programming environment, extempore, has its own major mode.

(use-package extempore-mode
  :defer t)

Auto complete

Getting auto completion to work right tends to be a messy process of trial and error, though in recent years the situation has improved, with auto-complete mode being more or less the de facto standard.

  • Fuzzy matching might work in unexpected ways.
    (use-package fuzzy
      :defer t)
    
    (use-package auto-complete
      :defer t
      :init (setq ac-auto-show-menu t
                  ac-quick-help-delay 0.5
                  ac-use-fuzzy t)
      :config (global-auto-complete-mode +1))
        

Navigation

Window management

Emacs has its own terminology where operating system windows are called frames, and each independent pane inside frames are called windows.

Windows display buffers that exist inside emacs independently.

You can manage the number of windows in the frame with four commands:

C-x 1
keep only this window
C-x 2
split current window horizontally
C-x 3
split current window vertically
C-x 0
close this window

First, I boost standard window splitting commands according Sacha’s configuration to show previous buffer in the new window.

(defun my/vsplit-last-buffer (prefix)
  "Split the window vertically and display the previous buffer."
  (interactive "p")
  (split-window-vertically)
  (other-window 1 nil)
  (if (= prefix 1)
      (switch-to-next-buffer)))

(defun my/hsplit-last-buffer (prefix)
  "Split the window horizontally and display the previous buffer."
  (interactive "p")
  (split-window-horizontally)
  (other-window 1 nil)
  (if (= prefix 1) (switch-to-next-buffer)))

(bind-key "C-x 2" 'my/vsplit-last-buffer)
(bind-key "C-x 3" 'my/hsplit-last-buffer)

Multiple windows’ relative positions can be managed with the Transpose Frame package. It defines four commands:

transpose-frame
Swap x-direction and y-direction
flip-frame
Flip vertically
flop-frame
Flop horizontally
rotate-frame
Rotate 180 degrees
(use-package transpose-frame
  :defer t)

The only missing piece is provided by the crux package: crux-transpose-windows swaps two adjacent windows with each other.

(bind-key "C-c s" 'hydra-windows/body)
(defhydra hydra-windows (:color blue :hint nil)
  "
  Windows  ^Manage^                            ^Order^
  --------------------------------------------------------------------------------------------
           _1_ : C-x 1 keep only this window   _t_ : transpose windows
           _2_ : C-x 2 split horizontally
           _3_ : C-x 3 split vertically        _u_ : transpose frame - swap x- and y-direction
           _0_ : C-x 0 close this window       _i_ : flip frame - Flip vertically
           ^ ^                                 _o_ : flop frame - Flop horizontally
           ^ ^                                 _r_ : rotate frame - Rotate 180 degrees
           ^ ^                                 _x_ : rotate-frame-clockwise - Rotate 90 degrees clockwise
           ^ ^                                 _y_ : rotate-frame-anti-clockwise - Rotate 90 degrees anti-clockwise
 "
  ("1" delete-other-windows)
  ("2" my/vsplit-last-buffer)
  ("3" my/hsplit-last-buffer)
  ("0" delete-window)

  ("t" crux-transpose-windows)

  ("u" transpose-frame)
  ("i" flip-frame)
  ("o" flop-frame)
  ("r" rotate-frame)
  ("x" rotate-frame-clockwise)
  ("y" rotate-frame-anticlockwise))

The built-in winner-mode defines Ctrl+c ← to go back to previous window configuration. Elsewhere, It is enabled globally with (winner-mode 1).

Eyebrowse

Eyebrowse is for easy workspaces creation and switching. Configuration from Easily manage Emacs workspaces with eyebrowse | Pragmatic Emacs.

The default key bindings are:

KeyFunction on
bindingwindow config
C-c C-w <Switch to previous
C-c C-w >Switch to next
C-c C-w ’Switch to last
C-c C-w ”Close current
C-c C-w ,Rename current
C-c C-w 0Switch to 0
C-c C-w 9Switch to 9

Note: My custom mode line does not show the names of workspaces.

(use-package eyebrowse
  :diminish eyebrowse-mode
  :bind (:map eyebrowse-mode-map
              ("C-1" . eyebrowse-switch-to-window-config-1)
              ("C-2" . eyebrowse-switch-to-window-config-2)
              ("C-3" . eyebrowse-switch-to-window-config-3)
              ("C-4" . eyebrowse-switch-to-window-config-4))
  :init
  (setq eyebrowse-new-workspace t
        eyebrowse-mode-line-separator " ")
  :config
  (eyebrowse-mode t))

Local navigation in a buffer

John Kitchin’s navigation hydra is a starting point to combine almost all navigation tasks:

(global-subword-mode +1)
;; (diminish 'subword-mode)
(defhydra hydra-navigate (:color red
                                 :hint nil)
  "
_f_: forward-char       _w_: forward-word       _n_: next-line
_b_: backward-char      _W_: backward-word      _p_: previous-line
^ ^                     _o_: subword-right      _,_: beginning-of-line
^ ^                     _O_: subword-left       _._: end-of-line

_s_: forward sentence   _a_: forward paragraph  _g_: forward page
_S_: backward sentence  _A_: backward paragraph _G_: backward page

_r_: recent files _B_: buffer list
_<left>_: previous buffer   _<right>_: next buffer
_<up>_: scroll-up           _<down>_: scroll-down

_[_: backward-sexp _]_: forward-sexp
_<_ beginning of buffer _>_ end of buffer _m_: set mark _/_: jump to mark
"

  ("f" forward-char)
  ("b" backward-char)
  ("w" forward-word)
  ("W" backward-word)
  ("n" next-line)
  ("p" previous-line)
  ("o" subword-right)
  ("O" subword-left)
  ("s" forward-sentence)
  ("S" backward-sentence)
  ("a" forward-paragraph)
  ("A" backward-paragraph)
  ("g" forward-page)
  ("G" backward-page)
  ("<right>" next-buffer)
  ("<left>" previous-buffer)
  ("r" recentf-open-files :color blue)
  ("m" org-mark-ring-push)
  ("/" org-mark-ring-goto :color blue)
  ("B" list-buffers)
  ("<up>" scroll-down)
  ("<down>" scroll-up)
  ("<" beginning-of-buffer)
  (">" end-of-buffer)
  ("." end-of-line)
  ("[" backward-sexp)
  ("]" forward-sexp)
  ("," beginning-of-line)
  ("q" nil "quit" :color blue))
(bind-key "M-n" 'hydra-navigate/body)

Delete a word at a time: M-backspace.

Kill line backward from cursor is C-0 C-k but it easier to remember when redefined as C-backspace. s-backspace does the same thing, but calling crux-kill-line-backwards.

(bind-key "C-<backspace>"
          #'(lambda () (interactive)
              (kill-line 0)))

The most complex replace key combination made little bit easier to remember:

(defalias 'qrr 'query-replace-regexp)  ; M-C-S %

Folding uses set-selective-display to show a high level outline of you document. Useful to get an overview of long code documents. Launch it with C-x t f.

;; folding of code
;; http://emacs.wordpress.com/2007/01/16/quick-and-dirty-code-folding/
(defun toggle-selective-display ()
  (interactive)
  (set-selective-display (if selective-display nil 1)))

Key M-j joins the next line with the current one. Copied from WhatTheEmacs!? The is an alternative to M-^ or C-c q for joining current line to previous one.

(bind-key  "M-j"  #'(lambda ()
                      (interactive)
                      (join-line -1)))
(bind-key "C-c q" 'delete-indentation)

When editing indented text, you seldom want to go to the first column of the line. Instead the following modifies C-a to move point back to indentation of beginning of line. Copied from Emacs Redux. Now in crux: A Collection of Ridiculously Useful eXtensions for Emacs.

Note: I need to use more crux commands.

Move point to the first non-whitespace character on this line. If point is already there, move to the beginning of the line. Effectively toggle between the first non-whitespace character and the beginning of the line.

(use-package crux
  :bind (("C-a" . crux-move-beginning-of-line)
         ("C-x 4 t" . crux-transpose-windows)
         ("s-d" . crux-duplicate-current-line-or-region)
         ("s-D" . crux-duplicate-and-comment-current-line-or-region)
         ("s-r" . crux-rename-file-and-buffer)
         ("s-R" . rename-buffer)
         ("s-b" . crux-open-with)
         ("s-O" . crux-smart-open-line-above)
         ("s-o" . crux-smart-open-line)))

Going to end of buffer with M-> involves keeping the shift-key down on my American Apple keyboard. I quite often miss the option key and press the command key instead. It turns out shift is not recognized together with the command key, so I create a key binding for s-. to move to end of the buffer. Logically, =s-,= then moves to the beginning of the buffer.

Code from Enhanced beginning- and end-of-buffer in special mode buffers (dired etc.) replaced by DamienCassou/beginend: Emacs package to redefine M-< and M-> for some modes

(bind-key "s-." 'end-of-buffer)
(bind-key "H-." 'end-of-buffer)
(bind-key "s-," 'beginning-of-buffer)
(bind-key "H-," 'beginning-of-buffer)

(use-package beginend
  :config
  (beginend-global-mode))

Bookmarks

Visible bookmarks from bm package are made easy with a hydra. I am running out of keys, so this time the incantation is “Emacs, launch bookmarks” for C-c x.

Bookmarks can be made persistent with (setq-default bm-buffer-persistence t), but the whole setup is quite complicated. You might as well start using Bookmark Plus, instead.

(use-package bm
  :init
  (setq bm-in-lifo-order t)
  (setq bm-cycle-all-buffers t)
  (setq bm-highlight-style 'bm-highlight-only-fringe)
  (setq bm-marker 'bm-marker-left)
  :bind
  (("C-c x" . hydra-bookmark/body))
  ("<left-fringe>" . bm-next-mouse)
  ("<left-fringe>" . bm-previous-mouse)
  ("<left-fringe>" . bm-toggle-mouse)
  (" <mouse-5>" . bm-next-mouse)
  (" <mouse-4>" . bm-previous-mouse)
  (" <mouse-1>" . bm-toggle-mouse)
  :config
  (defhydra hydra-bookmark (:color blue :hint nil)
    "
     bookmark   |   Add^^          Move^^         Manage
  ----------------------------------------------------------------
                    _t_: toggle    _n_: next      _s_: show local
                    _y_: add temp  _p_: previous  _S_: show all
                    _r_: regexp    ^ ^            _x_: remove local
                    ^ ^            ^ ^            _X_: remove all
                "
    ("t" bm-toggle)
    ("n" bm-next :color red)
    ("p" bm-previous :color red)
    ("y" (bm-bookmark-add nil nil t))
    ("r" bm-bookmark-regexp)
    ("s" bm-show)
    ("S" bm-show-all)
    ("x" bm-remove-all-current-buffer)
    ("X" bm-remove-all-all-buffers)))

Searching

Swiper is a replacement for isearch that faster and easier to configure. I bind it to isearch key, C-s. To complete current word to swiper minibuffer, press M-j. Isearch is still usable with C-`. It is especially good for searching European 8-bit characters with ASCII keyboard: just use the ASCII equivalent keys.

Current window layout can now be saved with ivy once virtual buffers are enabled with C-c v. Normal switch-buffer C-x b shows layouts with a {} tag prepended. Really easy!

Also, the ivy-enhanced switch-buffer command lists recently opened files (recentf).

While the default emacs history list can be accessed by the arrow up and down keys, ivy makes you use M-p and M-n for it.

I have bound commands ivy-push-view and ivy-pop-view to C-c b and C-c B, respectively.

Counsel also nicely boosts yanking from kill-ring history that is now set to M-y.

More in Ivy User Manual.

Also, save system clipboard before overwriting it from emacs (Prevent Emacs wiping the system clipboard | Pragmatic Emacs).

counsel-imenu is bound to ‘s’ in worf mode.

ivy-occur, see Save Ivy file completions to Dired · (or emacs

Save Ivy file completions to Dired · (or emacs: ivy-occur is now bound to C-c C-o so that it can be launched from any mini buffer where ivy is active. Ivy version 0.10.0 added C-d to remove unwanted lines from the occur buffer before applying wgrep editing on it with C-x C-q.

Using exclusion patterns when grepping · (or emacs gives details on how to configure counsel-git and counsel-rg.

(setq save-interprogram-paste-before-kill t)

(use-package ivy
  :ensure counsel
  :diminish (ivy-mode . "")
  :init
  (setq ivy-use-virtual-buffers t) ; Enable bookmarks and recentf in buffer list
  (setq enable-recursive-minibuffers t)
  (setq ivy-display-style 'fancy)
  (setq ivy-height 10)
  (setq ivy-count-format "(%d/%d) ")
  (setq ivy-use-selectable-prompt t)
  (setq ivy-switch-buffer-faces-alist
        '((emacs-lisp-mode . swiper-match-face-1)
          (dired-mode . ivy-subdir)
          (setq counsel-git-cmd "rg --files")
          (setq counsel-rg-base-command
                "rg -i -M 120 --no-heading --line-number --color never %s .")
            (org-mode . org-level-4)))
    :bind (("C-s"     . swiper)
           ("C-c C-r" . ivy-resume)
           ("M-x"     . counsel-M-x)
           ("C-c C-o" . ivy-occur)
           ("C-c b"   . ivy-push-view)
           ("C-c B"   . ivy-pop-view)
           ("M-y"     . counsel-yank-pop)
           ("s-f"     . counsel-git)
           ("s-g"     . counsel-rg)
           ("C-M-s"   . avy-goto-char-timer)
           :map ivy-minibuffer-map
           ("M-y" . ivy-next-line))
    :config
    (ivy-mode 1)

    (setq ivy-re-builders-alist
          ;; allow regex input not in order
          '((t   . ivy--regex-ignore-order)))

    (setq ivy-use-selectable-prompt t)

    ;; allow editing of occur buffers
    (use-package wgrep)

    (custom-set-faces
     '(swiper-minibuffer-match-face-1
       ((t :background "#dddddd")))
     '(swiper-minibuffer-match-face-2
       ((t :background "#bbbbbb" :weight bold)))
     '(swiper-minibuffer-match-face-3
       ((t :background "#bbbbff" :weight bold)))
     '(swiper-minibuffer-match-face-4
       ((t :background "#ffbbff" :weight bold))))
    )
  ;; advice swiper to recenter on exit
  ;; from http://pragmaticemacs.com/emacs/dont-search-swipe/
  ;;(defun my/swiper-recenter (&rest args)
  ;;  "recenter display after swiper"
  ;;  (recenter))
  ;;(advice-add 'swiper :after #'my/swiper-recenter))
  ;; ; (advice-remove 'swiper #'my/swiper-recenter)
  ;; end of use-package
  ;; (fmakunbound 'my/swiper-recenter)


  ;; restore key bindings to isearch due to character folding in emacs 25.1
  (bind-key "C-`" 'isearch-forward)
  (bind-key "C-r" 'isearch-backward)

  ;; Isearch convenience, space matches anything (non-greedy)
  (setq search-whitespace-regexp ".*?")

  ;; http://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.htmlh
  ;; This will only leave point at the start of search if you exit the
  ;; search with C-↵ instead of ↵.
  (define-key isearch-mode-map [(control return)]
    #'isearch-exit-other-end)
  (defun isearch-exit-other-end ()
    "Exit isearch, at the opposite end of the string."
    (interactive)
    (isearch-exit)
    (goto-char isearch-other-end))

Yet an other alternative way to search using avy.

(use-package avy
  :bind (("M-s" . avy-goto-word-1)
         ("C-c C-j" . avy-resume)))

TRAMP mode

TRAMP mode allows opening remote files. It knows about ssh and aliases defined in the ssh config file. You can even use tab completion. Setting the default method frees you from typing it. Just open file, give ‘/’, and start typing the name of the remote computer.

(setq tramp-default-method "ssh")

Projects

Projectile automatically defines a project for any git repository. It indexes files and makes it possible to search files and contents within a project. See it’s list of commands with C-c p C-h and more commands from the project wiki.

Tex linter from flycheck disables projectile loading. Fix: (setq flycheck-disabled-checkers nil) and then M-x flycheck-buffer.

counsel-projectile: Ivy UI for Projectile adds more ivy functionality to it.

  (use-package projectile
    :defer t
    :diminish ""
    :init
    (setq projectile-completion-system 'ivy)
    (setq projectile-file-exists-remote-cache-expire nil)
    :config
    (projectile-mode))

    (use-package counsel-projectile
      :defer t
      :after projectile
      ;;:defines counsel-projectile-on
      ;;:functions counsel-projectile-on ; silence warnings
      :config
    ;;  (counsel-projectile-on)
)

Narrowing

Narrowing is a way for emacs to hide part of the buffer so that only visible parts can be viewed and edited. This has the potential to be so confusing to an unsuspecting user that this feature is disabled by default. It has to be explicitly turned on.

(put 'narrow-to-region 'disabled nil)

Emacs-Fu has a well written article on narrowing. EmacsWiki is worth checking for caveats.

VisibleFunctionBinding
region(narrow-to-region)C-x n n
subtree(narrow-to-subtree)C-x n s
all(widen)C-x n w

The Endless Parentheses blog defines function how to toggle narrow and widen. You just do the incantation “Emacs, toggle narrowing” by pressing C-x t n!

(defun narrow-or-widen-dwim (p)
  "Widen if buffer is narrowed, narrow-dwim otherwise.
   Dwim means: region, org-src-block, org-subtree, or defun,
   whichever applies first. Narrowing to org-src-block actually
   calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer is
already narrowed."
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((region-active-p)
         (narrow-to-region (region-beginning) (region-end)))
        ((derived-mode-p 'org-mode)
         ;; `org-edit-src-code' is not a real narrowing
         ;; command. Remove this first conditional if you
         ;; don't want it.
         (cond ((ignore-errors (org-edit-src-code))
                (delete-other-windows))
               ((ignore-errors (org-narrow-to-block) t))
               (t (org-narrow-to-subtree))))
        ((derived-mode-p 'latex-mode)
         (LaTeX-narrow-to-environment))
        (t (narrow-to-defun))))

Multiple views

To have an other view into the same buffer run clone-indirect-buffer-other-window or C-x 4 c. This is great if you need to keep an outline in the first window and narrow to one section in the other.

DocView

DocView is for displaying PDF and other document files. It works by creating an PNG image for each page of the document. Arrow keys work within a page. Pressing n or <SPC> moves forward, and p or <DEL> change the page. I set the mouse wheel to scroll over pages, too.

(setq doc-view-continuous nil)

Navigation between windows and frames

Emacs standard way of moving between windows opened in a frame is C-x o. It jumps the cursor through all windows one by one and can not move between frames. I like to have a bit more control and use the built in windmove package augmented with framemove. With them, shift-<arrow> moves the focus to any window and even does wraparound.

While framemove provides a consistent interface to moving focus, do not forget that Emacs behaves exactly like any other application with multiple windows: you move between frames (windows belonging to the same application) using OS specific keys. On OS X, this is ⌘-`.

The package description for windmove is good place to start reading about it:

;; execute this lisp code in org mode by placing
;; the curser after the closing parenthesis and press C-x C-e
(describe-package 'windmove)

I need to tell org-mode to allow the windmove commands where it does not use them for its own purposes. These commands work outside headers and lists and has to be called after org-mode (see below).

(use-package framemove
  :defer t)

(windmove-default-keybindings)
(setq windmove-wrap-around t)
(setq framemove-hook-into-windmove t)

;; Make windmove work in org-mode:
(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)

wn-mode

Let’s try yet an other package wn-mode to change between windows.

Each window within the active frame gets a number that is indicated in the mode line among the minor modes. M-1 and so on move point to that window.

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

Resize windows

Buffer windows within frames can be resized but the default keys are cumbersome. I have mapped these commands to Apple command key-arrow key combinations for ease of use in my Apple laptop.

(setq my/window-resize-step 10)

(bind-key "s-<left>"
          (lambda () (interactive)
            (shrink-window-horizontally my/window-resize-step)))
(bind-key "s-<right>"
          (lambda () (interactive)
            (enlarge-window-horizontally my/window-resize-step)))
(bind-key "s-<down>"
          (lambda () (interactive)
            (shrink-window my/window-resize-step)))
(bind-key "s-<up>"
          (lambda () (interactive)
            (enlarge-window my/window-resize-step)))

External navigation

This allows you to google the selected region from local emacs buffer. Defines function google.

(defun google ()
  "Google the selected region if any, display a query prompt otherwise."
  (interactive)
  (browse-url
   (concat
    "http://www.google.com/search?ie=utf-8&oe=utf-8&q="
    (url-hexify-string (if mark-active
                           (buffer-substring (region-beginning) (region-end))
                         (read-string "Google: "))))))

Global navigation

This org configuration file has a shortcut C-c e.

This and more files can be reached with my hydra-files by C-z.

(defun my/edit-emacs-configuration ()
  "Open the main emacs configuration file."
  (interactive)
  (find-file "~/.emacs.d/emacs.org"))
(bind-key "C-c e" 'my/edit-emacs-configuration)

;; I often want to add more comments to the last note
(defun my/last-captured-org-note ()
  "Move to the last line of the last org capture note."
  (interactive)
  (find-file "~/Dropbox/org/reference.org")
  (goto-char (point-max)))

(bind-key "C-c z" 'hydra-goto/body)
(defhydra hydra-goto (:color blue :hint nil)
  "
       goto   buffer                                          info
              -----------------------------------------------------
              _c_hangeLog     _r_eference.org: last note      _o_rg
              _e_macs.org     _s_cratch
              _d_otfiles.txt  _w_ork.org
              _h_ome.gpg      _l_edger:refile.led
              _a_bbrevs             _k_äyttötili.led
           "
  ("c" (find-file "~/Dropbox/installation.notes/balamac/ChangeLog"))
  ("e" (find-file "~/.emacs.d/emacs.org"))
  ("d" (find-file "~/Dropbox/dotfiles/dotfiles.txt"))
  ("h" (find-file "~/Documents/documents/details/home.gpg"))
  ("r" my/last-captured-org-note)
  ("s" (switch-to-buffer "*scratch*"))
  ("w" (find-file "~/Dropbox/org/work.org"))
  ("l" (find-file "~/Documents/ledger/refile.led"))
  ("k" (find-file "~/Documents/ledger/2018_heikintili.led"))
  ("a" (find-file "~/.emacs.d/abbrev_defs"))
  ("o" org-info))

NeoTree is a file browser plugin that I am trying out. Toggle its panel: Emacs, Toggle neoTree C-x t t.

(use-package neotree
  :defer t
  :custom
  (neo-smart-open t "always change focus to current buffer"))

I like emacs to remember files that I have visited. The recentf package allows you to see the list using C-x C-r. It comes handy when Emacs desktop save looses your file.

This is mostly superseded by ivy that includes past buffers in the change buffer list. I might remove this binding in the future.

(use-package recentf
  :if (not noninteractive)
  :bind ( "C-x C-r" . recentf-open-files)
  :init
  (setq recentf-auto-cleanup 'never ; cleanup interfers with tramp mode
        recentf-max-saved-items 400
        recentf-max-menu-items 35
        recentf-save-file (expand-file-name "recentf" my/backup-dir))
  :config
  (recentf-mode 1))

Geographical location

Calendar functions like to know your geographical coordinates to display celestial movements correctly.

(setq calendar-latitude 60.47)
(setq calendar-longitude 25.73)
(setq calendar-location-name "Åtorp")

Filename to clipboard

This useful function can be accessed through the launch hydra with C-x l f (Emacs, launch filename copying).

(defun copy-file-name-to-clipboard ()
  "Copy the current buffer file name to the clipboard."
  (interactive)
  (let ((filename (if (equal major-mode 'dired-mode)
                      default-directory
                    (buffer-file-name))))
    (when filename
      (kill-new filename)
      (message "Copied buffer file name '%s' to the clipboard." filename))))

Org mode

Intro

Org mode is for all writing of plain text. Use org mode rather than plain text mode even when the file extension is .txt.

Let’s bind the org mode online info into hydra-goto C-c z o since it is so useful.

Two minor modes visual-line-mode and org-indent-mode combined make org buffers automatically to wrap long lines at word boundary and indent the next line.

org-autolist makes org lists behave more like you’d expect: Return inserts a new list item and backspace removes the bullet and backs up to previous list item.

Org mode has a large selected special symbols (like \=alpha= > =\alpha) to enter characters into the text. Exporting converts them to the proper Unicode character or symbol for that output. I my org mode, the entities are rendered as symbols. You can toggle that with C-c C-x \. The list of all entities can be seen in a buffer with M-x org-entities-help.

Underscores are used in so often in file names, that I have disabled rendering of superscript and subscript in org buffers. Now, ^ or _ need to be followed by a string in curly brackets to be rendered and exported.

Unsetting variable org-M-RET-may-split-line disallows splitting heaser lines with enter (Make M-RET better in Org Mode | Irreal).

Fontification

Pretty fontification of source code blocks needs to be set before calling org mode.

(custom-set-faces
 '(org-block-begin-line
   ((t (:underline "#A7A6AA" :foreground "#f00f00" :background "#efefef"))))
 '(org-block
   ((t (:background "#fffffc"))))
 '(org-block-end-line
   ((t (:overline "#A7A6AA" :foreground "##f00f00" :background "#efefef")))))

Basic config

(use-package org
  :ensure org-plus-contrib
  :mode ("\\.txt$" . org-mode)
  :diminish org-indent-mode
  :config
  ;; export Unicode
  (setq org-pretty-entities t)
  (setq org-use-sub-superscripts "{}")
  ;; Don't allow editing of folded regions
  (setq org-catch-invisible-edits 'error)
  (add-hook 'org-mode-hook
            (lambda ()
              (visual-line-mode)
              ;; (turn-on-org-cdlatex)
              (org-indent-mode)
              )))

(use-package org-autolist
  :diminish ""
  :config
  (add-hook 'org-mode-hook (lambda () (org-autolist-mode))))

;; too slow to have on by default
;; (add-hook 'org-mode-hook 'wc-mode)
(use-package wc-mode)

(setq org-M-RET-may-split-line '((default . nil)))

(use-package org-contacts
  :defer t
  :ensure nil
  :init
  (setq org-contacts-files '("~/Dropbox/org/contacts.org")))

See this page for clickable org-contacts in text files.

Note: C-c C-j is org-goto and creates a copy of the current org buffer to move around and copy text. Allows moving or returning to current location. Awesome!

The wc-mode adds commands and mode line display of count of words, characters or lines. Also, it can set goals.

(describe-function 'wc-mode)

Note: Do not enable it by default if you have large org files. It slows emacs down drastically.

Wrap region

I use wrap-region.el to add automatic wrapping to org-mode text characters.

(use-package wrap-region
  :config
  (wrap-region-global-mode t)
  ;; (wrap-region-add-wrapper "`" "'")
  (wrap-region-add-wrapper "~" "~" nil 'org-mode)  ; code
  (wrap-region-add-wrapper "*" "*" nil 'org-mode)  ; bold
  (wrap-region-add-wrapper "/" "/" nil 'org-mode)  ; italic
  (wrap-region-add-wrapper "=" "=" nil 'org-mode)) ; verbatim

Agenda

I need reminders of holidays in Finland.

I learned ways to speed up agenda generation from learn profiler.

Added a hydra to prettify agenda dispatcher. Press v in agenda.

(use-package suomalainen-kalenteri
  :defer t
  :init (setq org-agenda-start-on-weekday 1)) ;; 1 is Monday
;; speed-ups
(setq org-agenda-inhibit-startup t
      org-agenda-use-tag-inheritance nil
      org-agenda-show-future-repeats 'next)


;;(define-key org-agenda-mode-map
;;    "v" 'hydra-org-agenda-view/body)

(defun org-agenda-cts ()
  (let ((args (get-text-property
               (min (1- (point-max)) (point))
               'org-last-args)))
    (nth 2 args)))

(defhydra hydra-org-agenda-view (:hint none)
  "
   _d_: ?d? day        _g_: time grid=?g? _a_: arch-trees
   _w_: ?w? week       _[_: inactive      _A_: arch-files
   _t_: ?t? fortnight  _f_: follow=?f?    _r_: report=?r?
   _m_: ?m? month      _e_: entry =?e?    _D_: diary=?D?
   _y_: ?y? year       _q_: quit          _L__l__c_: ?l?"
  ("SPC" org-agenda-reset-view)
  ("d" org-agenda-day-view
   (if (eq 'day (org-agenda-cts))
       "[x]" "[ ]"))
  ("w" org-agenda-week-view
   (if (eq 'week (org-agenda-cts))
       "[x]" "[ ]"))
  ("t" org-agenda-fortnight-view
   (if (eq 'fortnight (org-agenda-cts))
       "[x]" "[ ]"))
  ("m" org-agenda-month-view
   (if (eq 'month (org-agenda-cts)) "[x]" "[ ]"))
  ("y" org-agenda-year-view
   (if (eq 'year (org-agenda-cts)) "[x]" "[ ]"))
  ("l" org-agenda-log-mode
   (format "% -3S" org-agenda-show-log))
  ("L" (org-agenda-log-mode '(4)))
  ("c" (org-agenda-log-mode 'clockcheck))
  ("f" org-agenda-follow-mode
   (format "% -3S" org-agenda-follow-mode))
  ("a" org-agenda-archives-mode)
  ("A" (org-agenda-archives-mode 'files))
  ("r" org-agenda-clockreport-mode
   (format "% -3S" org-agenda-clockreport-mode))
  ("e" org-agenda-entry-text-mode
   (format "% -3S" org-agenda-entry-text-mode))
  ("g" org-agenda-toggle-time-grid
   (format "% -3S" org-agenda-use-time-grid))
  ("D" org-agenda-toggle-diary
   (format "% -3S" org-agenda-include-diary))
  ("!" org-agenda-toggle-deadlines)
  ("["
   (let ((org-agenda-include-inactive-timestamps t))
     (org-agenda-check-type t 'timeline 'agenda)
     (org-agenda-redo)))
  ("q" (message "Abort") :exit t))

You can add tags to any agenda item manually or preferably by pulling them from a list. At the agenda item header, hit C-c C-c to see the list and select any subset of tags by pressing the shortcut key(s). My tags are grouped: Searching with the group name will find entries with any sub tag.

Tags can be added automatically at org-capture. This solution works, but only if capitalization is right. All my tags are in upper case, so it was necessary to add upcase.

(setq org-tag-alist '(("ATORP"   . ?a)
                      ("WORK"    . ?r)
                      ("TMI"     . ?i)
                      ("CSC"     . ?c)

                      (:startgrouptag)
                      ("SCIENCE" . ?z)
                      (:grouptags)
                      ("BIO"     . ?b)
                      ("HUMEVO"  . ?h)
                      ("BATS"    . ?t)
                      ("NATURE"  . ?n)
                      (:endgrouptag)

                      (:startgrouptag)
                      ("COMP"    . ?x)
                      (:grouptags)
                      ("GIT"     . ?g)
                      ("LATEX"   . ?l)
                      ("PERL"    . ?p)
                      ("SECURITY". ?s)
                      ("PYTHON"  . ?y)
                      (:endgrouptag)

                      (:startgrouptag)
                      ("EMACS"   . ?e)
                      (:grouptags)
                      ("ORG"     . ?o)
                      (:endgrouptag)

                      (:startgrouptag)
                      ("CULTURE" . ?e)
                      (:grouptags)
                      ("FOOD"    . ?d)
                      ("PHOTO"   . ?f)
                      ("BOOK"    . ?k)
                      ("MOVIE"   . ?m)
                      ("WRITING" . ?w)
                      ("MUSIC"   . ?u)
                      (:endgrouptag)))

The agenda command pulls all active events and todos from files together. Org-agenda needs to load before calling org-agenda.

You have to tell org-mode which files contain your agenda items. The following setup adds all files from a given directory. I am using DropBox to get one more way to backup these important files.

In addition, use C-c C-l to paste the link stored with C-c l. Links on org-mode are now followed by pressing return on a link.

I prefer agenda listing for a fortnight and warnings 5 days before deadline.

With line %%(diary-lunar-phases) in the calendar.org file, the phases are displayed – now with symbols.

Links to non-existing files can be highlighted.

(use-package org-agenda
  :ensure nil
  :bind* (("C-c a" . org-agenda)  ; bind* ensures that all minor mode bindings are overriden
         ("C-c c" . org-capture)
         ("C-c l" . org-store-link)
         ("C-c C-s" . org-schedule)) ; override synosaurus
  :init
  (setq org-agenda-files '("~/Dropbox/org"))
  (setq org-return-follows-link t)


  (setq org-agenda-span 14)
  (setq org-deadline-warning-days 5)
  ;; clean agenda
  (setq org-agenda-skip-deadline-if-done t)
  (setq org-agenda-skip-scheduled-if-done t)
  (setq lunar-phase-names
        '("● New Moon"
          "☽ First Quarter Moon"
          "○ Full Moon"
          "☾ Last Quarter Moon")))

worf – modal editing in org mode

Adds vi-like modal key bindings to org mode by adding a new minor mode. Documentation

Note: While most of the worf key bindings work only in the header asterisk area, there are a number of key bindings that are active everywhere in the buffer. The most surprising are the square brackets [] that move the cursor to next or previous special position. While this binding is active, key sequence C-q [ can be used to enter the characters. I have disabled the M-j that conflicts my other use for that binding.

(use-package worf
  :diminish ""
  :defer t
  :config (add-hook 'org-mode-hook (lambda () (worf-mode 1)))
  (define-key worf-mode-map (kbd "M-j") nil))

Capture templates

First we have to tell emacs where we want to store all captured notes. I keep all files in DropBox.

(setq org-directory "~/Dropbox/org")
(setq org-default-notes-file "~/Dropbox/org/reference.org")

I copied these capture templates from this excellent page and modified to my own use. I try to minimize refiling. I have several categories of entries:

  1. notes [n] for all note taking (URLs, ideas, papers,…) that I want to file away for later retrieval. They are time stamped, stored in that order and have optional tags I defined in the previous section.
  2. code snippets [s] are subclasses of notes that create a code block and ask for the language and tags.
  3. events [e] are regular events with active time stamp. Scheduled and completion times can be added to them later.
  4. appointments [a] for events that are shared with Google Calendar using org-gcal.
  5. work [w] events start the clock automatically for the new entry.

    Events are in file:~/Dropbox/org/calendar.org that starts with sections for anniversaries and other recurring tasks. Gcal integration happens through file:~/Dropbox/org/gcal.org All other entries are in file:~/Dropbox/org/reference.org .

Code snippet capture code was mentioned in the Irreal blog.

;; Capture templates for: general notes, TODO tasks, events
(setq org-capture-templates
      '(("n" "note" entry (file+olp+datetree "~/Dropbox/org/reference.org")
         "* %?\n     :PROPERTIES:\n     :CREATED:  %U\n     :END:     \n%i")
        ("s" "code snippet" entry (file+olp+datetree "~/Dropbox/org/reference.org")
         ;; Prompt for tag and language
         "* %?\t%^g\n     :PROPERTIES:\n     :CREATED:  %U\n     :END:     \n#+BEGIN_SRC %^{language}\n%i\n#+END_SRC")
        ("e" "event" entry (file+olp+datetree "~/Dropbox/org/reference.org")
         "* %?\n     :PROPERTIES:\n     :CREATED:  %U\n     :CATEGORY: event\n     :END:\n     %T\n%i")
        ("a" "appointment" entry (file "~/Dropbox/org/gcal.org" )
         "* %?\n\n %^T\n\n:PROPERTIES:\n\n:END:\n\n")
        ("c" "contacts" entry (file "~/Dropbox/org/contacts.org")
         "* %(org-contacts-template-name)
:PROPERTIES:
:EMAIL: %(org-contacts-template-email)
:PHONE:
:ALIAS:
:NICKNAME:
:IGNORE:
:ICON:
:NOTE:
:ADDRESS:
:BIRTHDAY:
:END:")
        ("w" "work" entry (file+olp+datetree "~/Dropbox/org/reference.org")
         "* %? %^g\n     :PROPERTIES:\n     :CREATED:  %U\n     :CATEGORY: work\n     :END:\n%i"
         :clock-in t :clock-keep t)))

Captured notes can be tagged just like any other org headings. However, Key combination C-c C-c finalizes the capture, so you have to use C-c C-q to call up the capture interface. Tags that match words in the header are automatically added at the end of the capture.

;; Disabled. 2016-11-27 package update to messed this up.
(defun org-auto-tag ()
  (interactive)
  (let ((alltags (append org-tag-persistent-alist org-tag-alist))
        (headline-words  (split-string (upcase (org-get-heading t t)))))
    (mapcar (lambda (word)
              (if (assoc word alltags)
                  a~S                       (org-toggle-tag word 'saon)))
            headline-words)))
;; (add-hook 'org-capture-before-finalize-hook 'org-auto-tag)
;; (remove-hook 'org-capture-before-finalize-hook 'org-auto-tag)

Todos can have additional keywords with dates: DEADLINE C-c C-d for the time the task needs to be finished, and SCHEDULED C-c C-s for the date when to start working on the task.

Additionally, there are templates for the Ledger accounting program for several accounts. The path to the file must exist.

  (setq org-capture-templates
        (append '(("l" "Ledger entries")
                  ("lm" "MasterCard" plain
                   (file "~/Documents/ledger/refile.led")
                   "
%(org-read-date)  %^{Payee}
    ; entered: %U
    Liabilities:MasterCard
    Expenses:%^{Account}              € %^{Amount}
   " :empty-lines-before 1)
                  ("lc" "Cash" plain
                   (file "~/Documents/ledger/refile.led")
                   "
%(org-read-date) * %^{Payee}
    ; entered: %U
    Assets:Cash
    Expenses:%^{Account}             € %^{Amount}
   " :empty-lines-before 1 )
                  ("le" "EUR debit" plain
                   (file "~/Documents/ledger/refile.led")
                   "
%(org-read-date) * %^{Payee}
    ; entered: %U
    Assets:Heikintili
    Expenses:%^{Account}               € %^{Amount}
   " :emptye-lines-before 1 ))
                org-capture-templates))

Org Dropbox

org-dropbox is my own package that is now available in MELPA. It creates a minor mode that syncs DropBox notes from mobile devices into an org datetree file that is part of my org agenda. The minor mode starts a daemon that periodically scans the note directory.

With org-dropbox-mode on, I can browse news in my phone, add interesting articles to Dropbox, and these notes will automatically pop into my main capture file reference.org that is searchable using org agenda commands.

(use-package org-dropbox
  :defer 5
  :config (org-dropbox-mode))

Structure templates

Extending org capture templates as in http://acidwords.com/posts/2018-03-02-extending-org-mode-easy-templates.html with comment and abstract blocks. These have been added to hydra-org-template that is triggered by the < key.

;; http://acidwords.com/posts/2018-03-02-extending-org-mode-easy-templates.html
(add-to-list 'org-structure-template-alist
             '("C" "#+BEGIN_COMMENT\n?\n#+END_COMMENT" ""))
(add-to-list 'org-structure-template-alist
             '("b" "#+BEGIN_ABSTRACT\n?\n#+END_ABSTRACT" ""))


;; http://oremacs.com/2015/03/07/hydra-org-templates/
;; https://github.com/abo-abo/hydra/wiki/Org-mode-block-templates
(defhydra hydra-org-template (:color blue :hint nil)
  "
         org-template  _c_enter  _q_uote     _e_macs-lisp    _L_aTeX:
                       _l_atex   _E_xample   _p_erl          _i_ndex:
                       _a_scii   _v_erse     _P_erl tangled  _I_NCLUDE:
                       _s_rc     _V_erbatim  plant_u_ml      _H_TML:
                       _h_tml    _n_ote     _C_omment        _A_SCII:
                       ^ ^       a_b_stract
             "
  ("s" (hot-expand "<s"))
  ("E" (hot-expand "<e"))
  ("q" (hot-expand "<q"))
  ("v" (hot-expand "<v"))
  ("V" (hot-expand "<V"))
  ("n" (let (text) ; org-reveal speaker notes
         (when (region-active-p)
           (setq text (buffer-substring (region-beginning) (region-end)))
           (delete-region (region-beginning) (region-end)))
         (insert "#+BEGIN_NOTES\n\n#+END_NOTES")
         (forward-line -1)
         (when text (insert text))))
  ("c" (hot-expand "<c"))
  ("C" (hot-expand "<C"))
  ("b" (hot-expand "<b"))
  ("l" (hot-expand "<l"))
  ("h" (hot-expand "<h"))
  ("a" (hot-expand "<a"))
  ("L" (hot-expand "<L"))
  ("i" (hot-expand "<i"))
  ("e" (hot-expand "<s" "emacs-lisp"))
  ("p" (hot-expand "<s" "perl"))
  ("u" (hot-expand "<s" "plantuml :file CHANGE.png"))
  ("P" (hot-expand "<s" "perl" ":results output :exports both :shebang \"#!/usr/bin/env perl\"\n"))
  ("I" (hot-expand "<I"))
  ("H" (hot-expand "<H"))
  ("A" (hot-expand "<A"))
  ("<" self-insert-command "ins")
  ("o" nil "quit"))

(defun hot-expand (str &optional mod header)
  "Expand org template.

STR is a structure template string recognised by org like <s. MOD is a
string with additional parameters to add the begin line of the
structure element. HEADER string includes more parameters that are
prepended to the element after the #+HEADERS: tag."
  (let (text)
    (when (region-active-p)
      (setq text (buffer-substring (region-beginning) (region-end)))
      (delete-region (region-beginning) (region-end))
      (deactivate-mark))
    (when header (insert "#+HEADERS: " header))
    (insert str)
    (org-try-structure-completion)
    (when mod (insert mod) (forward-line))
    (when text (insert text))))

(define-key org-mode-map "<"
  (lambda () (interactive)
    (if (or (region-active-p) (looking-back "^" nil))
        (hydra-org-template/body)
      (self-insert-command 1))))

Org-gcal

myuhe/org-gcal.el: Org sync with Google Calendar

Instructions from Using Emacs - 26 - Google Calendar, Org Agenda | C’est la Z

Video: (3) Using emacs 26 - Google Calendar and Org Agenda (good version) - YouTube 🔊

Config is in my emacs secrets file.

(setq package-check-signature nil)

(use-package org-gcal)

(add-hook 'org-agenda-mode-hook (lambda () (org-gcal-sync) ))
;; (add-hook 'org-capture-after-finalize-hook (lambda () (org-gcal-sync) ))

;; fix a bug
(defun new/org-gcal--notify (title mes)
  (message "org-gcal::%s - %s" title mes))
(fset 'org-gcal--notify 'new/org-gcal--notify)

Org time

Org time stamps

Org time stamps, see (org-info "Timestamps"), come in two flavours, active and inactive. An active timestamp in a file that is followed by the agenda, are visible in the calendar. The commands are org-time-stamp and org-time-stamp-inactive. The key combination C-c . is the for the active time stamp. C-c ! for inactive ones. Prefix arguments are very useful in this context:

KeysInteractiveAction
C-c .tdate
C-u C-c .ttime
C-u C-u C-c .niltime now

org-toggle-time-stamp-type is not bound to any key by default.

Time manipulation

org-clock-convenience adds functions that manipulate time stamps with keys. Press shift up or down.

(use-package org-clock-convenience
  :defer t
  :bind (:map org-agenda-mode-map
              ("<S-up>" . org-clock-convenience-timestamp-up)
              ("<S-down>" . org-clock-convenience-timestamp-down)
              ("'" . org-clock-convenience-fill-gap)))

Time tracking

This combines all commands I know about time management under org mode to one that can be launched with C-c w /endash w for work.

Setting org-clock-idle-time makes emacs ask for confirmation if the computer has been idle for some time while the clock is running. Out of the many options, these are the most useful:

  • i (ignore the question, continue with the clock),
  • S (that is, shift-s – probably the most useful – indicates that all idle time should be subtracted from the clock).
  • K RET (that is, shift-k RET; basically almost the same as clock out now),
    (setq org-clock-persist 'history)
    (org-clock-persistence-insinuate)
    (setq org-log-note-clock-out t)
    
    (setq org-clock-idle-time 10)
    (bind-key "C-c w" 'hydra-org-clock/body)
    (defhydra hydra-org-clock (:color blue :hint nil)
      "
    ^Clock:^ ^In/out^     ^Edit^           ^Summary^        | ^Timers:^ ^Run^           ^Insert
    -^-^-----^-^----------^-^--------------^-^--------------|--^-^------^-^-------------^------
    (_?_)    _i_n         _e_dit           _g_oto entry     | (_z_)     _r_elative      ti_m_e
    ^ ^      _I_n list    _q_uit           goto _h_istory  |  ^ ^      cou_n_tdown     i_t_em
    ^ ^      _c_ontinue   _T_oggle type    _d_isplay        |  ^ ^      _p_ause toggle
    ^ ^      _o_ut        ^ ^              _r_eport         |  ^ ^      _s_top
    ^ ^      ^ ^
    "
       ("i" org-clock-in)
       ("I" (org-clock-in 4))
       ("o" org-clock-out)
       ("c" org-clock-in-last)
       ("e" org-clock-modify-effort-estimate)
       ("q" org-clock-cancel)
       ("T" org-toggle-timestamp-type)
       ("g" org-clock-goto)
       ("h" (org-clock-goto 4))
       ("d" org-clock-display)
       ("r" org-clock-report)
       ("?" (org-info "Clocking commands"))
    
      ("r" org-timer-start)
      ("n" org-timer-set-timer)
      ("p" org-timer-pause-or-continue)
      ;; ("a" (org-timer 16)) ; double universal argument
      ("s" org-timer-stop)
    
      ("m" org-timer)
      ("t" org-timer-item)
      ("z" (org-info "Timers")))
        

    See Clocking work time.

PENDING MobileOrg

Use Dropbox for syncing my agenda files with my Android phone. Worry about the security implications later.

(setq org-mobile-directory "~/Dropbox/org")

Extending org completion

Ora-ora has an amazing blog post: Extending completion-at-point for Org-mode · (or emacs.

He sets up context aware completion for org mode to be used with complete-symbol command with C-M-i. it turned out that flyspell has already bound that key. Luckily, it also binds a key that I use more frequently, C-., to the same flyspell-auto-correct-word function), and I can disable the former and keep the latter binding.

This setup means that any filenames, recurring in-document symbols, or references (\ref{...) should be quoted using the ‘​=’ character, and use C-M-i to complete.

;; (define-key flyspell-mode-map (kbd "C-M-i") nil)
(bind-key "C-M-i" 'complete-symbol org-mode-map)
(setq completion-at-point-functions
      '(org-completion-symbols
        ora-cap-filesystem
        org-completion-refs))

(defun org-completion-symbols ()
  (when (looking-back "=[a-zA-Z]+")
    (let (cands)
      (save-match-data
        (save-excursion
          (goto-char (point-min))
          (while (re-search-forward "=\\([a-zA-Z]+\\)=" nil t)
            (cl-pushnew
             (match-string-no-properties 0) cands :test 'equal))
          cands))
      (when cands
        (list (match-beginning 0) (match-end 0) cands)))))

(defun ora-cap-filesystem ()
  (let (path)
    (when (setq path (ffap-string-at-point))
      (let ((compl
             (all-completions path #'read-file-name-internal)))
        (when compl
          (let ((offset (ivy-completion-common-length (car compl))))
            (list (- (point) offset) (point) compl)))))))

(defun org-completion-refs ()
  (when (looking-back "\\\\\\(?:ref\\|label\\){\\([^\n{}]\\)*")
    (let (cands beg end)
      (save-excursion
        (goto-char (point-min))
        (while (re-search-forward "\\label{\\([^}]+\\)}" nil t)
          (push (match-string-no-properties 1) cands)))
      (save-excursion
        (up-list)
        (setq end (1- (point)))
        (backward-list)
        (setq beg (1+ (point))))
      (list beg end
            (delete (buffer-substring-no-properties beg end)
                    (nreverse< cands))))))

External jars

Tell org where to find external dependencies. Ditaa and PlantUML executable are java jar files. Ditaa is part of org-mode git repository but you have to download PlantUML and place somewhere where Emacs can find it. I am using homebrew to maintain a recent copy of both with a shell script wrapper.

The org code seems to require the direct access to the jar file. Run this perl code create a symbolic link after installation or upgrade.

use strict;
use warnings;

my $file = '/usr/local/bin/plantuml';
unlink $file. ".jar" if -e $file. ".jar";

my $data;
{
    open my $fh, '<', $file or die;
    $/ = undef;
    $data = <$fh>;
    close $fh;
}
my ($jar) = $data =~ /jar +([^ ]+)/;
`ln -s $jar "${file}.jar"`;
print `ls -l "${file}.jar"`;

The plantuml-mode helps editing the code. Also, check the new puml-mode.

;; ditaa
(setq org-ditaa-jar-path "/usr/local/bin/ditaa.jar")
                                        ; plantuml-mode
(setq plantuml-jar-path (expand-file-name "/usr/local/bin/plantuml.jar"))
(setq org-plantuml-jar-path plantuml-jar-path)

TODOs

Make custom markers for todo items:

TODO
something that needs to be done at some point. If it has a date, it should be done on that day but it may be moved.
PENDING
something that’s awaiting feedback from someone else. If it has a date, it needs followup if there hasn’t been any feedback at that time.
MEETING
a scheduled meeting and cannot easily be rescheduled.
DONE
done.
CANCELED
can be ignored. May include a note on why it’s been cancelled.

Apply todo markers by placing the cursor on the header or item line and shift arrow left or right, or accessing the list by C-c C-t.

(setq org-todo-keywords
      '((sequence "TODO(t)" "PENDING(p)" "MEETING(m)" "|" "DONE(d)" "CANCELED(c)")))

    

Automatically mark todo items with todo subitems as DONE when all subitems are done.

(defun my-org-autodone (n-done n-not-done)
  "Switch entry to DONE when all subentries are done, to TODO otherwise."
  (let (org-log-done org-log-states)   ; turn off logging
    (org-todo (if (= n-not-done 0) "DONE" "TODO"))))

(add-hook 'org-after-todo-statistics-hook 'my-org-autodone)

    

Add timestamp to all DONE items.

(setq org-log-done 'time)
    

Prettify with Unicode characters

The first snippet (from Sacha.org) turns - [X] into ☑ and - [ ] into ☐, but leaves [-] alone in HTML export.

The second uses org-bullets to beautify org header bullets with pretty UTF-8 characters. Custom bullets icons are from puntoblogspot.

The third replaces ASCII ellipsis with a Unicode character.

Do not show org mode emphasis markers. Org as a Word Processor

(setq org-html-checkbox-type 'unicode)
(setq org-html-checkbox-types
      '((unicode (on . "<span class=\"task-done\">&#x2611;</span>")
                 (off . "<span class=\"task-todo\">&#x2610;</span>")
                 (trans . "<span class=\"task-in-progress\">[-]</span>"))))
(use-package org-bullets
  :disabled t
  :defer t
  ;; :init (setq org-bullets-bullet-list '("✺" "✹" "✸" "✷" "✶" "✭" "✦" "■" "▲" "●" ))
  :init (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
;; http://endlessparentheses.com/changing-the-org-mode-ellipsis.html?source=rss
;;(setq org-ellipsis "…")
(setq org-ellipsis "")
(setq org-hide-emphasis-markers t)
;; (setq org-hide-leading-stars t)

;; ###
(font-lock-add-keywords
 'org-mode
 `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 1 'org-headline-done prepend))
 'append)

Org tables sitcky headers

(use-package org-table-sticky-header
  :diminish ""
  :config
  (add-hook 'org-mode-hook 'org-table-sticky-header-mode))

Org Babel

Run code with a block by C-c C-c without confirmation. This is a known security risk, but makes life easier. Beware.

(setq org-confirm-babel-evaluate nil)

If you have more than one interpreter for any of the languages in code blocks, you better set it explicitly. My main python with all modern libraries is Anaconda python version 3.

;; Alternative python interpreter for babel blocks
(setq org-babel-python-command "~/miniconda3/bin/python")

Use syntax highlighting (“fontification”) in org-mode source blocks. This also highlights source blocks in HTML exports.

  (setq org-src-fontify-natively t
        org-src-tab-acts-natively t)

  ;; ###
  ;; display/update images in the buffer after I evaluate
  (add-hook 'org-babel-after-execute-hook 'org-display-inline-images 'append)

;; org block backgrounds

;;(org-block-begin-line
;; ((t (:underline "#A7A6AA" :foreground "#008ED1" :background "#EAEAFF"))))
;;(org-block-background
;; ((t (:background "#FFFFEA"))))
;;(org-block-end-line
;; ((t (:overline "#A7A6AA" :foreground "#008ED1" :background "#EAEAFF"))))

Highlight latex text in org mode | Pragmatic Emacs gives code for fontifying inline LaTeX code like this: $y=mx+c$.

See Emphasize LaTeX Code in an Org Buffer | Irreal comment from Grant Rettke to highlight even more.

Use the minted package for syntax highlighting source blocks in LaTeX/PDF exports. It needs the python Pygments library. Install it e.g. sudo easy_install Pygments. Configuration copied from a blog post by Florian Bergmann. Check also the blog entry by Praveen Kumar.

;; Syntax highlighting for inline LaTeX
(setq org-highlight-latex-and-related '(latex))
;; highlight quite a lot
(setq org-highlight-latex-and-related '(latex script entities))

;; Include the latex-exporter
(use-package ox-latex
  :ensure nil)
;; Add minted to the defaults packages to include when exporting.
(add-to-list 'org-latex-packages-alist '("" "minted"))
;; Tell the latex export to use the minted package for source
;; code coloration.
(setq org-latex-listings 'minted)
;; Let the exporter use the -shell-escape option to let latex
;; execute external programs.
;; This obviously can be dangerous!
(setq org-latex-pdf-process
      ;; '("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
      ;; alternative
      '("latexmk -shell-escape -interaction=nonstopmode -pdf -f %f"))

My additions and overrides inlude export to Beamer presentations, too.

(use-package ox-beamer
  :ensure nil)

Slower but more robust latex-to-PDF processing uses latexmk. I have I commented it out because the above xelatax call seems to work well.

(setq org-latex-pdf-process
      '("latexmk -interaction=nonstopmode -shell-escape -pdflatex=xelatex -gg -f -pdf %f"))

Finally, I could export to \LaTeX document and run the following continuous process in the document directory:

latexmk -pvc -pdf -view=none FILENAME.tex

Untangle files; i.e. write org code blocks to their own files. Making Emacs Work For Me

  (bind-key "C-c i" 'my/org-babel-untangle)

  (defun my/org-babel-untangle (path)
    (interactive "fFile to include: ")
    (message "Untangling '%s'..." path)
    (save-current-buffer
      (let ((lang (save-current-buffer
                    (set-buffer (find-file-noselect path))
                    (my/mode->language major-mode))))
        (insert (format "\n** %s\n\n#+BEGIN_SRC %s :tangle %s\n"
                        (capitalize (replace-regexp-in-string "\\[_-\\]" " " (file-name-base path)))
                        lang
                        (file-relative-name path)))
        (forward-char (cadr (insert-file-contents path)))
        (insert "\n#+" "END_SRC\n"))))

  (defun my/mode->language (mode)
    "Return the language for the given mode"
    (intern (replace-regexp-in-string "\\-mode$" "" (my/->string mode))))

;; (defun my/org-babel-untangle-tree (path)
;;  (interactive "Droot directory to untangle: ")
;;  (mapc 'my/org-babel-untangle
;;        (cl-remove-if 'file-directory-p
;;                      (f-files path (lambda (p) t) t))))

Display and refresh images created by a source block in the same document. Also rescale images to 300px for display.

(setq org-startup-with-inline-images t)
(setq org-image-actual-width 300)
(org-display-inline-images t t)
;;(add-hook 'org-babel-after-execute-hook
;;          (lambda () (org-redisplay-inline-images)))

Enable flycheck in org-buffer (from here)

(defadvice org-edit-src-code (around set-buffer-file-name activate compile)
  (let ((file-name (buffer-file-name)))
    ad-do-it
    (setq buffer-file-name file-name)))

Org export

I add a formats to org export menu C-c C-e: markdown for bitbucket.

;; Set the encoding to utf-8
(setq org-export-coding-system 'utf-8)

(use-package ox-md
  :ensure nil)
;; /Applications/Emacs.app/Contents/Resources/etc/org/
;;(setq org-odt-data-dir "~/.emacs.d/etc/")
;;(use-package ox-odt :ensure nil)

Setting the org-odt-data-dir is a hack. Why does not emacs find the files in any of my locations by itself?

Latex export

This defines a new latex class fu-org-article based on the article class that has fresher and more compact look than the default article. The fonts used in the output are Linux Libertine. The Latex binaries and packages come from Tex Live.

I have amended and modified the original code from emacs-fu blog quite a bit.

(add-to-list 'org-latex-classes
             '("fu-org-article"
               "\\documentclass[11pt,a4paper]{article}
     \\usepackage[T1]{fontenc}
     \\usepackage{xunicode}        % for XeTex
     \\usepackage{fontspec}        % for XeTex
     \\usepackage{xltxtra}         % for XeTex
     \\usepackage{url}             % for XeTex to break long URLs at line ending
     \\usepackage[english,finnish]{babel}  % for XeTex
     \\selectlanguage{english}
     \\usepackage[osf]{libertine}  % Libertine fonts with old-style numbers
     \\usepackage{graphicx}
     \\usepackage{minted}
     \\usepackage{hypernat}
     \\usepackage[round]{natbib}
     \\usepackage{microtype}

     \\usepackage{paralist}
     \\let\\itemize\\compactitem
     \\let\\description\\compactdesc
     \\let\\enumerate\\compactenum

     \\usepackage[a4paper, textheight=10in,
                 marginparsep=7pt, marginparwidth=1.5in, margin=2in]{geometry}

     \\usepackage[colorlinks=true,urlcolor=black,linkcolor=black,citecolor=blue]{hyperref}

     \\let\\nofiles\\relax % Void the \\nofiles command

     \\pagestyle{plain}
     \\title{}
           [NO-DEFAULT-PACKAGES]
           [NO-PACKAGES]"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))


;; tufte export from https://github.com/smadhueagle/prelude/blob/master/personal/org-latex-custom.el
;; tufte-book class for writing classy books
(add-to-list 'org-latex-classes
             '("tufte-book"
               "\\documentclass{tufte-book}
\\usepackage[T1]{fontenc}
\\usepackage{color}
\\usepackage{amssymb}
\\usepackage{gensymb}
\\usepackage{nicefrac}
\\usepackage{microtype}
\\usepackage{units}"
               ("\\chapter{%s}" . "\\chapter*{%s}")
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))


;; tufte-handout class for writing classy handouts and papers
(add-to-list 'org-latex-classes
             '("tufte-handout"
               "\\documentclass{tufte-handout}
\\usepackage[T1]{fontenc}
\\usepackage{color}
\\usepackage{amssymb}
\\usepackage{amsmath}
\\usepackage{gensymb}
\\usepackage{nicefrac}
\\usepackage{units}
\\usepackage[a4paper]{geometry}"

               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

Language evaluation support

Org-Babel needs to know which languages to evaluate within code blocks Each language evaluation package can be loaded in a very simple way:

(use-package ob-perl :ensure nil)
(use-package ob-clojure :ensure nil)
(use-package ob-ruby :ensure nil)
(use-package ob-shell :ensure nil)
(use-package ob-python :ensure nil)
(use-package ob-emacs-lisp :ensure nil)
(use-package ob-dot :ensure nil)
(use-package ob-ditaa :ensure nil)
(use-package ob-plantuml :ensure nil)
(use-package ob-gnuplot :ensure nil)
(use-package ob-sql :ensure nil)
(use-package ob-sqlite :ensure nil)
(use-package ob-org :ensure nil)
(use-package ob-latex :ensure nil)
(use-package ob-lilypond :ensure nil)

Shortcuts for some language blocks

There are some source blocks that I use more than others. To save time typing them, I’ve defined skeletons with abbreviations for them.

sblk - Generic with interactive type.

(define-skeleton skel-org-block
  "Insert an org block, querying for type."
  "Type: "
  "#+BEGIN_SRC " str "\n"
  _ -
  "\n#+END_SRC\n")
(define-abbrev org-mode-abbrev-table "sblk" "" 'skel-org-block-source)

pblk - perl block with shebang

(define-skeleton skel-org-block-perl
  "Insert an org perl block with results in the output."
  ""
  "#+HEADERS: :results output :exports both :shebang \"#!/usr/bin/env perl\"\n#+BEGIN_SRC perl :tangle yes\n"
  _ -
  "\n#+END_SRC\n")

(define-abbrev org-mode-abbrev-table "pblk" "" 'skel-org-block-perl)

rblk – R block optimised for inline graphics

(define-skeleton skel-org-block-r
  "Insert an org R block with results in the output."
  ""
  "#+HEADER: :session *R* :cache yes :results output graphics :exports both :tangle yes\n#+BEGIN_SRC R  :file a.png  :width 500 :height 500\n"
  _ -
  "\n#+END_SRC\n")

(define-abbrev org-mode-abbrev-table "rblk" "" 'skel-org-block-r)

splant - PlantUML Source block

(define-skeleton skel-org-block-plantuml
  "Insert a org plantuml block, querying for filename."
  "File (no extension): "
  "#+BEGIN_SRC plantuml :file " str ".png\n"
  _ -
  "\n#+END_SRC\n")

(define-abbrev org-mode-abbrev-table "splant" "" 'skel-org-block-plantuml)

sdot - Graphviz DOT block

(define-skeleton skel-org-block-dot
  "Insert a org graphviz dot block, querying for filename."
  "File (no extension): "
  "#+BEGIN_SRC dot :file " str ".png :cmdline -Kdot -Tpng\n"
  "graph G {\n"
  _ - \n
  "}"
  "\n#+END_SRC\n")

(define-abbrev org-mode-abbrev-table "sdot" "" 'skel-org-block-dot)

sditaa - Ditaa source block

(define-skeleton skel-org-block-ditaa
  "Insert a org ditaa block, querying for filename."
  "File (no extension): "
  "#+BEGIN_SRC ditaa :file " str ".png  :cmdline -r\n"
  _ -
  "\n#+END_SRC\n")

(define-abbrev org-mode-abbrev-table "sditaa" "" 'skel-org-block-ditaa)

lblk - Emacs Lisp source block

(define-skeleton skel-org-block-elisp
  "Insert a org emacs-lisp block"
  ""
  "#+BEGIN_SRC emacs-lisp\n"
  _ -
  "\n#+END_SRC\n")

(define-abbrev org-mode-abbrev-table "lblk" "" 'skel-org-block-elisp)

References

I have one master bib file for references. Package gscholar-bibtex can retrieve bibtex entries into it from several sources. Launch it with C-x l g.

org-ref is a set of tools to do literature references in org mode. Org-ref Read the org-ref manual.

Looks like org-ref messes with LaTeX references unless it is told not to.

(use-package org-ref
  :defer t
  :after org
  :init
  (setq org-ref-bibliography-notes "~/Documents/bibliography/notes.org"
        org-ref-default-bibliography '("~/Documents/latex/all.bib")
        org-ref-pdf-directory "~/Documents/bibliography/bibtex-pdfs/"))
;; org-ref-ivy-bibtex
;; Do not mess up used defined label names
(setq org-latex-prefer-user-labels t)
(setq reftex-default-bibliography
      (quote ("~/Documents/latex/all.bib")))

(use-package gscholar-bibtex
  :defer t
  :init
  (setq gscholar-bibtex-database-file "~/Documents/latex/all.bib")
  (setq gscholar-bibtex-default-source "Google Scholar")
  :config
  (set-face-attribute 'gscholar-bibtex-title nil
                      :height 1.1
                      :foreground "blue"))

#

Bibliography is needed only in some documents. I have defined an abbreviation obiblio that adds these two lines to the document. Place them to the end. Read more about natbib.

\bibliographystyle{natbib}{}
\bibliography{bibfilename}
(define-skeleton skel-org-block-bibl
  "Insert a org/lisp bibliography block"
  ""
  "\n\\bibliographystyle{plainnat}\n\\bibliography{~/Documents/latex/all.bib}\n"
  _ -
  "")

(define-abbrev org-mode-abbrev-table "obiblio" "" 'skel-org-block-bibl)

Org-kanban

Finally a sensible implementation of kanban for org! gizmomogwai/org-kanban: Kanban table for org-mode

  1. The first line defines TODO headers to use. E.g #+TODO:Todo Plan Develop Test Done
  2. Write the topics as level one headers
  3. Shift right arrow the topics to initial TODO state.
  4. Create the kanban table:
#+BEGIN: kanban
#+END:

Use abbreviation okanban to create it.

  1. Place cursor on start or end tag and press C-c C-c to create or update the table.
  2. The TODO state can be updated from inside the table. Place the cursor on a line and give command org-kanban/shift. Keys j and k are bound to continue moving the topic left and right.
(use-package org-kanban)

Presentation

This code exports org mode outlines to presentations in fancy HTML5 Reveal.js format. Read more at GitHub.

To start using it, first clone the org-reveal repository, then create a copy of the Readme.org file and edit it with emacs.

cd ~/src/
git clone https://github.com/yjwen/org-reveal.git

Then activate the org-reveal mode and tell the location of the js file to emacs. The location can be either in the local file system or in the cloud, but it has to use URI syntax.

The htmlize package lets ox-reveal to do syntax highlighting in code blocks.

(use-package ox-reveal
  :init
  ;; (setq org-reveal-root "file:~/src/reveal.js")
  (setq org-reveal-root "http://cdn.jsdelivr.net/reveal.js/3.0.0/"))
(use-package htmlize)

Live preview

org-preview-html-mode automatically shows an HTML preview in eww on save. I helped rewrite the package!

(use-package org-preview-html)

Crypt

###

(use-package org-crypt
  :ensure nil
  :config
  (setq epg-gpg-program "gpg2")
  (org-crypt-use-before-save-magic)
  (setq org-tags-exclude-from-inheritance (quote ("crypt")))
  ;; GPG key to use for encryption
  ;; Either the Key ID or set to nil to use symmetric encryption.
  (setq org-crypt-key nil))

Highlight links to files

;; neat config that alerts on links to non-existing files
(org-link-set-parameters
 "file"
 :face (lambda (path) (if (file-exists-p path) 'org-link 'org-warning)))

Applications

Functionality that otherwise require external applications and are not really something a normal text editor would do.

PDF

The pdf-tools package gives you fast in-memory rendering of PDF that is always in right resolution. It allows searching of PDFs with isearch commands and its own version of occur, pdf-occur. Also,it can create and edit annotations, but it needs active cursor for that to have full functionality.

I have installed it with Joe’s instructions using homebrew.

Code from Marcin Borkowski on displaying pdfs on the right follows.

See more tweeks from

  (use-package pdf-tools
    :mode ("\\.pdf$" . pdf-tools-mode)
    :config
    (custom-set-variables
     '(pdf-tools-handle-upgrades nil)) ; Use brew upgrade pdf-tools instead.
    (setq pdf-info-epdfinfo-program "/usr/local/bin/epdfinfo")
    (pdf-tools-install)

    ;; open pdfs scaled to fit page
    (setq-default pdf-view-display-size 'fit-page)
    ;; automatically annotate highlights
    (setq pdf-annot-activate-created-annotations t)
    ;; use normal isearch
    (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)

    ;; turn off cua so copy works
    (add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))

    ;; keyboard shortcuts
    (define-key pdf-view-mode-map (kbd "l") #'pdf-annot-list-annotations)
    (define-key pdf-view-mode-map (kbd "h") #'pdf-annot-add-highlight-markup-annotation)
    ;; (define-key pdf-view-mode-map (kbd "H") #'pdf-annot-add-highlight-automatically)
    (define-key pdf-view-mode-map (kbd "t") #'pdf-annot-add-text-annotation)
    (define-key pdf-view-mode-map (kbd "D") #'pdf-annot-delete)
    (define-key pdf-view-mode-map (kbd "e") #'org-pdfquote-open)

    (defvar pdf-minimal-width 72
      "Minimal width of a window displaying a pdf.
               If an integer, number of columns.  If a float, fraction of the
               original window.")

    (defvar pdf-split-width-threshold 120
      "Minimum width a window should have to split it horizontally
               for displaying a pdf in the right.")

    (defun pdf-split-window-sensibly (&optional window)
      "A version of `split-window-sensibly' for pdfs.
               It prefers splitting horizontally, and takes `pdf-minimal-width'
               into account."
      (let ((window (or window (selected-window)))
            (width (- (if (integerp pdf-minimal-width)
                          pdf-minimal-width
                        (round (* pdf-minimal-width (window-width window)))))))
        (or (and (window-splittable-p window t)
                 ;; Split window horizontally.
                 (with-selected-window window
                   (split-window-right width)))
            (and (window-splittable-p window)
                 ;; Split window vertically.
                 (with-selected-window window
                   (split-window-below)))
            (and (eq window (frame-root-window (window-frame window)))
                 (not (window-minibuffer-p window))
                 ;; If WINDOW is the only window on its frame and is not the
                 ;; minibuffer window, try to split it vertically disregarding
                 ;; the value of `split-height-threshold'.
                 (let ((split-height-threshold 0))
                   (when (window-splittable-p window)
                     (with-selected-window window
                       (split-window-below))))))))

    (defun display-buffer-pop-up-window-pdf-split-horizontally (buffer alist)
      "Call `display-buffer-pop-up-window', using `pdf-split-window-sensibly'
               when needed."
      (let ((split-height-threshold nil)
            (split-width-threshold pdf-split-width-threshold)
            (split-window-preferred-function #'pdf-split-window-sensibly))
        (display-buffer-pop-up-window buffer alist)))


    ;; midnite mode hook
    ;; automatically turns off midnight-mode for pdfs
    (add-hook 'pdf-view-mode-hook (lambda ()
                                    (bms/pdf-no-filter)))

    ;; set the amber profile as default (see below)
    ;; I prefer white background by default
    ;; (setq pdf-view-midnight-colors '("#ff9900" . "#0a0a12" ))

    (defun bms/pdf-no-filter ()
      "View pdf without colour filter."
      (interactive)
      (pdf-view-midnight-minor-mode -1))

    ;; change midnite mode colours functions
    (defun bms/pdf-midnite-original ()
      "Set pdf-view-midnight-colors to original colours."
      (interactive)
      (setq pdf-view-midnight-colors '("#839496" . "#002b36" )) ; original values
      (pdf-view-midnight-minor-mode)
      )

    (defun bms/pdf-midnite-amber ()
      "Set pdf-view-midnight-colors to amber on dark slate blue."
      (interactive)
      (setq pdf-view-midnight-colors '("#ff9900" . "#0a0a12" )) ; amber
      (pdf-view-midnight-minor-mode)
      )

    (defun bms/pdf-midnite-green ()
      "Set pdf-view-midnight-colors to green on black."
      (interactive)
      (setq pdf-view-midnight-colors '("#00B800" . "#000000" )) ; green
      (pdf-view-midnight-minor-mode)
      )

    (defun bms/pdf-midnite-colour-schemes ()
      "Midnight mode colour schemes bound to keys"
      (local-set-key (kbd "!") (quote bms/pdf-no-filter))
      (local-set-key (kbd "@") (quote bms/pdf-midnite-amber))
      (local-set-key (kbd "#") (quote bms/pdf-midnite-green))
      (local-set-key (kbd "$") (quote bms/pdf-midnite-original)))

    (add-hook 'pdf-view-mode-hook 'bms/pdf-midnite-colour-schemes)

    ;; save after adding comment
    ;; (advice-add 'pdf-annot-edit-contents-commit :after #'bjm/save-buffer-no-args)
    ;; takes too long on big PDFs. Set up a toggle !!!
    ;; (advice-remove 'pdf-annot-edit-contents-commit #'bjm/save-buffer-no-args)

    (add-to-list 'display-buffer-alist '("\\.pdf\\(<[^>]+>\\)?$" . (display-buffer-pop-up-window-pdf-split-horizontally)))

    (bind-key "C-c r" 'hydra-pdftools/body)
    (defhydra hydra-pdftools (:color blue :hint nil)
      "
                                                                   ╭───────────┐
    Move  History   Scale/Fit     Annotations  Search/Link    Do   │ PDF Tools │
╭──────────────────────────────────────────────────────────────────┴───────────╯
      ^^_g_^^      _B_    ^↧^    _+_    ^ ^     [_al_] list    [_s_] search    [_u_] revert buffer
      ^^^↑^^^      ^↑^    _H_    ^↑^  ↦ _W_ ↤   [_am_] markup  [_o_] outline   [_i_] info
      ^^_p_^^      ^ ^    ^↥^    _0_    ^ ^     [_at_] text    [_F_] link      [_d_] dark mode
      ^^^↑^^^      ^↓^  ╭─^─^─┐  ^↓^  ╭─^ ^─┐   [_ad_] delete  [_f_] search link
 _h_ ←pag_e_→ _l_  _N_  │ _P_ │  _-_    _b_     [_aa_] dired
      ^^^↓^^^      ^ ^  ╰─^─^─╯  ^ ^  ╰─^ ^─╯   [_y_]  yank
      ^^_n_^^      ^ ^  _r_eset slice box
      ^^^↓^^^
      ^^_G_^^
--------------------------------------------------------------------------------
     "
      ("\\" hydra-master/body "back")
      ("<ESC>" nil "quit")
      ("al" pdf-annot-list-annotations)
      ("ad" pdf-annot-delete)
      ("aa" pdf-annot-attachment-dired)
      ("am" pdf-annot-add-markup-annotation)
      ("at" pdf-annot-add-text-annotation)
      ("y"  pdf-view-kill-ring-save)
      ("+" pdf-view-enlarge :color red)
      ("-" pdf-view-shrink :color red)
      ("0" pdf-view-scale-reset)
      ("H" pdf-view-fit-height-to-window)
      ("W" pdf-view-fit-width-to-window)
      ("P" pdf-view-fit-page-to-window)
      ("n" pdf-view-next-page-command :color red)
      ("p" pdf-view-previous-page-command :color red)
      ("d" pdf-view-dark-minor-mode)
      ("b" pdf-view-set-slice-from-bounding-box)
      ("r" pdf-view-reset-slice)
      ("g" pdf-view-first-page)
      ("G" pdf-view-last-page)
      ("e" pdf-view-goto-page)
      ("o" pdf-outline)
      ("s" pdf-occur)
      ("i" pdf-misc-display-metadata)
      ("u" pdf-view-revert-buffer)
      ("F" pdf-links-action-perfom)
      ("f" pdf-links-isearch-link)
      ("B" pdf-history-backward :color red)
      ("N" pdf-history-forward :color red)
      ("l" image-forward-hscroll :color red)
      ("h" image-backward-hscroll :color red)))


  (use-package org-pdfview
    :after (pdf-tools org))

  (use-package pdftools-annotation
    :after (pdf-tools org org-pdfview)
    :bind (:map pdf-view-mode-map ("e" . org-pdfquote-open))
    :load-path "elisp/" ; elisp dir under ~/.emacs.d
    :config
    (add-to-list
     'org-file-apps '("\\.pdf\\'" . org-pdfview-open))
    (add-to-list
     'org-file-apps '("\\.pdf::\\([[:digit:]]+\\)\\'" . org-pdfview-open)))
(define-key smap "m" 'pdf-annot-add-markup-annotation)
(define-key smap "s" 'pdf-annot-add-squiggly-markup-annotation)
(define-key smap "u" 'pdf-annot-add-underline-markup-annotation)
(define-key smap "o" 'pdf-annot-add-strikeout-markup-annotation)
(define-key smap "h" 'pdf-annot-add-highlight-markup-annotation)))

Mail: gmail

TIP: How to easily manage your emails with mu4e : emacs 🔊

also on gmail setup: https://gist.github.com/au/a271c09e8233f19ffb01da7f017c7269

More on mu4e configuration: https://gist.github.com/chlalanne/7397629

brew install mu –with-emacs brew install isync

mkdir ~/Sync/shared

cat > ~ctrl-D gpg -e -r heikki.lehvaslaiho@gmail.com .mbsyncpass

cd mkdir -p Maildir/gmail

machine imap.gmail.com login terencio.agozzino password <password> port 993 machine smtp.gmail.com login terencio.agozzino password <password> port 465

gpg -e -r heikki.lehvaslaiho@gmail.com ~/.authinfo ~/.authinfo.gpg

;; debug mail sending (setq smtpmail-debug-info t)

Mu4e Configuration | Irreal

(add-to-list 'load-path "/usr/local/Cellar/mu/1.0/share/emacs/site-lisp/mu/mu4e")

(use-package mu4e
  :ensure nil
  :ensure-system-package mu
  :bind ("C-c m" . mu4e)
  :hook ((mu4e-compose-mode . flyspell-mode)
         (message-mode . turn-on-org-tbl)
         (message-mode . turn-on-orgstruct++))
  :custom
  (mu4e-attachment-dir "~/Downloads")
  (mu4e-confirm-quit nil)
  (mu4e-compose-signature-auto-include t)
  (mu4e-completing-read-function 'ivy-completing-read)
  (mu4e-get-mail-command "mbsync -a")
  (mu4e-maildir "~/Maildir")
  ;; folders are under mu4e maildir
  (mu4e-trash-folder "/gmail/Trash")
  (mu4e-sent-folder "/gmail/Sent Mail")
  (mu4e-drafts-folder "/gmail/Drafts")
  (mu4e-refile-folder "/gmail/Archive")
  (mu4e-maildir-shortcuts
   '(("/gmail/INBOX" . ?i)
     ("/gmail/All Mail" . ?a)
     ("/gmail/Deleted Items" . ?d)
     ("/gmail/Drafts" . ?D)
     ("/gmail/Important" . ?I)
     ("/gmail/Sent Mail" . ?s)
     ("/gmail/Starred" . ?S)))
  (mu4e-html2text-command "iconv -c -t utf-8 | pandoc -f html -t plain")
  (mu4e-sent-messages-behavior 'delete) ; gmail stores a copy automatically
  (mu4e-update-interval 300)
  (mu4e-compose-format-flowed t) ; Set format=flowed
  (mu4e-use-fancy-chars t)
  (mu4e-view-show-addresses t)
  (mail-user-agent 'mu4e-user-agent)
  (mu4e-view-show-images t)
  (mu4e-view-image-max-width 800)
  (mu4e-headers-date-format "%y-%m-%d %H:%M")
  (mu4e-headers-fields
   '( (:human-date   .  18) ; 12, longer date format
      (:flags        .   6)
      (:mailing-list .  10)
      (:from         .  22)
      (:subject      . nil)))
  :config
  ;;store org-mode links to messages
  (require 'org-mu4e)
  ;;store link to message if in header view, not to header query
  (setq org-mu4e-link-query-in-headers-mode nil))
  ;; end of mu4e

 ;;rename files when moving
 ;;NEEDED FOR MBSYNC
 (setq mu4e-change-filenames-when-moving t)

  (setq mu4e-mu-binary "/usr/local/bin/mu")
  (use-package mu4e-alert
    :after mu4e
    :hook (;; (after-init . mu4e-alert-enable-mode-line-display)
           (after-init . mu4e-alert-enable-notifications))
    :config (mu4e-alert-set-default-style 'osx-notifier))

  (add-to-list 'mu4e-view-actions '("view in browser" . mu4e-action-view-in-browser))

  (add-hook 'mu4e-view-mode-hook #'visual-line-mode)

  (defvaralias 'mu4e-compose-signature 'message-signature)

  (setq mu4e-headers-show-threads nil) ; Use "P" to toggle threading

  (setq mu4e-org-contacts-file  (car org-contacts-files))
  ;;(add-to-list 'mu4e-headers-actions '("org-contact-add" . mu4e-action-add-org-contact) t)
  ;;(add-to-list 'mu4e-view-actions '("org-contact-add" . mu4e-action-add-org-contact) t)


  ;; sending mail
  (setq auth-sources '("~/.authinfo.gpg"
                       "~/Sync/shared/.authinfo.gpg"
                       "~/.authinfo"
                       "~/.netrc"))

  (use-package message
    :ensure nil
    :custom (send-mail-function 'smtpmail-send-it))

  (use-package smtpmail
    :ensure nil
    :custom
    (smtpmail-smtp-server "smtp.gmail.com")
    (smtpmail-smtp-service 465)
    (smtpmail-stream-type 'ssl)
    (message-kill-buffer-on-exit t "don't keep message buffers around"))

  ;; these are the standard mu4e search bookmarks
  ;; I've only added the fourth one to pull up flagged emails in my inbox
  ;; I sometimes use this to shortlist emails I need to get around to ASAP
  (setq mu4e-bookmarks
        `( ,(make-mu4e-bookmark
             :name  "Unread messages"
             :query "flag:unread AND NOT flag:trashed"
             :key ?u)
           ,(make-mu4e-bookmark
             :name "Today's messages"
             :query "date:today..now"
             :key ?t)
           ,(make-mu4e-bookmark
             :name "Last 7 days"
             :query "date:7d..now"
             :key ?w)
           ,(make-mu4e-bookmark
             :name "Flagged in Gmail INBOX"
             :query "maildir:\"/gmail/INBOX\" and flag:flagged"
             :key ?f)))

  ;; mu4e-contexts set in secrets.el

  ;; set `mu4e-context-policy` and `mu4e-compose-policy` to tweak when mu4e should
  ;; guess or ask the correct context, e.g.

  ;; start with the first (default) context;
  ;; default is to ask-if-none (ask when there's no context yet, and none match)
  (setq mu4e-context-policy 'pick-first)

  ;; compose with the current context if no context matches;
  ;; default is to ask
  (setq mu4e-compose-context-policy nil)

The gmail setup used is from Practical guide to use Gnus with Gmail.

The main difference is that I am not connecting to Network News servers at all. This gnus configuration is purely for gmail.

As suggested, I installed w3m and its emacs package:

brew install w3m

I set up personal information up earlier in this config at the Identify yourself section.

I have 2-step authentication on my gmail account, so the ~/.authinfo.gpg file contains the gmail application specific password.

gmail2bbdb -converts gmail contacts into bbdb file that gnus calls to complete email address. Clean the database with M-x bbdb-search-duplicates and use commands d for delete and M-x bbdb-merge-records.

(use-package nnir
  :disabled t
  :defer t
  :config
  ;; ask encyption password once
  (setq epa-file-cache-passphrase-for-symmetric-encryption t)
  (setq smtpmail-auth-credentials "~/.authinfo.gpg")
  (setq send-mail-function (quote smtpmail-send-it))
  ;;@see http://gnus.org/manual/gnus_397.html
  (setq gnus-select-method
        '(nnimap "gmail"
                 (nnimap-address "imap.gmail.com")
                 (nnimap-server-port 993)
                 (nnimap-stream ssl)
                 (nnir-search-engine imap)
                 (nnimap-authinfo-file "~/.authinfo.gpg")
                 ;; @see http://www.gnu.org/software/emacs/manual/html_node/gnus/Expiring-Mail.html
                 ;; press 'E' to expire email
                 (nnmail-expiry-target "nnimap+gmail:[Gmail]/Trash")
                 (nnmail-expiry-wait 90)))

  (setq-default
   gnus-summary-line-format "%U%R%z %(%&user-date;  %-15,15f  %B%s%)\n"
   gnus-user-date-format-alist '((t . "%Y-%m-%d %H:%M"))
   gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references
   gnus-sum-thread-tree-false-root ""
   gnus-sum-thread-tree-indent ""
   gnus-sum-thread-tree-leaf-with-other "-> "
   gnus-sum-thread-tree-root ""
   gnus-sum-thread-tree-single-leaf "|_ "
   gnus-sum-thread-tree-vertical "|")

  (setq gnus-thread-sort-functions
        '((not gnus-thread-sort-by-date)
          (not gnus-thread-sort-by-number)))

  ;; NO 'passive
  (setq gnus-use-cache t)
  (setq gnus-use-adaptive-scoring t)
  (setq gnus-save-score t)
  (add-hook 'mail-citation-hook 'sc-cite-original)
  (add-hook 'message-sent-hook 'gnus-score-followup-article)
  (add-hook 'message-sent-hook 'gnus-score-followup-thread)
  ;; @see http://stackoverflow.com/questions/945419/how-dont-use-gnus-adaptive-scoring-in-some-newsgroups
  (setq gnus-parameters
        '(("nnimap.*"
           (gnus-use-scoring nil))))

  (defvar gnus-default-adaptive-score-alist
    '((gnus-kill-file-mark (from -10))
      (gnus-unread-mark)
      (gnus-read-mark (from 10) (subject 30))
      (gnus-catchup-mark (subject -10))
      (gnus-killed-mark (from -1) (subject -30))
      (gnus-del-mark (from -2) (subject -15))
      (gnus-ticked-mark (from 10))
      (gnus-dormant-mark (from 5))))

  (setq  gnus-score-find-score-files-function
         '(gnus-score-find-hierarchical gnus-score-find-bnews bbdb/gnus-score))

  ;; BBDB: Address list
  (use-package bbdb
    :defer t
    :if (file-exists-p "/usr/share/emacs/site-lisp/bbdb")
    :load-path "/usr/share/emacs/site-lisp/bbdb"
    :init
    (setq bbdb-file "~/emacs.d/bbdb")
    (setq bbdb/mail-auto-create-p t
          bbdb/news-auto-create-p t)
    (defvar bbdb-time-internal-format "%Y-%m-%d"
      "The internal date format.")
    :config
    (bbdb-initialize 'message 'gnus 'sendmail)

    (add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus)

    ;; ###autoload
    (defun bbdb-timestamp-hook (record)
      "For use as a `bbdb-change-hook'; maintains a notes-field called `timestamp'
           for the given record which contains the time when it was last modified.  If
           there is such a field there already, it is changed, otherwise it is added."
      (bbdb-record-putprop record 'timestamp (format-time-string
                                              bbdb-time-internal-format
                                              (current-time)))))

  (add-hook 'message-mode-hook
            '(lambda ()
               (flyspell-mode t)
               (local-set-key "<TAB>" 'bbdb-complete-name)))

  ;; Fetch only part of the article if we can.  I saw this in someone
  ;; else's .gnus
  (setq gnus-read-active-file 'some)

  ;; Tree view for groups.  I like the organisational feel this has.
  (add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

  ;; Threads!  I hate reading un-threaded email -- especially mailing
  ;; lists.  This helps a ton!
  (setq gnus-summary-thread-gathering-function
        'gnus-gather-threads-by-subject)

  ;; Also, I prefer to see only the top level message.  If a message has
  ;; several replies or is part of a thread, only show the first
  ;; message.  'gnus-thread-ignore-subject' will ignore the subject and
  ;; look at 'In-Reply-To:' and 'References:' headers.
  (setq gnus-thread-hide-subtree t)
  (setq gnus-thread-ignore-subject t)

  ;; Change email address for work folder.  This is one of the most
  ;; interesting features of Gnus.  I plan on adding custom .sigs soon
  ;; for different mailing lists.
  ;; Usage, FROM: My Name <work>
  (setq gnus-posting-styles
        '((".*"
           (name "Heikki Lehväslaiho"
                 (address "heikki.lehvaslaiho@gmail.com"
                          (organization "CSC")
                          (signature-file "~/.signature")
                          ("X-Troll" "Emacs is better than Vi")
                          )))))

  ;; You need install the command line brower 'w3m' and Emacs plugin 'w3m'
  (setq mm-text-html-renderer 'w3m)
  (use-package w3m
    :defer t)
  (setq message-send-mail-function 'smtpmail-send-it
        smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil))
        smtpmail-auth-credentials '(("smtp.gmail.com" 587 "heikki.lehvaslaiho@gmail.com" nil))
        smtpmail-default-smtp-server "smtp.gmail.com"
        smtpmail-smtp-server "smtp.gmail.com"
        smtpmail-smtp-service 587
        smtpmail-local-domain "laptop")
  ;;http://www.gnu.org/software/emacs/manual/html_node/gnus/_005b9_002e2_005d.html
  (setq gnus-use-correct-string-widths nil)


  (defun my-gnus-group-list-subscribed-groups ()
    "List all subscribed groups with or without un-read messages"
    (interactive)
    (gnus-group-list-all-groups 5))

  (add-hook 'gnus-group-mode-hook
            ;; list all the subscribed groups even they contain zero un-read messages
            (lambda () (local-set-key "o" 'my-gnus-group-list-subscribed-groups ))))

PENDING Calender

Emacs-calf gives the look of Google Calendar as well as links to it and integrates org agenda entries.

My private function my/calendar is bound to incantation “Emacs, launch calendar” C-x l c.

(use-package calfw
  :defer t
  :init
  (setq cfw:fchar-junction ?╬
        cfw:fchar-vertical-line ?║
        cfw:fchar-horizontal-line ?═
        cfw:fchar-left-junction ?╠
        cfw:fchar-right-junction ?╣
        cfw:fchar-top-junction ?╦
        cfw:fchar-top-left-corner ?╔
        cfw:fchar-top-right-corner ?╗)
  ;; First day of the week
  (setq calendar-week-start-day 1) ; 0:Sunday, 1:Monday
  :config
  ;; not in melpa any more
  ;;(use-package calfw-org
  ;;  :defer t)
  (use-package calfw-ical
    :defer t)
  (defun my/calendar ()
    (interactive)
    (cfw:open-calendar-buffer
     :contents-sources
     (list
      (cfw:org-create-source "Blue")  ; org-mode source
      (cfw:ical-create-source "TripIt" my-tripit-ical "Green")  ; TripIt ICS, set in ~/.emacs.secrets.el
      (cfw:ical-create-source "gcal" my-gcal-ical "IndianRed")  ; google calendar ICS, set in ~/.emacs.secrets.el
      ))))

Elfeed

Elfeed is a sensible RSS feed reader. C-c f starts it and G updates the article list. r marks things as read and b opens them in browser. There are no folders but you can filter articles with s. Simple substring search with BBC works as expected, but to filter using tags, you have to precede them with a plus character, e.g. +emacs, or +e using my abbreviated tags. It possible to invert the query using ! preposition: i.e. to see feeds that do not match the query string.

y copies the current entry link URL to the clipboard for note taking.

Tags have to be written out whole before they match anything, so it is best to keep them short. Here are the mnemonics that work for me:

\+tagname
bBiology
cComics
eEmacs
dMobile
fFriends
jJournals
lLanguage
nNews
pPerl
sSecurity

elfeed-org package that makes elfeed to read the file ./elfeed.org for RSS URLs and loads them at runtime. This is more convinient than editing the lisp list and evaluating the statement.

The package author recommended binding filters to unused keys in elfeed window. My new keys bind to functions that do all the hard work in making selecting tags ever easier:

keyfunctionnote
0elfeed-read-allresets to my default filter
1elfeed-read-news-fiworld news in Finnish , removes pesky sport news
2elfeed-read-newsworld news, removes pesky sport news
3elfeed-read-journalsscience news
4elfeed-read-archeologyarcheology news
5elfeed-read-mobilemobile device news
6elfeed-read-comicslatest comics
7elfeed-read-emacsemacs news
8elfeed-read-cultureliterature, design, arts
9elfeed-read-friendsfriend’s feeds
Relfeed–mark-all-as-readone key to mark all visible articles

The read functions report their action in the echo field.

Elfeed-goodies needs Powerline font tweeking.

(use-package elfeed-org
  ;;:defer t
  ;;:after elfeed
  :config
  (elfeed-org))

(use-package elfeed
  :bind (("C-c f" . elfeed))
  :bind (:map elfeed-show-mode-map
              ("b" . elfeed-show-visit)
              ("l" . elfeed-show-link-title)
              ("v" . elfeed-show-quick-url-note))
  :bind (:map elfeed-search-mode-map
              ("=" . elfeed-update)
              ("R" . elfeed-mark-all-as-read)
              ("0" . elfeed-read-all)
              ("1" . elfeed-read-news-fi)
              ("2" . elfeed-read-news)
              ("3" . elfeed-read-journals)
              ("4" . elfeed-read-archaeology)
              ("5" . elfeed-read-mobile)
              ("6" . elfeed-read-comics)
              ("7" . elfeed-read-emacs)
              ("8" . elfeed-read-culture)
              ("9" . elfeed-read-friends)
              ("l" . elfeed-search-link-title)
              ("v" . elfeed-search-quick-url-note))
  :init
  (setq my/default-elfeed-search-filter "@1-month-ago +unread !sport ")
  (setq-default elfeed-search-filter my/default-elfeed-search-filter)
  (setq elfeed-sort-order 'ascending)
  (setq elfeed-search-title-max-width 80) ; newspaper articles have long titles
  (setq elfeed-use-curl t) ; new, using curl; now default, this is not needed
  :config

  (use-package elfeed-goodies
    :disabled t
    :defer t
    :config
    (elfeed-goodies/setup))

  (defun elfeed-mark-all-as-read ()
    "Mark currently shown articles read"
    (interactive)
    (mark-whole-buffer)
    (elfeed-search-untag-all-unread))

  (defun elfeed--read-tag (filter tag)
    "Template for filtering various feed categories.

   FILTER is the filter string to apply, and TAG is a short name of
   the displayed category.

   The cursor is moved to the beginning of the first feed line."
    (setq elfeed-search-filter filter)
    (elfeed-search-update :force)
    (goto-char (point-min))
    (message (concat "elfeed: show " tag)))

  (defun elfeed-read-all ()
    "Show all new titles (except sport)"
    (interactive)
    (elfeed--read-tag my/default-elfeed-search-filter "all"))

  (defun elfeed--remove-sports ()
    "Remove sports articles from world news"
    (setq elfeed-search-filter "@1-month-ago +unread +n sport")
    (elfeed-search-update :force)
    (elfeed-mark-all-as-read)
    (message "elfeed: sports removed"))

  (defun elfeed-read-news-fi ()
    "Show global news articles in Finnish"
    (interactive)
    (elfeed--remove-sports)
    (elfeed--read-tag "@1-month-ago +unread +fi " "Finnish news"))

  (defun elfeed-read-news ()
    "Show global news articles"
    (interactive)
    (elfeed--remove-sports)
    (elfeed--read-tag "@1-month-ago +unread +n " "news"))

  (defun elfeed-read-journals ()
    "Show scientific news from major journals"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +j " "journals"))

  (defun elfeed-read-archaeology ()
    "Show archeology news"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +a " "archaeology"))

  (defun elfeed-read-mobile ()
    "Show mobile device news"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +d " "mobile"))

  (defun elfeed-read-comics ()
    "Show latest online comics"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +c " "comics"))

  (defun elfeed-read-emacs ()
    "Show news on emacs"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +e " "emacs"))

  (defun elfeed-read-culture ()
    "Show news on culture"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +cu " "culture"))

  (defun elfeed-read-friends ()
    "Show news from friends"
    (interactive)
    (elfeed--read-tag "@1-month-ago +unread +f " "friends"))

  ;;
  ;; linking and capturing
  ;;


  ;; show mode

  (defun elfeed-show-link-title ()
    "Copy the current entry title and URL as org link to the clipboard."
    (interactive)
    (let* ((title (elfeed-entry-title elfeed-show-entry))
           (link (elfeed-entry-link elfeed-show-entry))
           (titlelink (org-make-link-string link title)))
      (when titlelink
        (kill-new titlelink)
        (gui-set-selection 'PRIMARY titlelink)
        (message "Yanked: %s" titlelink))))

  (defun elfeed-show-quick-url-note ()
    "Fastest way to capture entry link to org agenda from elfeed show mode"
    (interactive)
    (elfeed-show-link-title)
    (org-capture nil "n")
    (yank)
    (org-capture-finalize))

  ;; search mode

  (defun elfeed-link-title (entry)
    "Copy the entry title and URL as org link to the clipboard."
    (interactive)
    (let* ((title (or (elfeed-meta entry :title)
                      (elfeed-entry-title entry)))
           (link (elfeed-entry-link entry))
           (titlelink (org-make-link-string link title)))
           (when titlelink
             (kill-new titlelink)
             (gui-set-selection 'PRIMARY titlelink)
             (message "Yanked: %s" titlelink))))

  (defun elfeed-search-link-title ()
    "Copy the current entry title and URL as org link to the clipboard."
    (interactive)
    (let ((entry (elfeed-search-selected t)))
      (when (elfeed-entry-link entry)
        (elfeed-link-title (entry) ))))

  (defun elfeed-search-quick-url-note ()
    "In search mode, capture the title and link for the selected
            entry or entries in org aganda."
    (interactive)
    (let ((entries (elfeed-search-selected)))
      (cl-loop for entry in entries
               do (elfeed-untag entry 'unread)
               when (elfeed-entry-link entry)
               do (elfeed-link-title entry)
               do (org-capture nil "n")
               do (yank)
               do (org-capture-finalize)
               (mapc #'elfeed-search-update-entry entries))
      (unless (use-region-p) (forward-line)))))

Twitter

Twittering mode (Github)gives a full blown twitter client with avatar images, filtering, and posting. The key map incantation is “Emacs, launch twItter”, C-x l i (because t and w) were taken).

I have the prerequisites installed from homebrew: gnutls, GnuPG, ImageMagick, gzip.

Common keys:

  • start C-x l i
  • next j, previous k article
  • open URL in browser <TAB>...<Enter>
  • open user timeline v
  • interactive timeline V
    • e.g. V #emacs <Enter> to follow tweets with hashtag #emacs
  • next f, previous b timeline
  • top of page H
  • u post new tweet in current timeline

See https://github.com/abo-abo/hydra/wiki/Twittering

(use-package twittering-mode
  :defer t
  :commands twit
  :init
  (add-hook 'twittering-edit-mode-hook (lambda () (flyspell-mode)))
  :config
  (setq twittering-use-master-password t
        twittering-icon-mode t
        twittering-use-icon-storage t
        twittering-timer-interval 120
        twittering-convert-fix-size 52
        twittering-initial-timeline-spec-string '(":home")
        twittering-edit-skeleton 'inherit-any
        twittering-display-remaining t
        twittering-timeline-footer  ""
        twittering-timeline-header  "")

  ;; better status format
  (setq twittering-status-format
        "%FOLD{%RT{%FACE[bold]{RT}}%i%s  %r %@{}\n%FILL[          ]{%T%RT{\nretweeted by %s @%C{%Y-%m-%d %H:%M:%S}}}}")
  ;; mode line symbol
  (add-hook 'twittering-mode-hook
            '(lambda () (setq mode-name "")))
  ;; hydra
  (defhydra hydra-twittering (:color blue :hint nil)
    "
                                                                    ╭────────────┐
     Tweets                User                        Timeline     │ Twittering │
  ╭─────────────────────────────────────────────────────────────────┴────────────╯
    _k_  [_t_] post tweet      _p_  [_f_] follow                  ^_g_^      [_u_] update
    ^↑^  [_X_] delete tweet    ^↑^  [_F_] unfollow              ^_S-SPC_^    [_._] new
    ^ ^  [_r_] retweet         ^ ^  [_d_] direct message          ^^↑^^      [^@^] current user
    ^↓^  [_R_] retweet & edit  ^↓^  [_i_] profile (browser)   _h_ ←   → _l_  [_a_] toggle
    _j_  [_b_] favorite        _n_   ^ ^                          ^^↓^^
    ^ ^  [_B_] unfavorite      ^ ^   ^ ^                         ^_SPC_^
    ^ ^  [_RET_] reply         ^ ^   ^ ^                          ^_G_^
    ^ ^  [_T_] show Thread
    ^ ^  [_y_] yank url          Items                     Do
    ^ ^  [_Y_] yank tweet     ╭───────────────────────────────────────────────────────
    ^ ^  [_e_] edit mode        _<backtab>_ ← _o_pen → _<tab>_    [_q_] exit
    ^ ^   ^ ^                   ^         ^   ^ ^      ^     ^    [_/_] search
  --------------------------------------------------------------------------------
       "
    ("\\" nil "quit")
    ("q"          twittering-kill-buffer)
    ("e"          twittering-edit-mode)
    ("j"          twittering-goto-next-status :color red)
    ("k"          twittering-goto-previous-status :color red)
    ("h"          twittering-switch-to-next-timeline :color red)
    ("l"          twittering-switch-to-previous-timeline :color red)
    ("g"          beginning-of-buffer)
    ("G"          end-of-buffer)
    ("t"          twittering-update-status-interactive)
    ("X"          twittering-delete-status)
    ("RET"        twittering-reply-to-user)
    ("r"          twittering-native-retweet)
    ("R"          twittering-organic-retweet)
    ("d"          twittering-direct-message)
    ("u"          twittering-current-timeline)
    ("b"          twittering-favorite)
    ("B"          twittering-unfavorite)
    ("f"          twittering-follow)
    ("F"          twittering-unfollow)
    ("i"          twittering-view-user-page)
    ("/"          twittering-search)
    ("."          twittering-visit-timeline)
    ("@"          twittering-other-user-timeline)
    ("T"          twittering-toggle-or-retrieve-replied-statuses)
    ("o"          twittering-click)
    ("<tab>"        twittering-goto-next-thing :color red)
    ("<backtab>"  twittering-goto-previous-thing :color red)
    ("n"          twittering-goto-next-status-of-user :color red)
    ("p"          twittering-goto-previous-status-of-user :color red)
    ("SPC"        twittering-scroll-up :color red)
    ("S-SPC"      twittering-scroll-down :color red)
    ("y"          twittering-push-uri-onto-kill-ring)
    ("Y"          twittering-push-tweet-onto-kill-ring)
    ("a"          twittering-toggle-activate-buffer))
  ;; set the new bindings
  (bind-keys :map twittering-mode-map
             ("\\" . hydra-twittering/body)
             ("q" . twittering-kill-buffer)
             ("Q" . twittering-edit-mode)
             ("j" . twittering-goto-next-status)
             ("k" . twittering-goto-previous-status)
             ("h" . twittering-switch-to-next-timeline)
             ("l" . twittering-switch-to-previous-timeline)
             ("g" . beginning-of-buffer)
             ("G" . end-of-buffer)
             ("t" . twittering-update-status-interactive)
             ("X" . twittering-delete-status)
             ("RET" . twittering-reply-to-user)
             ("r" . twittering-native-retweet)
             ("R" . twittering-organic-retweet)
             ("d" . twittering-direct-message)
             ("u" . twittering-current-timeline)
             ("b" . twittering-favorite)
             ("B" . twittering-unfavorite)
             ("f" . twittering-follow)
             ("F" . twittering-unfollow)
             ("i" . twittering-view-user-page)
             ("/" . twittering-search)
             ("." . twittering-visit-timeline)
             ("@" . twittering-other-user-timeline)
             ("T" . twittering-toggle-or-retrieve-replied-statuses)
             ("o" . twittering-click)
             ("TAB" . twittering-goto-next-thing)
             ("<backtab>" . twittering-goto-previous-thing)
             ("n" . twittering-goto-next-status-of-user)
             ("p" . twittering-goto-previous-status-of-user)
             ("SPC" . twittering-scroll-up)
             ("S-SPC" . twittering-scroll-down)
             ("y" . twittering-push-uri-onto-kill-ring)
             ("Y" . twittering-push-tweet-onto-kill-ring)
             ("a" . twittering-toggle-activate-buffer)))

EPUB reader

nov.el is already better for reading EPUB texts than ereader, and it is being rapidly developed further.

I installed Liberation Serif for nov.el use.

;;  (use-package ereader
;;    :config
;;    (add-hook 'ereader-mode-hook #'line-break-mode)
;;    (add-hook 'ereader-mode-hook #'visual-line-mode))

(use-package nov
  :defer
  :init
  (push '("\\.epub\\'" . nov-mode) auto-mode-alist)
  :config
  (setq nov-text-width 80)
  (defun my-nov-font-setup ()
    (face-remap-add-relative 'variable-pitch :family "Liberation Serif"
                             :height 2.0))
  (add-hook 'nov-mode-hook 'my-nov-font-setup)
  ;; (add-hook 'nov-mode-hook #'line-break-mode)
  (add-hook 'nov-mode-hook #'visual-line-mode))

Web browsing

PENDING w3m

The emacs package emacs-w3m gives access to the commandline programme w3m. The w3m cheat sheet.

Put the cursor inside an URL and incant: Emacs, lauch web C-x l w.

(setq browse-url-browser-function 'w3m-browse-url)
(setq browse-url-browser-function 'browse-url-default-browser)
(use-package w3m
  :defer t
  :init (setq w3m-use-cookies t)
  :config (autoload 'w3m-browse-url "w3m" "Ask a WWW browser to show a URL." t))

Web browser text editing

I have been using Edit with Emacs, but this announcement made me move to a newer framework called Atomic Chrome that allows bi-directional communication between the browser text fields and Emacs.

You need to install this Chrome extension or read more to use it from Firefox.

Set major mode based on the website.

(use-package atomic-chrome
  :custom
  (atomic-chrome-url-major-mode-alist
   '(("reddit\\.com" . markdown-mode)
     ("github\\.com" . gfm-mode))
   "Major modes for URLs")
  :config
  (atomic-chrome-start-server))

Atomic-chrome server is not starting. If I run the commands manually from the function, it works. What is wrong? Solved: start server under config, not init.

Calculator

For a long time I used python interactive command line mode to do simple calculations. I now use mostly quick-calc which has key binding C-x l = as part of my launch hydra. The default calc has strange setup that gives multiplication a higher precedence than division. The following fixes it.

(setq-default calc-multiplication-has-precedence nil)

The full blown calc has facinating possibilities that I explore occasionally but not often enough to learn to use it effectively.

World Clock

The built-in command display-time-world opens a new buffer with current time in a selection of time zones. The values displayed can be modified using a variable display-time-world-list.

(setq display-time-world-list
      '(("Europe/London" "London")
        ("Africa/Johannesburg" "Cape Town")
        ("Europe/Paris" "Paris")
        ("Europe/Amsterdam" "Amsterdam")
        ("Europe/Zurich" "Geneva")
        ("Europe/Helsinki" "Helsinki")
        ("Asia/Riyadh" "Jeddah")
        ("Indian/Mauritius" "Mauritius")
        ("Asia/Kolkata" "Delhi")
        ("Asia/Kathmandu" "Kathmandu")
        ("Asia/Tokyo" "Tokyo")
        ("America/New_York" "New York")
        ("America/Los_Angeles" "Seattle")))

I have added command display-time-world in my launch hydra to use the incantation “Emacs, launch time Zones”. C-x l z.

Buffer sharing

sacha chua: impatient-mode to share your buffer

  1. Install the impatient-mode package.
  2. Call M-x httpd-start.
  3. Configure the firewall to allow incoming connections.
  4. Put the selected buffer into impatient-mode.
  5. Share the link with my IP address (form: http://my.ip.ad.dress:8080/imp/)

Binclock

Binary clock in the message area.

(use-package binclock
  :defer 5)

PENDING Blogging with org-webpage

org-webpage is based on org-page, a simple static page website generator. I moved my blog quite easily to org-webpage.

org-webpage is now called org2web. This code needs updating.

Command owp/do-publication seems to do all I need.

#

#

#

#

#

(use-package org-webpage
  :config
  (owp/add-project-config
   '("heikkil.github.io"
     :repository-directory "~/src/org-webpage/heikkil.github.io"
     :remote (git "https://github.com/heikkil/heikkil.github.io.git" "master")
     ;; you can use `rclone` with `:remote (rclone "remote-name" "/remote/path/location")` instead.
     :site-domain "http://heikkil.github.io/"
     :site-main-title "Heikki @ home"
     :site-sub-title "Loose leaves from my tree"
     :theme (sans)
     :category-ignore-list ("themes")
     :source-browse-url ("Github" "https://github.com/heikkil/heikkil.github.io")
     :personal-avatar "https://avatars0.githubusercontent.com/u/75674?v=3&s=460"
     :personal-duoshuo-shortname "heikki-home"
     :web-server-port 8000))
  )

easy-hugo

I really like Hugo static site generator and I’ve created a few websites with it. The latest (0.19) version includes built-in support for org-mode. masasam/emacs-easy-hugo: Emacs package for writing blogs made with hugo

(use-package easy-hugo
  :init
  (setq easy-hugo-basedir "~/hugo/test/")
  (setq easy-hugo-url "https://example.org/")
  (setq easy-hugo-sshdomain "blogdomain")
  (setq easy-hugo-root "/home/blog/")
  (setq easy-hugo-previewtime "300")
  :config
  (defhydra hydra-blog (:color blue :hint nil)
    "
             blog  _n_: new article        _l_: list articles
                   _p_: preview            _P_: publish
                   "
    ("n" easy-hugo-newpost)
    ("p" easy-hugo-preview)
    ("l" easy-hugo-article)
    ("P" easy-hugo-publish))
  :bind ("C-c o" . hydra-blog/body))

Password management

Command pass gives access to similarly named command line utility.

(use-package pass
  :defer t
  :config
  (add-hook 'password-store-mode-hook
            (lambda () (view-mode -1))))

(use-package auth-source-pass
  :defer t
  :config
  (auth-source-pass-enable))

eshell

Eshell is a shell written in elisp that integrates with with emacs environment. My shortcut incantation is “Emacs, launch shell”, C-x l x. (Sorry, does not make sense!)

The use of directory file:~/.emacs.p is from Eshell Customizations.

(use-package eshell
  :config
  (setenv "PAGER" "cat")

  (setq eshell-history-size 100000
        eshell-directory-name "~/.emacs.p/eshell")

  (defun eshell/dd (&rest args)
    (dired (pop args) "."))

  (defun eshell/d ()
    "Open a dired instance of the current working directory."
    (dired "."))

  (defun eshell/q ()
    "Send the *eshell* buffer to the back of buffer list."
    (bury-buffer)))

Autosuggest on eshell

dieggsy/esh-autosuggest: Fish-like autosuggestions in eshell.

(use-package esh-autosuggest
  :hook (eshell-mode . esh-autosuggest-mode))

shell

Shell process in emacs is better for managing and piping big data sets. Shell & Comint Secrets: History commands - Mastering Emacs

Command history with replacement works with ^a^b^ and =<Space> = after binding the magic space command to the space key.

(define-key shell-mode-map (kbd "SPC") 'comint-magic-space)

PENDING Process management

The package vkill makes it possible to kill UNIX processes from emacs. This package works under OS X, too.

(use-package vkill
  :defer t)

Ediff

Better defaults for ediff.

Remember the spell “Emacs, Launch eDiff”, C-x l d.

This setting activates winner mode to return the previous window setup by C-c left.

Quickly ediff files from dired · (or emacs by pressing e after two files have been selected.

;; custom macro for changing custom values
(defmacro csetq (variable value)
  `(funcall (or (get ',variable 'custom-set)
                'set-default)
            ',variable ,value))

;; no separate frame for the control panel
(csetq ediff-window-setup-function 'ediff-setup-windows-plain)
;; split horizontally
(csetq ediff-split-window-function 'split-window-horizontally)
;; ignore whitespace
(csetq ediff-diff-options "-w")

;; remove ediff buffers and restore previous window settings
(use-package winner
  :defer t
  :config (winner-mode 1)
  (add-hook 'ediff-after-quit-hook-internal 'winner-undo))

;; clever ediff of two marked files
;; -*- lexical-binding: t -*-
(defun ora-ediff-files ()
  (interactive)
  (let ((files (dired-get-marked-files))
        (wnd (current-window-configuration)))
    (if (<= (length files) 2)
        (let ((file1 (car files))
              (file2 (if (cdr files)
                         (cadr files)
                       (read-file-name
                        "file: "
                        (dired-dwim-target-directory)))))
          (if (file-newer-than-file-p file1 file2)
              (ediff-files file2 file1)
            (ediff-files file1 file2))
          (add-hook 'ediff-after-quit-hook-internal
                    (lambda ()
                      (setq ediff-after-quit-hook-internal nil)
                      (set-window-configuration wnd))))
      (error "no more than 2 files should be marked"))))

(define-key dired-mode-map "e" 'ora-ediff-files)

Phonetic alphabet

[[http://en.wikipedia.org/wiki/NATO_phonetic_alphabet][NATO phonetic alphabet] is an invaluable help in passing names and IDs through bad telephone or slow network lines. Next time you call the airline with your reservation number, write it down, select it and apply function M-x nato-region or C-x l n.

Note: nato-region does not place the cursor at the end of the converted region if the last character has been converted. This prevents you direct application of denato-region to reverse the change.

Regex tool

Coming from perl regexps, I find emacs regexps confusing. Launch re-builder to match anything in your current buffer. The shortcut is “Emacs, launch re-builder”, C-x l r.

As recommended in Mastering emacs, I’ve set the syntax to “string” that escaped one set of backlashes. C-c C-w will copy the created regexp and correct the syntax to be pasted into elisp.

I am now testing re-builder with rx syntax. The details of the syntax are documented under rx:

(describe-symbol 'rx)
(use-package re-builder
  :defer 5
  :init
  ;; (setq reb-re-syntax 'string)
  (setq reb-re-syntax 'rx))

jwiegley/regex-tool is similar tool for PCRE regexps.

M-x qrr runs query-replace-regexp that by default has a really complicated key binding M-C-S %.

Read more on emacs regexps.

ChangeLog mode

While git and other distributed version control systems (see Version control) do a great job in keeping track of changes projects, sometimes you need something more general. Enter ancient ChangeLog mode that predates all version control systems. It assumes that there is file called ChangeLog somewhere in the file hierarchy above the current file and gives you a strange key chord C-x 4 a to add an entry to it.

I use it to keep a log of OS-wide changes to my computers (thanks for Martin Senger for teaching me the habit!). Each computer has a ChangeLog file in its own directory and the whole project is under git control. When running install, uninstall, or configure commands I open the relevant file and create a record of the change and where the information came from.

How Do I?

Query programming problems within emacs by howdoi-query or howdoi-query-line-at-point. This will google the answer in StackOverflow, and parse and return best answers.

;; execute this lisp code in org mode
;; by placing the curser after
;; the closing parenthesis and press C-x C-e
(describe-package 'howdoi)
(use-package howdoi
  :defer 5)

Timer

The simple countdown timer: tea-timer.el. Not yet in MELPA. Using a local copy.

Run C-u 10 M-x tea-timer to get the alert after 10 minutes.

(use-package tea-timer
  :defer t
  ;; :bind (:map pdf-view-mode-map ("e" . org-pdfquote-open))
  :load-path "elisp/"
  :init
  (setq tea-timer-default-duration 1.5)
  (setq tea-timer-message "Tea is ready!"))

Toys

PENDING xkcd comics

The xkcd package implements an xkcd comics reader for Emacs. I use Elfeed to read it, the key binding used now elsewhere.

KeybindingUseFunction
tShow alt-text in the minibuffer(xkcd-alt-text)
rShow random strip(xkcd-rand)
qKill buffer(xkcd-kill-buffer)
<right>Load next xkcd(xkcd-next)
<left>Load previous xkcd(xkcd-prev)
o/bShow strip in browser(xkcd-open-browser)
eShow explanation to strip(xkcd-open-explanation-browser)
(use-package xkcd
  :defer t
  ;;:bind ("C-c x" . xkcd)
  :config
  (bind-keys :map xkcd-mode-map
             ("b" . xkcd-open-browser)))

2048-game

Start a pure emacs and text-only version of the 2048 game with C-x l 2.

(use-package 2048-game
  :defer 5)