You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

94 KiB

emacs init file

TODO Make indentation uniform

Introduction

setq vs setq-default

Some variables are buffer-local, others are not; for non buffer-local variables the two commands are equivalent; for the buffer-local variables, setq acts on the current buffer, whereas setq-default sets the default value of the variable for buffers that do not have a local value.

:source: [https://stackoverflow.com/a/18173666]

Why not package.el

it is convenient, but it is not git-based; borg.el is promising, but it is way complicated; I can do everything by hand as soon as it is neatly org-anized. In the end we use a few, but I plan to phase them out and replace them with git submodules

Files and dirs

Move Customize to a separate file

  (setq custom-file "~/.emacs.d/custom.el")
  (load custom-file 'noerror)

Add relevant dirs to load path [This is somewhat undesirable; I should uniformize the path-loading business at some point…]

  (let ((default-directory "~/.emacs.d/"))
    (normal-top-level-add-subdirs-to-load-path)
    (normal-top-level-add-to-load-path '("biblio.el"
                                         "fringe-helper.el"
                                         "multiple-cursors.el"
                                         "expand-region.el"
                                         "dash.el"
                                         "webpaste.el"
                                         "highlight-parentheses.el")))

Put autosave files (ie #foo#) and backup files (ie foo~) in ~/.emacs.d/. create the autosave dir if necessary, since emacs won't.

  (make-directory "~/.emacs.d/autosaves/" t)
  (make-directory "~/.emacs.d/backup/" t)

Themes

Use (my clone of) the solarized theme

  (add-to-list 'custom-theme-load-path "/home/jacopods/.emacs.d/emacs-color-theme-solarized")
  (load-theme 'lunarized t)

Use patched terminus font (this overrides the settings in Customize, but I never could it to work otherwise). See the special treatment later on for dealing with bold weight. To avoid flickering one should also set the font in .Xresources

  (set-face-font 'default "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1")
  (set-face-font 'fixed-pitch "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1")
  (set-face-font 'fixed-pitch-serif "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1")
  (set-face-font 'variable-pitch "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1")

Global settings

Global helper functions

This is a helper function used to set several global keys given in provided as a parameter in binding-alist

  (defun global-set-key-alist (binding-alist)
    "This function iterates over the binding-alist, which should be an alist of key and binding and sets each binding in the global-key-map"
    (dolist (binding binding-alist)
      (global-set-key (kbd (car binding)) (cdr binding))))

  (defun define-key-alist (keymap binding-alist)
    "This function iterates over the binding-alist, which should be an alist of key and binding and sets each binding in the global-key-map"
    (dolist (binding binding-alist)
      (define-key keymap (kbd (car binding)) (cdr binding))))

This is a hack to remove slant and bold from all faces

  (defun wilder/fixup-faces ()
    (interactive)
    (mapc (lambda (face)
       (set-face-attribute face nil :weight 'normal)
       (set-face-attribute face nil :slant 'normal))
     (face-list))
  (set-face-font 'default "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1"))

Cosmetics

Prefer a minimal appearance: no menu, toolbar or scroll-bars; no splash screens or messages

  (menu-bar-mode -1)
  (tool-bar-mode 0)
  (scroll-bar-mode -1)
  (setq inhibit-startup-screen t
        inhibit-startup-message t)

a blinking cursor keeps the gpu awake; add global hl-line mode to more easily spot the cursor

  (blink-cursor-mode 0)
  (set-default 'cursor-type 'box)

Set frame title

  (setq frame-title-format
     '((buffer-file-name "%f"
         (dired-directory dired-directory "%b")) " · emacs"));; · " (:eval (kde-current-activity-name)))) ;; "%S"))

Themed tooltips

(setq x-gtk-use-system-tooltips nil)

Set fill-column to 72, which happens to be good for third-tiled frames and it also is a reasonable standard

  (setq default-fill-column 72)

Highlight sexp (apparently I am not even using this)

  ;(require 'highlight-sexps)

Try to get along with large margins

  (setq-default left-margin-width 3
                right-margin-width 3)
  (fringe-mode 10)
  ;(set-window-buffer nil (current-buffer))

Mouseless

Disable mouse interaction with emacs

  (mouse-wheel-mode -1)
  (setq mouse-autoselect-window nil
        mouse-yank-at-point nil
        focus-follows-mouse nil
        mouse-highlight nil)

TODO Find out what of the above is necessary given the disable-mouse mode below

Use the disable-mouse package by Steve Purcell available at [https://github.com/purcell/disable-mouse]

  (require 'disable-mouse)
  (global-disable-mouse-mode)

Window behavior

Prevent compilation window eating up other windows

   (setq compilation-window-height 12
         compilation-scroll-output nil)

Prevent any automatic splitting to split vertically

  (setq split-height-threshold 0)

Scrolling

Scrolling setup

   (setq redisplay-dont-pause t
         scroll-margin 3
         scroll-step 1
         scroll-conservatively 10000
         scroll-preserve-screen-position 1)

TODO find out what this was actually meant to do

  (setq-default display-buffer-reuse-frames t)

Mode-line

  (setq-default mode-line-modified '(:eval (if (buffer-modified-p) "●" "·"))
  ;Still needs some improvements, does not report Readonly state
                mode-line-remote '(:eval (let ((s (format-mode-line "%@")))
                                           (cond
                                            ((equal s "-") " ") ((equal s "@") "@") (t s)))))

  (defface mode-line-indicator
    '((t nil))
    "mode-line active indicator"
    :group 'mode-line-faces)

  (defface mode-line-inactive-indicator
    '((t nil))
    "Inactive variant of indicator"
    :group 'mode-line-faces)


  ;; This has some issues when two buffers are shown in different windows
  ;; There are some solutions but let us see if this works first
  (defun mode-line-update-face (window)
    "Update the `mode-line' face in WINDOW to indicate whether the window is selected."
    (with-current-buffer (window-buffer window)
      (if (eq (current-buffer) (window-buffer (selected-window)))
          (face-remap-reset-base 'mode-line-indicator)
        (face-remap-set-base 'mode-line-indicator (face-all-attributes 'mode-line-inactive-indicator)))))

  (add-hook 'buffer-list-update-hook (lambda () (walk-windows #'mode-line-update-face nil t)))

  (defvar wilder-buffer-vc-mode-line
    '("%b" (vc-mode (:propertize
                     ;; Strip the backend name from the VC status information
                     (:eval (let* ((backend (downcase (symbol-name (vc-backend (buffer-file-name)))))
                                   (branch (substring vc-mode (+ (length backend) 2)))
                                   (s (substring vc-mode (+ (length backend) 1) (+ (length backend) 2)))
                                   (status (cond ((equal s "-") "") ((equal s ":") "!") (t s))))
                              (concat "·" branch status)))
                     face magit-branch-local))))

  (defvar wilder-position
    '("%p · %I" ))

  (put 'wilder-buffer-vc-mode-line 'risky-local-variable t)
  (put 'wilder-position 'risky-local-variable t)

  (defvar wilder/mode-line-modes
    (let ((recursive-edit-help-echo "Recursive edit, type C-M-c to get out"))
      (list (propertize "%[" 'help-echo recursive-edit-help-echo)
            '("" mode-name)
            '("" mode-line-process)
            " "
            '("" minor-mode-alist)
            (propertize "%n" 'help-echo "mouse-2: Remove narrowing from buffer"
                        'mouse-face 'mode-line-highlight
                        'local-map (make-mode-line-mouse-map
                                    'mouse-2 #'mode-line-widen))
            (propertize "%]" 'help-echo recursive-edit-help-echo)
            " "))
    "Mode line construct for displaying major and minor modes.")

  (put 'wilder/mode-line-modes 'risky-local-variable t)

  (setq-default header-line-format nil);'("%e" ));wilder-buffer-vc-mode-line))

  (setq mode-line-separator
    '(:eval (let* ((len-left (length (format-mode-line mode-line-format-left)))
                   (len-right (length (format-mode-line mode-line-format-right)))
                   (len-separator (- (+ (window-width) 2 2 2) (+ len-left len-right))))
              (format (format "%%%ds" len-separator) ""))))

  (setq mode-line-format-left
    '("%e"
      mode-line-front-space
      mode-line-front-space
      mode-line-front-space
      ; mode-line-mule-info
      mode-line-modified
      mode-line-remote
      mode-line-frame-identification
      wilder-buffer-vc-mode-line
      "  "
      wilder-position))

  (setq mode-line-format-right
    '((:propertize " " face mode-line-indicator)
      wilder/mode-line-modes
      mode-line-misc-info
      "   "))

  (put 'mode-line-format-left 'risky-local-variable t)
  (put 'mode-line-format-right 'risky-local-variable t)
  (put 'mode-line-separator 'risky-local-variable t)

  (setq-default mode-line-format
                '("%e" mode-line-format-left
                  mode-line-separator
                  mode-line-format-right))

The following has been found in here to clean up the modeline

  (defvar mode-line-cleaner-alist
    `((auto-complete-mode . " α")
      (yas/minor-mode . " υ")
      (paredit-mode . " π")
      (eldoc-mode . "")
      (abbrev-mode . "")
      (auto-fill-function . "")
      (disable-mouse-global-mode . "")
      (auto-revert-mode . "")
      (helm-mode . " η" )
      (smart-tab-mode . "")
      (subword-mode . "")
      (outshine-mode . " o")
      (outline-minor-mode . "")
      (reftex-mode . "")
      (flyspell-mode . "")
      ;; Major modes
      (lisp-interaction-mode . "λ")
      (hi-lock-mode . "")
      (python-mode . "Py")
      (emacs-lisp-mode . "EL")
      (tex-mode . "χ")
      (latex-mode . "χ")
      (TeX-latex-mode . "χ")
      (org-mode . "Ω")
      (org-agenda-mode . "Ω:Agenda"))
    "Alist for `clean-mode-line'.

  When you add a new element to the alist, keep in mind that you
  must pass the correct minor/major mode symbol and a string you
  want to use in the modeline *in lieu of* the original.")

  (defun clean-mode-line ()
    (interactive)
    (loop for cleaner in mode-line-cleaner-alist
          do (let* ((mode (car cleaner))
                    (mode-str (cdr cleaner))
                    (old-mode-str (cdr (assq mode minor-mode-alist))))
               (when old-mode-str
                 (setcar old-mode-str mode-str))
               ;; major mode
               (when (eq mode major-mode)
                 (setq mode-name mode-str)))))


  (add-hook 'after-change-major-mode-hook 'clean-mode-line)

Coding system

Prefer the utf-8 coding system globally. This helps with the issue of magit not correctly staging hunks containing utf-8 characters. See [https://github.com/magit/magit/issues/32]

  (prefer-coding-system 'utf-8)

Mark handling

No transient mark is more flexible

(transient-mark-mode 0)

But of course we need to see the mark

(require 'visible-mark)
(visible-mark-mode t)
(global-visible-mark-mode t)

The following are some convenient bindings; notice that on my layout F13 and F14 are obtained by tapping the left and right shift respectively

  (defun jump-to-mark ()
    "Jumps to the local mark, respecting the `mark-ring' order.
  This is the same as using \\[set-mark-command] with the prefix argument."
    (interactive)
    (set-mark-command 1))

  (defun just-activate-mark ()
    (interactive)
    (activate-mark))

  (global-set-key-alist
   '(("<f13>"   . set-mark-command)
     ("<f14>"   . set-mark-command)
     ("<M-f13>" . jump-to-mark)
     ("<M-f14>" . jump-to-mark)
     ("<S-f13>" . just-activate-mark)
     ("<S-f14>" . just-activate-mark)))

Global bindings

Remove some bindings that I find supremely annoying. Additionally, unbind the C-x o binding to force me using ace-window Finally, unbind the C-SPC to mark the point, as I am using LR-shift Note that I will use C-SPC as a hydra below to deal with parenthesis

  (mapcar
   (lambda (ch)
     (global-unset-key (kbd ch)))
     '("C-z" "C-x f" "<M-f4>" "C-M-u" "C-M-d" "C-x o" "C-SPC"))

Change {up,down}-list

  (global-set-key (kbd "C-M-i") 'down-list) ;; -i stands for /in/
  (global-set-key (kbd "C-M-o") 'up-list)   ;; -o stands for /out/

Add some opinionated bindings

  (global-set-key-alist
   '(("C-M-d"           . kill-sexp)
     ("C-M-<backspace>" . backward-kill-sexp)
     ("C-x k"           . kill-this-buffer)
     ("C-S-v"           . scroll-down-command)
     ("C-M-u"           . universal-argument)))

Disable commands

Enable narrow commands

  (put 'narrow-to-region 'disabled nil)
  (put 'LaTeX-narrow-to-environment 'disabled nil)
  (put 'narrow-to-page 'disabled nil)

Smart beginning-of-line

This is a relatively smart way to go back to the beginning of the line

  (defun smart-line-beginning ()
  "Move point to the beginning of text on the current line; if that
  is already the current position of point, then move it to the
  beginning of the line."
(interactive)
(let ((pt (point)))
(beginning-of-line-text)
(when (eq pt (point))
  (beginning-of-line))))
   (global-set-key (kbd "C-a") 'smart-line-beginning)

Whitespace

Trailing whitespace is evil; get rid of it unless we are in special modes, namely calendar (and later mu4e)

  (setq-default show-trailing-whitespace t)
  (add-hook 'calendar-mode-hook
              #'(lambda () (setq-local show-trailing-whitespace nil)))
  (add-hook 'before-save-hook 'delete-trailing-whitespace)

Define what is whitespace during a search

     (setq search-whitespace-regexp "[ \t\r\n]+")

Tabs are evil; get rid of them

  (setq c-basic-offset 4)
  (setq-default tab-width 4
                indent-tabs-mode nil)

TODO Have a look at ws-trim.el

It is conf'ble to avoid removing whitespace from lines that were not modified; sounds like a good idea for git [ftp://ftp.lysator.liu.se/pub/emacs/ws-trim.el]

Show matching parens

Use show-paren for paren-highlighting

  (show-paren-mode 1)

TODO find out if there are better options out there

Load hydra

(require 'hydra)

Abbrevs

Set up abbrevs

   (setq-default abbrev-mode t)
   (read-abbrev-file "~/.abbrev_defs")
   (setq save-abbrevs t)

Spellcheck

Use flyspell

  (require 'flyspell-lazy)
  (flyspell-lazy-mode 1)
  (add-hook 'text-mode-hook 'flyspell-mode)
  (setq flyspell-use-meta-tab nil)
  (defface flyspell-margin-incorrect
         '((t nil))
         "flyspell-margin-incorrect"
         :group 'flyspell)
  (setq flyspell-before-incorrect-word-string
  (propertize "." 'display `((margin left-margin)
  ,(propertize "×" 'face 'flyspell-margin-incorrect))))

Fringe treatment

TODO try linum-relative

;      (require 'linum-relative)
;      (linum-relative-mode 1)

Add line numbers globally

;    (global-linum-mode 1)

Highlight also the linum in the fringe

;    (require 'hlinum)
;    (hlinum-activate)

Add marker for current line in the margin (see [https://github.com/kyanagi/fringe-current-line] and [https://github.com/nschum/fringe-helper.el] for inspiration)

  (require 'margin-current-line)
  (global-margin-current-line-mode 1)

Turn on echo mode

Display unfinished commands in the echo area after the specified delay.

  (setq echo-keystrokes 0.10)

Disable completion buffer

Remove the completion buffer as soon as we get out of the minibuffer

  (add-hook 'minibuffer-exit-hook
            '(lambda ()
               (let ((buffer "*Completions*"))
                 (and (get-buffer buffer)
                      (kill-buffer buffer))) ))

Auto save on compile

  (setq compilation-ask-about-save nil)

Idle-kill

  (defun kill-buffers-on-idle ()
    "Kill buffers that have the appropriate property set."
    (save-excursion
      (save-window-excursion
        (dolist (b (buffer-list))
          (when (and (with-current-buffer b (boundp 'buffer-close-on-idle))
                     (with-current-buffer b buffer-close-on-idle))
            (with-current-buffer b (message "Killed %s" buffer-file-name))
            (pop-to-buffer-same-window b)
            (kill-buffer))))))
  (run-with-idle-timer 180 t 'kill-buffers-on-idle)

Calendar

       (add-hook 'calendar-load-hook
         (lambda ()
         (calendar-set-date-style 'european)))
       ;; first day of the week is monday instead of sunday:
       (setq calendar-week-start-day 1
             calendar-location-name "Toronto, ON Canada"
             calendar-latitude 43.7
             calendar-longitude -79.4
             calendar-today-marker "·")
  (add-hook 'today-visible-calendar-hook 'calendar-mark-today)

Use local proxy

I need this to route bibretrieve requests through my local proxy, that in turn routes requests to mathscinet through the University network

       ;; Use system proxy
      (setq url-proxy-services '(("http" . "127.0.0.1:8118")
                                 ("https" . "127.0.0.1:8118")))

Indicator

Change cursor color to reflect different layers on the keyboard This is the handler

  (defun xkbvleds-indicator-signal-handler (indicator on)
    (if on
        (cond ((string-equal indicator "Greek")
               (set-face-background 'cursor "#2aa198"))
              ((string-equal indicator "Math")
               (set-face-background 'cursor "#cb4b16")))
      (set-face-background 'cursor "#919191")))

Connect the signal from xkbvleds to the handler

  (require 'dbus)
  ;; Register for the signal indicatorChanged coming from our service.  It is
  ;; important that the =service= argument is =nil=, otherwise the registration
  ;; would stop once the process is respawned.
  (ignore-errors (dbus-register-signal
  :session nil "/org/xkbvleds" "org.xkbvleds" "indicatorChanged"
       'xkbvleds-indicator-signal-handler))

Tarmak-ready

Set up all possible combinations of modifiers

  (defun concat-recursive (b &optional a)
    (if b
        (append (concat-recursive (cdr b) (concat a (car b)))
                (concat-recursive (cdr b) a))
      (when a (list a))))

  (setq modifier-combo (concat-recursive '("C-" "M-" "s-" "H-")))

Then list the swapped keys

  (setq tarmak1-swaps '(("j" . "e")
                        ("e" . "k")
                        ("k" . "n")
                        ("n" . "j")))

Transmission

  (require 'transmission)
  (setq transmission-host "192.168.0.40")

Main major modes

mu4e

  (require 'smtpmail)
  (require 'mu4e)

  (global-set-key (kbd "C-c μ") 'mu4e)

  (setq mu4e-maildir "~/.mail"
        mu4e-attachment-dir "~/attachments"
        mu4e-html2text-command "w3m -dump -T text/html -cols 72 -o display_link_number=true -o auto_image=false -o display_image=false -o ignore_null_img_alt=true"
        mu4e-headers-show-threads nil
        mu4e-view-use-gnus t
        mm-text-html-renderer 'gnus-w3m)

  (setq mu4e-contexts
        `( ,(make-mu4e-context
             :name "Work"
             :enter-func (lambda () (mu4e-message "Switch to the Work context"))
             ;; no leave-func
             ;; we match based on the maildir of the message
             ;; this matches maildir /Arkham and its sub-directories
             :match-func (lambda (msg)
                           (when msg
                             (string-match-p "^/math" (mu4e-message-field
                                                       msg :maildir))))
             :vars '( ( user-mail-address	     . "jacopods@math.utoronto.ca" )
                      ( user-full-name	     . "Jacopo De Simoi" )
                      ( mu4e-sent-folder       . "/math/Sent")
                      ( mu4e-drafts-folder     . "/math/Drafts")
                      ( mu4e-trash-folder      . "/math/Trash")
                      ( mu4e-refile-folder     . "/math/Archive")
                      ( smtpmail-stream-type   . starttls )
                      ( smtpmail-smtp-service  . 9587 )
                      ( mu4e-compose-signature . (concat
                                                  "Jacopo De Simoi\n"
                                                  "Associate Professor — U Toronto\n"))))))

  ;; 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 is no context matches;
  ;; default is to ask
  (setq mu4e-compose-context-policy 'pick-first)

  (add-hook 'mu4e-headers-mode-hook
            #'(lambda () (setq-local show-trailing-whitespace nil)))
  (add-hook 'mu4e-view-mode-hook
            #'(lambda () (setq-local show-trailing-whitespace nil)))

  ;; Get mail
  (setq mu4e-get-mail-command "mbsync math-fast"
        mu4e-change-filenames-when-moving t   ; needed for mbsync
        mu4e-headers-include-related nil ;do not include threaded
                                          ;sent messages in inbox queries
        )

  (define-key mu4e-headers-mode-map (kbd "h") 'mu4e-headers-mark-for-refile)
  (define-key mu4e-headers-mode-map (kbd "h") 'mu4e-headers-mark-for-refile)

  (define-key mu4e-headers-mode-map (kbd "h") 'mu4e-headers-mark-for-refile)
  (define-key mu4e-view-mode-map (kbd "h") 'mu4e-view-mark-for-refile)

  (define-key mu4e-headers-mode-map (kbd "r") 'mu4e-compose-reply)
  (define-key mu4e-view-mode-map (kbd "r") 'mu4e-compose-reply)

  (define-key mu4e-headers-mode-map (kbd "f") 'mu4e-compose-forward)
  (define-key mu4e-headers-mode-map (kbd "C-k") 'mu4e-headers-mark-for-trash)


  ;; Send mail
  (setq message-send-mail-function 'smtpmail-send-it
        smtpmail-servers-requiring-authorization ".*"
        smtpmail-smtp-server "127.0.0.1")

  (require 'org-mu4e)
  ;;store link to message if in header view, not to header query
  (setq mu4e-org-link-query-in-headers-mode nil)

org-mode

Require

Require the org package; I also occasionally use org-pomodoro

  (with-eval-after-load "org"
    (define-key org-src-mode-map (kbd "C-c C-c") 'org-edit-src-exit)
    (define-key org-src-mode-map (kbd "C-c C-k") nil) ;this conflicts with my LaTeX bindings
    (define-key org-src-mode-map (kbd "C-c C-`") 'org-edit-src-abort))

  (require 'org)
  (require 'org-pomodoro)
  (require 'org-habit)

  (require 'helm-org)
  (add-to-list 'helm-completing-read-handlers-alist '(org-capture . helm-org-completing-read-tags))
  (add-to-list 'helm-completing-read-handlers-alist '(org-set-tags-command . helm-org-completing-read-tags))
  ;   (add-to-list 'helm-completing-read-handlers-alist '(org-set-tags
  ;   . helm-org-completing-read-tags))

Hooks

Enable auto-fill-mode (see [the manual]: honestly I do not see where I would not want to use this feature). Also, disable truncate-lines

  (add-hook 'org-mode-hook 'turn-on-auto-fill)
  (setq org-starting-truncated nil
        org-startup-folded t)

Cosmetics

Change the default ellipsis ... to the unicode ellipsis Does not work properly

;      (setq org-ellipsis "…")

Ligatures [not in working order]

These require a patched hackminus font. Too bad it does not work for some reason

  ;; (defun delayed-org-prettify ()
  ;;   (prettify-symbols-mode 0)
  ;;   (run-with-idle-timer 0 nil
  ;;                        (lambda ()
  ;;                          (prettify-symbols-mode 1)
  ;;                          (add-to-list 'prettify-symbols-alist '("**" . (? (Br . Bl) ?)))
  ;;                          (add-to-list 'prettify-symbols-alist '("***" . (? (Br . Bl) ? (Br . Bl) ?)))
  ;;                          (add-to-list 'prettify-symbols-alist '("****" . (? (Br . Bl) ? (Br . Bl) ? (Br . Bl) ?))))))
  ;;(add-hook 'org-mode-hook 'delayed-org-prettify)

Links

Open links with external stuff

  (setq org-file-apps
        '((auto-mode . emacs)
          ("\\.x?html?\\'" . "xdg-open %s")
          ("\\.pdf\\'" . "xdg-open \"%s\"")))

Agenda

Set the canonical binding for the agenda

 (global-set-key (kbd "C-c a") 'org-agenda)

Define agenda files: the main one is master.org, but then I have a bunch of them on orgzly

      (setq org-agenda-files
      '("~/org/master.org"
        "~/org/next.org"
        "~/org/orgzly/work.org"
        "~/org/orgzly/scheduled.org"
        "~/org/orgzly/hack.org"
        "~/org/orgzly/library.org"
        "~/org/orgzly/kaizen.org"
        "~/org/orgzly/refile.org"))

Default to daily agenda

  (setq org-agenda-span 1)

Prevent headlines to be marked as DONE if some sub-headings are still TODO.

  (setq org-enforce-todo-dependencies t)

Do not show scheduled or deadline'd stuff in the Global TODO list

  (setq org-agenda-todo-ignore-deadlines 'all
        org-agenda-todo-ignore-scheduled 'all)

Do not show stuff marked with DONE even if they have a deadline

  (setq org-agenda-skip-deadline-if-done t)

Custom separator

  (setq org-agenda-block-separator ?─)

Turn on speed keys

  (setq org-use-speed-commands t)

Customize the agenda interface a bit

  • Sleeker time-grid
  (setq org-agenda-time-grid '((daily today require-timed)
         (800 1000 1200 1400 1600 1800 2000)
         " ······ " "───────────────")
        org-agenda-current-time-string "····· now ·····")
  • Use figlet-type fonts to display the date
              (setq figlet
                    [["███" "██ " "███" "███" "█ █" "███" "███" "███" "███" "███"]
                     ["█ █" " █ " "  █" "  █" "█ █" "█  " "█  " "  █" "█ █" "█ █"]
                     ["█ █" " █ " "███" "███" "███" "███" "███" "  █" "███" "███"]
                     ["█ █" " █ " "█  " "  █" "  █" "  █" "█ █" "  █" "█ █" "  █"]
                     ["███" "███" "███" "███" "  █" "███" "███" "  █" "███" "███"]])

              (setq figlet-lean
                    [["┌──┐" "╶┐ " "╶──┐" "╶──┐" "╷  ╷" "┌──╴" "┌──╴" "╶──┐" "┌──┐" "┌──┐"]
                     ["│  │" " │ " "   │" "   │" "│  │" "│   " "│   " "   │" "│  │" "│  │"]
                     ["│  │" " │ " "┌──┘" "╶──┤" "└──┤" "└──┐" "├──┐" "   │" "├──┤" "└──┤"]
                     ["│  │" " │ " "│   " "   │" "   │" "   │" "│  │" "   │" "│  │" "   │"]
                     ["└──┘" "╶┴╴" "└──╴" "╶──┘" "   ╵" "╶──┘" "└──┘" "   ╵" "└──┘" "╶──┘"]])

              (defun figlet-digit (digit row)
                (aref (aref figlet-lean row) digit))

              (defun figlet-num (number row)
                (let ((n number)
                      (d (list)))
                  (while (> n 0)
                    (setq d (append (list (mod n 10)) d))
                    (setq n (/ n 10)))
                  (string-join (mapcar
                                (lambda (digit) (concat (figlet-digit digit row) " "))
                                d))))
              (defun org-agenda-format-date-figlet (date)
                "Format a DATE string for display in the daily/weekly agenda.
              This function makes sure that dates are aligned for easy reading."
                ;(require 'cal-iso)
                (let* ((dayname (calendar-day-name date))
                   (day (cadr date))
                   (day-of-week (calendar-day-of-week date))
                   (month (car date))
                   (monthname (calendar-month-name month))
                   (year (nth 2 date))nf
                   (iso-week (org-days-to-iso-week
                          (calendar-absolute-from-gregorian date)))
                   (weekyear (cond ((and (= month 1) (>= iso-week 52))
                            (1- year))
                           ((and (= month 12) (<= iso-week 1))
                            (1+ year))
                           (t year)))
                   (weekstring (if (= day-of-week 1)
                           (format " W%02d" iso-week)
                             "")))

                  (format (concat "\n"
                                  "%12s  %s %4d%s\n"
                                  "%12s \n"
                                  "%12s  %-10s\n"
                                  "%12s \n"
                                  "%12s  %s\n")
                          (figlet-num day 0) monthname year weekstring
                          (figlet-num day 1)
                          (figlet-num day 2) dayname
                          (figlet-num day 3)
                          (figlet-num day 4) (sunrise-sunset))))

  (setq org-agenda-format-date #'org-agenda-format-date-figlet)
  (setq org-agenda-prefix-format
        '((agenda . " %i %9c · %?-12t% s")
         (todo . " %i %9c · ")
         (tags . " %i %9c · ")
         (search . " %i %9c · ")))
  • Add a whiteline after the header Now, this is a horrible hack: the string that forms the header is obtained by constructing some pretty-text in a temporary buffer and then retrieving the string with #'buffer-string Hence we add (and remove) an advice to the function buffer-string that concat's a newline around each function that produces the headers
  (defun concat-newline (s)
  (concat s "\n"))

  (mapcar (lambda (fun)
            (advice-add fun :around
              (lambda (orig-fun &rest args)
                (advice-add #'buffer-string :filter-return #'concat-newline)
                (apply orig-fun args)
                (advice-remove #'buffer-string #'concat-newline))))
          '(org-tags-view org-todo-list))
(advice-add #'org-agenda--insert-overriding-header :filter-args
              (lambda (params)
                (list `(concat ,(car params) "\n"))))

Improve the org-habit graph thing

  (setq org-habit-regular-glyph ?□
        org-habit-today-glyph ?□
        org-habit-completed-glyph ?▣)

  (defun wilder/org-habit-build-graph (habit starting current ending)
    "Build a graph for the given HABIT, from STARTING to ENDING.
        CURRENT gives the current time between STARTING and ENDING, for
        the purpose of drawing the graph.  It need not be the actual
        current time."
    (let* ((all-done-dates (sort (org-habit-done-dates habit) #'<))
           (done-dates all-done-dates)
           (scheduled (org-habit-scheduled habit))
           (s-repeat (org-habit-scheduled-repeat habit))
           (start (time-to-days starting))
           (now (time-to-days current))
           (end (time-to-days ending))
           (graph (make-string (- end start) org-habit-regular-glyph))
           (index 0)
           last-done-date)
      (while (and done-dates (< (car done-dates) start))
        (setq last-done-date (car done-dates)
              done-dates (cdr done-dates)))
      (while (< start end)
        (let* ((in-the-past-p (< start now))
               (todayp (= start now))
               (donep (and done-dates (= start (car done-dates))))
               (faces
                (if (and in-the-past-p
                         (not last-done-date)
                         (not (< scheduled now)))
                    (if (and all-done-dates (= (car all-done-dates) start))
                        ;; This is the very first done of this habit.
                        '(org-habit-ready-face . org-habit-ready-future-face)
                      '(org-habit-clear-face . org-habit-clear-future-face))
                  (org-habit-get-faces
                   habit start
                   (and in-the-past-p
                        last-done-date
                        ;; Compute scheduled time for habit at the time
                        ;; START was current.
                        (let ((type (org-habit-repeat-type habit)))
                          (cond
                           ;; At the last done date, use current
                           ;; scheduling in all cases.
                           ((null done-dates) scheduled)
                           ((equal type ".+") (+ last-done-date s-repeat))
                           ((equal type "+")
                            ;; Since LAST-DONE-DATE, each done mark
                            ;; shifted scheduled date by S-REPEAT.
                            (- scheduled (* (length done-dates) s-repeat)))
                           (t
                            ;; Compute the scheduled time after the
                            ;; first repeat.  This is the closest time
                            ;; past FIRST-DONE which can reach SCHEDULED
                            ;; by a number of S-REPEAT hops.
                            ;;
                            ;; Then, play TODO state change history from
                            ;; the beginning in order to find current
                            ;; scheduled time.
                            (let* ((first-done (car all-done-dates))
                                   (s (let ((shift (mod (- scheduled first-done)
                                                        s-repeat)))
                                        (+ (if (= shift 0) s-repeat shift)
                                           first-done))))
                              (if (= first-done last-done-date) s
                                (catch :exit
                                  (dolist (done (cdr all-done-dates) s)
                                    ;; Each repeat shifts S by any
                                    ;; number of S-REPEAT hops it takes
                                    ;; to get past DONE, with a minimum
                                    ;; of one hop.
                                    (cl-incf s (* (1+ (/ (max (- done s) 0)
                                                         s-repeat))
                                                  s-repeat))
                                    (when (= done last-done-date)
                                      (throw :exit s))))))))))
                   donep)))
               markedp face)
          (cond
           (donep
            (aset graph index org-habit-completed-glyph)
            (setq markedp t)
            (while (and done-dates (= start (car done-dates)))
              (setq last-done-date (car done-dates))
              (setq done-dates (cdr done-dates))))
           (todayp
            (aset graph index org-habit-today-glyph)))
          (setq face (if (or in-the-past-p todayp)
                         (car faces)
                       (cdr faces)))
          (when (and in-the-past-p
                     (not (eq face 'org-habit-overdue-face))
                     (not markedp))
            (setq face (cdr faces)))
          (put-text-property index (1+ index) 'face face graph)
          (put-text-property index (1+ index)
                             'help-echo
                             (concat (format-time-string
                                      (org-time-stamp-format)
                                      (time-add starting (days-to-time (- start (time-to-days starting)))))
                                     (if donep " DONE" ""))
                             graph))
        (setq start (1+ start)
              index (1+ index)))
      graph))

  (advice-add 'org-habit-build-graph  :override #'wilder/org-habit-build-graph)

Ideally I should tag some tasks as “break” tasks, which are suitable to be taken care of during a pomodoro break. Such tasks should be marked with tags :5m: and :20m: according to the estimate on the time it would take to take care of them

  (setq org-agenda-custom-commands
  '(
  ("a" "Main agenda"
  ((agenda "")
  (todo "NEXT|ONGOING")
  (tags-todo "hack")
  (tags-todo "5m")
  (todo "TODO")))
  ("h" "Agenda and Android tasks"
  ((agenda "")
  (tags-todo "Android")))
  ("5" "Agenda and Break tasks"
  ((agenda "")
  (tags-todo "5m")
  (tags-todo "20m")))))

Custom agenda view

  • cleanup stuff (TODO, what is this doing, exactly? )
  (defun org-agenda-prepare (&optional name)
        (let ((filter-alist (if org-agenda-persistent-filter
                    (with-current-buffer
                        (get-buffer-create org-agenda-buffer-name)
                      (list `(tag . ,org-agenda-tag-filter)
                        `(re . ,org-agenda-regexp-filter)
                        `(effort . ,org-agenda-effort-filter)
                        `(cat . ,org-agenda-category-filter))))))
          (if (org-agenda-use-sticky-p)
          (progn
            (put 'org-agenda-tag-filter :preset-filter nil)
            (put 'org-agenda-category-filter :preset-filter nil)
            (put 'org-agenda-regexp-filter :preset-filter nil)
            ;; Popup existing buffer
            (org-agenda-prepare-window (get-buffer org-agenda-buffer-name)
                           filter-alist)
            (message "Sticky Agenda buffer, use `r' to refresh")
            (or org-agenda-multi (org-agenda-fit-window-to-buffer))
            (throw 'exit "Sticky Agenda buffer, use `r' to refresh"))
            (setq org-todo-keywords-for-agenda nil)
            (put 'org-agenda-tag-filter :preset-filter
             org-agenda-tag-filter-preset)
            (put 'org-agenda-category-filter :preset-filter
             org-agenda-category-filter-preset)
            (put 'org-agenda-regexp-filter :preset-filter
             org-agenda-regexp-filter-preset)
            (put 'org-agenda-effort-filter :preset-filter
             org-agenda-effort-filter-preset)
            (if org-agenda-multi
            (progn
              (setq buffer-read-only nil)
              (goto-char (point-max))
              (unless (or (bobp) org-agenda-compact-blocks
                  (not org-agenda-block-separator))
                (insert "\n"
                    (if (stringp org-agenda-block-separator)
                    org-agenda-block-separator
                  (make-string (window-width) org-agenda-block-separator))
                    "\n\n"))
              (narrow-to-region (point) (point-max)))
          (setq org-done-keywords-for-agenda nil)
          ;; Setting any org variables that are in org-agenda-local-vars
          ;; list need to be done after the prepare call
          (org-agenda-prepare-window
           (get-buffer-create org-agenda-buffer-name) filter-alist)
          (setq buffer-read-only nil)
          (org-agenda-reset-markers)
          (let ((inhibit-read-only t)) (erase-buffer))
          (org-agenda-mode)
          (setq org-refile-targets '((org-agenda-files :level . 1)))
          (setq org-refile-use-outline-path 'file)
          (setq org-agenda-buffer (current-buffer))
          (setq org-agenda-contributing-files nil)
          (setq org-agenda-columns-active nil)
          (org-agenda-prepare-buffers (org-agenda-files nil 'ifmode))
          (setq org-todo-keywords-for-agenda
                (org-uniquify org-todo-keywords-for-agenda))
          (setq org-done-keywords-for-agenda
                (org-uniquify org-done-keywords-for-agenda))
          (setq org-agenda-last-prefix-arg current-prefix-arg)
          (setq org-agenda-this-buffer-name org-agenda-buffer-name)
          (and name (not org-agenda-name)
               (setq-local org-agenda-name name)))
            (setq buffer-read-only nil))))

        (add-hook 'org-agenda-mode-hook
            (lambda () (setq truncate-lines t
                             show-trailing-whitespace nil)))

Automate saving

This will take care of most of the other stuff

(add-hook 'auto-save-hook 'org-save-all-org-buffers)

Reverting stuff from orgzly

  (defun org-revert-all-orgzly-buffers (&optional ALL)
    "Revert all Org buffers that are sitting in orgzly
  Prompt for confirmation when there are unsaved changes.  Be sure
  you know what you are doing before letting this function
  overwrite your changes."
    (interactive)
    (message "Reverting Orgzly buffers…")
    (save-excursion
      (save-window-excursion
        (dolist (b (buffer-list))
          (when (and (with-current-buffer b (derived-mode-p 'org-mode))
                     (with-current-buffer b buffer-file-name)
                     (with-current-buffer b (string-match-p "orgzly" default-directory)))
            (pop-to-buffer-same-window b)
            (revert-buffer t 'no-confirm)))))
            (org-agenda-redo-all))
  (define-key org-agenda-mode-map (kbd "Z") 'org-revert-all-orgzly-buffers)

Capture

Set default keybinding

  (global-set-key (kbd "C-c c") 'org-capture)

This is my capture template: it needs to be revised as I really do not use The Idea, journal and break entry

        (setq org-default-notes-file "~/org/master.org")
        (setq org-capture-templates
          '(("t" "TODO today" entry (file+headline "~/org/orgzly/scheduled.org" "Tasks")
             "* TODO %?\n  SCHEDULED: %t" :clock-in t :clock-resume t)
            ("n" "TODO next" entry (file+headline "~/org/orgzly/scheduled.org" "Tasks")
             "* NEXT %?\n  " :clock-in t :clock-resume t)
            ("T" "TODO" entry (file+headline "~/org/orgzly/scheduled.org" "Tasks")
             "* TODO %?\n  %a" :clock-in t :clock-resume t)
            ("i" "Idea" entry (file+headline "~/org/master.org" "Ideas")
             "* IDEA %?\n  %u" :clock-in t :clock-resume t	 )
             ("j" "Journal" entry (file+datetree "~/org/master.org")
               "* %?\n%U\n" :clock-in t :clock-resume t)
            ("b" "Break" entry (file+datetree "~/org/master.org")
               "* break %?\n" :clock-in t :clock-resume t)
            ("e" "Mail To" entry (file+headline "~/org/orgzly/scheduled.org" "E-mails")
             "* DONE mailto:%?")
            ("R" "Reply" entry (file+headline "~/org/orgzly/scheduled.org" "E-Mails")
            "* TODO Reply to %:from \nSCHEDULED: %(org-insert-time-stamp
  (org-read-date nil t \"+0d\"))\n%a\n%?\n")))

LaTeX export

;   (add-to-list 'org-latex-classes
;    '("amsart" "\\documentclass[11pt]{amsart}"
;     ("\\section{%s}" . "\\section*{%s}")
;     ("\\subsection{%s}" . "\\subsection*{%s}")
;     ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
;     ("\\paragraph{%s}" . "\\paragraph*{%s}")
;     ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

Source blocks

Add template for a source block in a few selected languages; for now I have

  • emacs-lisp
  • shell

. This is useful for writing the emacs init file in literate form, or dotfiles for other code. Since Org 9.2, the behavior that I grew accustomed to (e.g. <el TAB) )is implemented by org-tempo, so I need to require that as well.

  (mapcar (lambda (structure-template)
            (add-to-list 'org-structure-template-alist
                         structure-template))
          '(("el" . "src emacs-lisp")
            ("sh" . "src sh")))
  (require 'org-tempo)

Fontify src blocks

  (setq org-src-fontify-natively t)

Lowercase org blocks

There is a new trend to use lowercase in the org block definitions; this gist (taken from the Scripter blog) lowercases all instances in the current buffer

  (defun modi/lower-case-org-keywords ()
    "Lower case Org keywords and block identifiers.

  Example: \"#+TITLE\" -> \"#+title\"
           \"#+BEGIN_EXAMPLE\" -> \"#+begin_example\"

  Inspiration:
  https://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0."
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (let ((case-fold-search nil)
            (count 0))
        ;; Match examples: "#+foo bar", "#+foo:", "=#+foo=", "~#+foo~",
        ;;                 "‘#+foo’", "“#+foo”", ",#+foo bar",
        ;;                 "#+FOO_bar<eol>", "#+FOO<eol>".
        (while (re-search-forward "\\(?1:#\\+[A-Z_]+\\(?:_[[:alpha:]]+\\)*\\)\\(?:[ :=~’”]\\|$\\)" nil :noerror)
          (setq count (1+ count))
          (replace-match (downcase (match-string-no-properties 1)) :fixedcase nil nil 1))
        (message "Lower-cased %d matches" count))))

Clocking

 ;; Separate drawers for clocking and logs
 (setq org-drawers (quote ("PROPERTIES" "CLOCKBOOK")))
 ;; Save clock data and state changes and notes in the CLOCK drawer
 (setq org-clock-into-drawer "CLOCKBOOK")
 ;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
 (setq org-clock-out-remove-zero-time-clocks t)
 ;; Clock out when moving task to a done state
 (setq org-clock-out-when-done t)

 (setq org-clock-persist 'history)

 (setq org-duration-format 'h:mm)
 (setq org-clock-clocktable-default-properties '(:maxlevel 2 :scope subtree))
 (org-clock-persistence-insinuate)

COMMENT Tangle to different files

This has been broken by commit 3ebee033103ccd3c3e8c354bad01c15332b9d901 and a2cb9b853d30fc301f4553d1556dba4ee6bc1ead. Try some workarounds to pinpoint the issue:

  (setq org-babel-tangle-use-relative-file-links nil)

—-

This is some some super-clever stuff. See [https://emacs.stackexchange.com/questions/39032/tangle-the-same-src-block-to-different-files]

  (defun org-babel-tangle-collect-blocks-handle-tangle-list (&optional language tangle-file)
    "Can be used as :override advice for `org-babel-tangle-collect-blocks'.
  Handles lists of :tangle files."
    (let ((counter 0) last-heading-pos blocks)
  (org-babel-map-src-blocks (buffer-file-name)
    (let ((current-heading-pos
       (org-with-wide-buffer
        (org-with-limited-levels (outline-previous-heading)))))
  (if (eq last-heading-pos current-heading-pos) (cl-incf counter)
    (setq counter 1)
    (setq last-heading-pos current-heading-pos)))
    (unless (org-in-commented-heading-p)
  (let* ((info (org-babel-get-src-block-info))
     (src-lang (nth 0 info))
     (src-tfiles (cdr (assq :tangle (nth 2 info))))) ; Tobias: accept list for :tangle
    (unless (consp src-tfiles) ; Tobias: unify handling of strings and lists for :tangle
      (setq src-tfiles (list src-tfiles))) ; Tobias: unify handling
    (dolist (src-tfile src-tfiles) ; Tobias: iterate over list
      (unless (or (string= src-tfile "no")
      (and tangle-file (not (equal tangle-file src-tfile)))
      (and language (not (string= language src-lang))))
        ;; Add the spec for this block to blocks under its
        ;; language.
        (let ((by-lang (assoc src-lang blocks))
      (block (org-babel-tangle-single-block counter)))
      (setcdr (assoc :tangle (nth 4 block)) src-tfile) ; Tobias:
      (if by-lang (setcdr by-lang (cons block (cdr by-lang)))
        (push (cons src-lang (list block)) blocks)))))))) ; Tobias: just ()
  ;; Ensure blocks are in the correct order.
  (mapcar (lambda (b) (cons (car b) (nreverse (cdr b)))) blocks)))

  (defun org-babel-tangle-single-block-handle-tangle-list (oldfun block-counter &optional only-this-block)
    "Can be used as :around advice for `org-babel-tangle-single-block'.
  If the :tangle header arg is a list of files. Handle all files"
    (let* ((info (org-babel-get-src-block-info))
           (params (nth 2 info))
           (tfiles (cdr (assoc :tangle params))))
      (message nil)
      (if (null (and only-this-block (consp tfiles)))
          (funcall oldfun block-counter only-this-block)
        (cl-assert (listp tfiles) nil
                   ":tangle only allows a tangle file name or a list of tangle file names")
        (let ((ret (mapcar
                    (lambda (tfile)
                      (message tfile)
                      (sleep-for 1)
                      (let (old-get-info)
                        (cl-letf* (((symbol-function 'old-get-info) (symbol-function 'org-babel-get-src-block-info))
                                   ((symbol-function 'org-babel-get-src-block-info)
                                    `(lambda (&rest get-info-args)
                                       (let* ((info (apply 'old-get-info get-info-args))
                                              (params (nth 2 info))
                                              (tfile-cons (assoc :tangle params)))
                                         (setcdr tfile-cons ,tfile)
                                         info))))
                          (funcall oldfun block-counter only-this-block))))
                    tfiles)))
          (if only-this-block
              (list (cons (cl-caaar ret) (mapcar #'cadar ret)))
            ret)))))


  (advice-add 'org-babel-tangle-collect-blocks :override
              #'org-babel-tangle-collect-blocks-handle-tangle-list)
  (advice-add 'org-babel-tangle-single-block :around
              #'org-babel-tangle-single-block-handle-tangle-list)

Append tangle

  (defun org-babel-tangle-append (filename)
    "Append source code block at point to its tangle file.
  The command works like `org-babel-tangle' with prefix arg
  but `delete-file' is ignored."
    (interactive)
    (cl-letf (((symbol-function 'delete-file) #'ignore))
      (org-babel-tangle '(4) filename)))

Tangle file

This can be used to tangle one or more files to their output files Source on gitlab

  (defun tangle-file(&rest files nokill)
  "Tangle FILES or all files in the project."
  (when (null files)
    (setq files command-line-args-left))
  (dolist (file files)
    (with-current-buffer (find-file-noselect file)
      (org-babel-tangle)
;          (unless nokill (kill-buffer))
  )))

Export file

This can be used to tangle one or more files to their output files Source on gitlab

  (defun export-org-file-pdf(&rest files nokill)
  "Export FILES or all files in the project."
  (when (null files)
    (setq files command-line-args-left))
  (dolist (file files)
    (with-current-buffer (find-file-noselect file)
      (org-latex-export-to-pdf)
      (kill-buffer))))

Crypto stuff

  (require 'org-crypt)
  (org-crypt-use-before-save-magic)
  (setq org-tags-exclude-from-inheritance (quote ("crypt")))

  (setq org-crypt-key "C86A9E7675295C62")

ox-export

Load ox-hugo

(with-eval-after-load 'ox
  (require 'ox-hugo))

elisp

Paredit

  (autoload 'enable-paredit-mode "paredit" "Turn on
        pseudo-structural editing of Lisp code." t)
  (add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
  (require 'hydra)
  (require 'highlight-parentheses)

  (defun hydra-paren/hl-paren-force-fix ()
  ;;; This is needed b/c hl-parent caches the point position and
  ;;; refuses to update if the point did not move
    (let ((hl-paren-last-point -1))
      (hl-paren-highlight)))
  (defun hydra-paren/pre ()
    (unless (boundp 'hydra-paren/hpm)
      (highlight-parentheses-mode 1))
    (setq hydra-paren/hpm t))
  (defun hydra-paren/post ()
    (highlight-parentheses-mode -1)
    (makunbound 'hydra-paren/hpm))
  (global-set-key
   (kbd "C-SPC")
   (defhydra hydra-paren
     (:pre hydra-paren/pre :post hydra-paren/post)
     "paren slurp and barf"
     ("l" (progn
            (paredit-forward-slurp-sexp)
            (hydra-paren/hl-paren-force-fix)) "slurp forward")
     ("j" (progn
            (paredit-forward-barf-sexp)
            (hydra-paren/hl-paren-force-fix)) "barf forward")
     ("s" (progn
            (paredit-backward-slurp-sexp)
            (hydra-paren/hl-paren-force-fix)) "slurp backward")
     ("f" (progn
            (paredit-backward-barf-sexp)
            (hydra-paren/hl-paren-force-fix)) "barf backward")))

Replace last sexp

I use this a lot to evaluate (e.g.) quick computations in files

  (defun replace-last-sexp ()
    (interactive)
    (let ((value (eval (preceding-sexp))))
      (kill-sexp -1)
      (insert (format "%S" value))))

  (global-set-key (kbd "C-c C-x C-e") #'replace-last-sexp)

qml

Load qml-mode

  (autoload 'qml-mode "qml-mode.el" t)
  (add-to-list 'auto-mode-alist '("\\.qml\\'" . qml-mode))

C and C++

Hooks

;;      (require 'doxymacs)

  (add-hook 'c-mode-hook
            (lambda ()
              (subword-mode)
              (doxymacs-mode)
              (define-key c-mode-map (kbd "C-c C-c") 'make)))
  (add-hook 'c++-mode-hook
            (lambda ()
              (subword-mode)
              (doxymacs-mode)
              (define-key c++-mode-map (kbd "C-c C-c") 'make)))

TODO split — LaTeX

TODO Setup reftex

  (with-eval-after-load "reftex"
    (setq reftex-cite-format "~\\cite{%l}"
          reftex-plug-into-AUCTeX '(t t nil t t)
          reftex-insert-label-flags '(t  t)
          reftex-label-alist
          '(("thm" ?t "thm:" "~\\ref{%s}" thm (regexp "theorems?"))
            ("lem" ?l "lem:" "~\\ref{%s}" lem (regexp "lemma{ta}?"))
            ("prop" ?p "prp:" "~\\ref{%s}" prp (regexp "propositions?"))
            ("cor" ?c "cor:" "~\\ref{%s}" cor (regexp "corollary"))
            ("def" ?d "def:" "~\\ref{%s}" cor (regexp "defintions?")))))
  ;;; advice the auctex function to replace the
  ;;; lighter with somthing softer
  (with-eval-after-load "auctex"
    (defun cleanup-TeX-mode (&optional mode)
      "Advice for the base auctex MODE naming"
      (setq mode-name (replace-regexp-in-string "LaTeX" "χ" mode-name t))
      (setq mode-name (replace-regexp-in-string "/" "·" mode-name)))
    (advice-add 'TeX-set-mode-name :after 'cleanup-TeX-mode))

Setup latex-mode

  (eval-after-load 'latex
    '(progn
       (font-lock-add-keywords 'latex-mode
                               `((,(rx "$") 0 'font-latex-sedate-face t)) t)
       (defface font-latex-special-comment-face '((t (:foreground "#2aa198"))) "Cyan")


       (font-lock-add-keywords 'latex-mode '(("^% \\([^*].*\\)" 1 'font-latex-special-comment-face t)))

       (define-key-alist LaTeX-mode-map
         '(("M-S-SPC"      . TeX-insert-braces)
           ("C-c C-v"      . wilder/TeX-insert-reference)
           ("C-M-<return>" . wilder/TeX-insert-align-dwim)
           ;; unbind return - NOTE it is important to unbind
           ;; <return> and not RET. If we unbind RET then C-m won't work
           ;; either.
           ("<return>"   . (lambda() (interactive) (insert "\\")))
           ("S-<return>" . (lambda() (interactive) (insert "|")))
           ("C-c C-."    . LaTeX-mark-environment)
           ("C-c C-k"     . (lambda (r-begin r-end)
                              (interactive "r")
                              (add-delimiter "_{" "}" r-begin r-end)))
           ("C-c C-i"     . (lambda (r-begin r-end)
                              (interactive "r")
                              (add-delimiter "^{" "}" r-begin r-end)))
           ("M-|"         . (lambda (r-begin r-end)
                              (interactive "r")
                              (add-delimiter "|" "|" r-begin r-end)))
           ("M-,"         . (lambda (r-begin r-end)
                              (interactive "r")
                              (add-delimiter ", " ", " r-begin r-end)))
           ("M-\""        . (lambda (r-begin r-end)
                              (interactive "r")
                              (add-delimiter "“" "”" r-begin r-end)))

           ;; This is the rationale: C-M-SPC starts inline math C-M-RET starts display math

           ("C-M-SPC" . (lambda (r-begin r-end) (interactive "r") (add-delimiter "$" "$" r-begin r-end)))
           ("C-c C-d" . wilder/TeX-insert-todonote)
           ("C-M-d"   . kill-sexp)
           ("C-M-i"   . down-list) ;; -i stands for /in/
           ("C-M-o"   . up-list)   ;; -o stands for /out/
           ("<f4>"    . ( lambda() (interactive) (message "Use C-c C-c")))
           ("C-c C-c" . ( lambda() (interactive) (compile "/home/jacopods/scripts/latex-mk")) )
           ("~"       . wilder/TeX-replace-tilde)
           ("C-o"     . wilder/open-line-and-indent)
           ;; Force moves around to be more “semantic”
           ("C-v"     . goto-next-comment-line)
           ("M-v"     . goto-previous-comment-line)
           ("C-x n c" . narrow-between-comments)
           ("C-S-v"   . backward-paragraph)))

       (mapcar (lambda (ch)
                 (define-key LaTeX-mode-map (kbd ch) 'insert-char-with-padding))
               '("=" "≠" ">" "<" "≥" "≤" "⇒" "∩" "∪" "∨" "∧" "×" "⊂" "⊃"))

       ;; Move around commands in the Right Way™
       (modify-syntax-entry ?\\ "w" LaTeX-mode-syntax-table)

       ;; add fancy quotes to the syntax table
       (modify-syntax-entry ?“ "(”" LaTeX-mode-syntax-table)
       (modify-syntax-entry ?” ")“" LaTeX-mode-syntax-table)

       (setq subword-forward-regexp "\\W*\\(\\([\\\\[:upper:]]*\\W?\\)[[:lower:][:digit:]]*\\)")
       (setq subword-backward-regexp "\\(\\(\\W\\|[[:lower:][:digit:]]\\)\\([\\\\[:upper:]]+\\W*\\)\\|\\W\\w+\\)")))

Require

Load auctex, reftex and set up related hooks

 (require 'tex-site)
 (require 'reftex)

Set default TeX options

  (setq-default TeX-master nil)
  (setq TeX-auto-save t
        TeX-parse-self t
        TeX-insert-braces nil)

Appearance

No fontification for sub and superscripts

  (setq font-latex-fontify-script nil)

Add unicode quotes to the quote-list

;      (defvar font-latex-quote-list '(("``" "''") ("“" "”") ("<<" ">>" french) ("«" "»" french)) ;

Redefine fold ellipsis

   (setq TeX-fold-ellipsis " …")

Default labels

 (setq LaTeX-equation-label "e_"
       LaTeX-section-label "s_"
       LaTeX-figure-label "f_")

Spell checking help

Do not spell-check inside the following commands. See [https://tex.stackexchange.com/questions/117204/skip-spelling-in-emacs-for-the-content-of-a-user-macro]

  (setq ispell-tex-skip-alists
        (list
         (append
          (car ispell-tex-skip-alists) ;tell ispell to ignore content of this:
          '(("\\\\eqref"       ispell-tex-arg-end)
            ("\\\\cite"       ispell-tex-arg-end)
            ("\\\\author"       ispell-tex-arg-end)
            ("\\\\address"       ispell-tex-arg-end)
            ("\\\\include"       ispell-tex-arg-end)
            ))
         (cadr ispell-tex-skip-alists)))

Specialty functions

This function adds a pair of delimiters or surrounds the active region with the given delimiters. TODO it breaks when there is no mark

  (defun add-delimiter (delim-begin delim-end r-begin r-end)
    "Add the pair of delimiters given in delim at the ends of the
    region if it is activated"
    (interactive "cBegin delimiter: \ncEnd delimiter: \nr")
    (if (region-active-p)
        (progn
          (save-excursion
            (goto-char r-end)
            (insert delim-end)
            (goto-char r-begin)
            (insert delim-begin)))
      (progn
        (save-excursion
          (insert delim-end))
        (insert delim-begin))))

The following re-implements TeX-insert-braces to work with negative argument

  (defun TeX-insert-braces (arg)
     "Make a pair of braces around next ARG sexps and leave point inside.
   No argument is equivalent to zero: just insert braces and leave point
   between.

   If there is an active region, ARG will be ignored, braces will be
   inserted around the region, and point will be left after the
   closing brace."
     (interactive "P")
     (if (TeX-active-mark)
     (progn
       (if (< (point) (mark))
       (exchange-point-and-mark))
       (insert TeX-grcl)
       (save-excursion
         (goto-char (mark))
         (insert TeX-grop)))
   (if (and arg (< arg 0))
       (progn
         (save-excursion
       (backward-sexp (prefix-numeric-value (- 0 arg)))
       (insert TeX-grop))
         (insert TeX-grcl))
     (insert TeX-grop)
     (save-excursion
     (if arg (forward-sexp (prefix-numeric-value arg)))
     (insert TeX-grcl)))))

   (defun TeX-back-insert-braces (arg)
     (interactive "P")
     (if arg (TeX-insert-braces (- 0 arg))
   (insert TeX-grcl)))

This is a helper for Dynamic abbrev expansion

  (defun dabbrev-expand-helper ()
    (interactive)
     (call-interactively 'dabbrev-expand))

This inserts a char adding some whitespace padding whenever necessary

  (defun insert-char-with-padding (arg)
    (interactive "*P")
    (unless (string-match (string (preceding-char)) " \&")
      (insert " "))
    (self-insert-command (prefix-numeric-value arg))
    (unless (char-equal (following-char) ?\s)
      (insert " "))) ;; decide what to do with the point

This function opens a line and indents it

  (defun wilder/open-line-and-indent (arg)
    "This function opens a line using (open-line) and indents it"
    (interactive "p")
    (open-line arg)
    (save-excursion (forward-char arg) (unless (eolp) (indent-according-to-mode))))

This inserts a plain reference (or a reference to an equation with prefix arg)

(defun wilder/TeX-insert-reference (arg)
          (interactive "P")
          (insert "~")
          (if arg (TeX-insert-macro "eqref")
            (TeX-insert-macro "ref")))

This inserts a citation

(defun wilder/TeX-insert-cite (arg)
          (interactive "P")
          (insert "~")
          (TeX-insert-macro "cite"))

This inserts an align environment (or an align* with prefix arg)

  (defun wilder/TeX-insert-align (arg)
    (interactive "P")
    (if arg
        (LaTeX-insert-environment "align")
      (LaTeX-insert-environment "align*"))
    (indent-according-to-mode))

  (defun wilder/TeX-insert-align-dwim (arg)
    (interactive "P")
    (if (texmathp)
        (let ((why (car texmathp-why)))
          (cond ((string-prefix-p "$" why) (wilder/TeX-promote-inline-math arg))
                ((string-equal "equation*" why) (LaTeX-modify-environment "align*"))
                ((string-equal "equation" why) (LaTeX-modify-environment "align"))
                ((string-equal "align*" why) (when arg (LaTeX-modify-environment "align")))))
      (wilder/TeX-insert-align arg)))

This replaces horizontal space with a tilde

  (defun wilder/TeX-replace-tilde (arg)
  (interactive "P")
  (delete-horizontal-space)
  (insert "~"))

Insert a todonote at point or wrap the region in a todonote.

  (defun wilder/TeX-insert-todonote (arg r-begin r-end)
    (interactive "P\nr")
    (if arg
        (add-delimiter "{\\todo[inline]{" "}}" r-begin r-end)
        (add-delimiter "{\\todo{" "}}" r-begin r-end)))

Promote inline math to an align

  (defun wilder/char-punctuation-p (ch)
    "returns t if the char is a punctuation"
    (interactive)
    (string-match (string ch) ".,:;"))
  (defun wilder/TeX-promote-inline-math (arg)
    (interactive "P")
    (when (and (texmathp) (string-prefix-p "$" (car texmathp-why)))
      (let* ((delim (car texmathp-why))
             (pos (cdr texmathp-why))
             (n (length delim)))
        (goto-char pos)
        (push-mark)
        (delete-char n)
        (search-forward delim)
        (delete-backward-char n)
        ;; include punctuations in the align
        (when (wilder/char-punctuation-p (char-after)) (forward-char))
        (activate-mark)
        (wilder/TeX-insert-align arg)
        (pop-mark)
        (pop-mark))))

Shadow the AucTeX version of this function

  (defun LaTeX-insert-environment (environment &optional extra)
    "Insert LaTeX ENVIRONMENT with optional argument EXTRA."
    (let ((active-mark (and (TeX-active-mark) (not (eq (mark) (point)))))
          prefix content-start env-start env-end)
      (when (and active-mark (< (mark) (point))) (exchange-point-and-mark))
      ;; Compute the prefix.
      (when (and LaTeX-insert-into-comments (TeX-in-commented-line))
        (save-excursion
          (beginning-of-line)
          (looking-at
           (concat "^\\([ \t]*" TeX-comment-start-regexp "+\\)+[ \t]*"))
          (setq prefix (match-string 0))))
      ;; What to do with the line containing point.
      (cond (;; if the line contains only whitespace, delete them
             (save-excursion (beginning-of-line)
                             (looking-at (concat prefix "[ \t]*$")))
             (delete-region (match-beginning 0) (match-end 0)))
            ;; otherwise, something is written on the line.  We can be
            ;; at the beginning of the text
            ((TeX-looking-at-backward (concat "^" prefix "[ \t]*")
                                      (line-beginning-position))
             ;;this morally opens a new line
             (beginning-of-line)
             (newline)
             (beginning-of-line 0))
            ((bolp)
             (delete-horizontal-space)
             (newline)
             (beginning-of-line 0))
            ((looking-at "[ \t]*$")
             (delete-horizontal-space)
             (newline)
             (when prefix (insert prefix))
             (beginning-of-line))
            (t
             (delete-horizontal-space)
             (newline 2)
             (when prefix (insert prefix))
             (beginning-of-line 0)))
      ;; What to do with the line containing mark.
      (when active-mark
        (save-excursion
          (goto-char (mark))
          (cond ((save-excursion (beginning-of-line)
                                 (or (looking-at (concat prefix "[ \t]*$"))
                                     (looking-at "[ \t]*$")))
                 (delete-region (match-beginning 0) (match-end 0)))
                ((TeX-looking-at-backward (concat "^" prefix "[ \t]*")
                                          (line-beginning-position))
                 (beginning-of-line)
                 (newline)
                 (beginning-of-line 0))
                ((looking-at "[ \t]*$")
                 (delete-horizontal-space)
                 (insert-before-markers "\n")
                 ;(newline)
                 (when prefix (insert prefix)))
                (t
                 (delete-horizontal-space)
                 (insert-before-markers "\n")
                 (newline)
                 (when prefix (insert prefix))))))
      ;; Now insert the environment.
      (when prefix (insert prefix))
      (setq env-start (point))
      (insert TeX-esc "begin" TeX-grop environment TeX-grcl)
      (indent-according-to-mode)
      (when extra (insert extra))
      (setq content-start (line-beginning-position 2))
      (unless active-mark
        (newline)
        (when prefix (insert prefix))
        (newline))
      (when active-mark (goto-char (mark)))
      (when prefix (insert prefix))
      (insert TeX-esc "end" TeX-grop environment TeX-grcl)
      (end-of-line 0)
      (if active-mark
          (progn
            (or (assoc environment LaTeX-indent-environment-list)
                (if auto-fill-function
                    ;; Fill the region only when `auto-fill-mode' is active.
                    (LaTeX-fill-region content-start (line-beginning-position 2))))
            (set-mark content-start))
        (indent-according-to-mode))
      (save-excursion (beginning-of-line 2) (indent-according-to-mode))
      (TeX-math-input-method-off)
      (setq env-end (save-excursion
                      (search-forward
                       (concat TeX-esc "end" TeX-grop
                               environment TeX-grcl))
                      (match-beginning 0)))
      (run-hook-with-args 'LaTeX-after-insert-env-hooks
                          environment env-start env-end)))

Patch auctex

I don't particularly like the way that the prefix arguments works with font selection. The function below patches the annoying behavior, by defaulting to the default behavior if the prefix argument is 0

  (defun wilder/TeX-font (replace what)
    "Insert template for font change command.
  If REPLACE is not nil, replace current font.  WHAT determines the font
  to use, as specified by `TeX-font-list'."
    (interactive "*P\nc")
    (TeX-update-style)
    (let* ((entry (assoc what TeX-font-list))
       (in-math (texmathp))
       (before (nth 1 entry))
       (after (nth 2 entry)))
      (setq replace (or replace (eq t (nth 3 entry)) (eq t (nth 5 entry))))
      (if (and in-math (stringp (nth 3 entry)))
      (setq before (nth 3 entry)
            after (nth 4 entry)))
      (setq arg (prefix-numeric-value replace))
      (cond
       ((null entry)
         (let ((help (concat
              "Font list:   "
              "KEY        TEXTFONT           MATHFONT\n\n"
              (mapconcat 'TeX-describe-font-entry
                     TeX-font-list "\n"))))
           (with-output-to-temp-buffer "*Help*"
             (set-buffer "*Help*")
             (insert help))))
       ((and replace  (eq 0 arg))
         (funcall TeX-font-replace-function before after))
       ((and replace (< arg 0) )
        (progn
          (save-excursion
            (backward-sexp (- 0 arg))
            (insert before))
          (insert after)))
       ((and replace (> arg 0))
        (insert before)
        (save-excursion
          (forward-sexp arg)
          (insert after)))
        ((TeX-active-mark)
         (save-excursion
           (cond ((> (mark) (point))
              (insert before)
              (goto-char (mark))
              (insert after))
             (t
              (insert after)
              (goto-char (mark))
              (insert before)))))
        (t
         (insert before)
         (save-excursion
           (insert after))))))
  (advice-add 'TeX-font :override #'wilder/TeX-font)

The hook

  (add-hook 'LaTeX-mode-hook
        (lambda ()
          (turn-on-reftex)

          (setq comment-column 0)
          (setq prettify-symbols-alist nil)
          (add-to-list 'prettify-symbols-alist '(" ⊂ " . (? (Br . Bl) ? (Br . Bl) ?)))

          (turn-on-auto-fill)
          (subword-mode)
          (TeX-fold-mode 1)
          (outshine-mode)))

Compilation fixes

Load appropriate compliation filters for warnings

  (load "latex-compile-filters.el")

Fix erroneous parsing of the LuaLaTeχ output "avail lists" as an error (works on ≥ emacs-27.1)

(add-to-list 'compilation-transform-file-match-alist '("   avail lists" nil))

Load bibretrieve

  (byte-recompile-directory "~/.emacs.d/bibretrieve" 0)
  (load "bibretrieve")
  (setq bibretrieve-backends '(("msn" . 10)))
  (require 'biblio)

TODO KDE integration

TODO cleanup and split

These functions connects to dbus to find out the current activity id and name

  (defun kde-current-activity ()
"Returns the current KDE activity"
(substring (shell-command-to-string "qdbus org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.CurrentActivity") 0 -1)
  )
  (defun kde-current-activity-name ()
"Returns the name of the current KDE activity"
(substring (shell-command-to-string (concat "qdbus org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.ActivityName " (kde-current-activity))) 0 -1))
  (defun X-window-id-belongs-to-activity (window-id activity)
(= (shell-command (concat "xprop -id " window-id " | grep  _KDE_NET_WM_ACTIVITIES | grep " activity ">/dev/null")) 0)
  )

  (defun select-frame-on-activity (activity)
(setq framelist (frame-list))
(setq done nil)
(while (and framelist (not done))
(setq cur (car framelist))
(setq cur-id (cdr (assq 'window-id (frame-parameters cur))))
(if cur-id (if (X-window-id-belongs-to-activity cur-id activity) (progn;
  (setq done 't) (select-frame cur)) ))
(setq framelist (cdr framelist)))
done
  )

  (defun select-X-frame ()
(setq framelist (frame-list))
(setq done nil)
(while (and framelist (not done))
(setq cur (car framelist))
(setq cur-id (cdr (assq 'window-id (frame-parameters cur))))
(if cur-id (progn;
 (setq done 't) (raise-frame cur)))
(setq framelist (cdr framelist)))
done
  )

This function is used to raise the frame associated to the current activity

TODO These entries should be added to the subtree once it is split

  (defun select-frame-on-current-activity ()
  (select-frame-on-activity (kde-current-activity)))

I prefer to keep one server for each KDE activity, so set the server name to be the name of the current activity

;      (setq server-name (kde-current-activity-name))

Journal

Setup org-journal

   (require 'org-journal)
   (setq org-journal-dir "~/org/journal"
         org-journal-file-type 'yearly
         org-journal-file-format "%Y"
         org-journal-encrypt-journal t)

Specialties

beacon

beacon is a package that helps finding the point when switching buffers. I like the idea but the aesthetics is a bit baroque. I should do the same with flash-hline

flash-hline

This function is defined to help in training with new keybindings. It acts as a visual bell which flashes the current line. It is (arbitrarily) bound to F15 which is supposed to be triggered by some “illegal” key hit

  (defun flash-hline ()
    "Flash the current line to emph some mistake"
    (interactive)
    (let ((fg (face-foreground 'default))
          (bg (face-background 'hl-line)))
      (set-face-background 'hl-line fg)
      (run-with-timer
       0.1 nil (lambda ()
                 (set-face-background 'hl-line "#303030") ))))

  (global-set-key (kbd "<f15>") 'flash-hline)

unfill-paragraph

This is authored by 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)))

kill-word

dwim manage space after kill-word. This has been morally pasted from this reddit post. The original version does not allow for double spaces after a period.

  (defun modi/just-one-space-post-kill-word (&rest _)
    "Function to manage white space after `kill-word' operations.

  1. If point is at the beginning of the line after possibly some white space,
     remove that white space and re-indent that line.
  2. If there is space before or after the point, ensure that there is only
     one white space around the point.
  3. Otherwise, do nothing.

  During the whole operation do not change the point position with respect to the
  surrounding white space.

  abc|   def  ghi <-- point on the left of white space after 'abc'
  abc| ghi        <-- point still before white space after calling this function
  abc   |def  ghi <-- point on the right of white space before 'def'
  abc |ghi        <-- point still after white space after calling this function."
    (save-excursion ; maintain the initial position of the pt with respect to space
      (cond ((looking-back "^ *") ; remove extra space at beginning of line
             (just-one-space 0)
             (indent-according-to-mode))
            ((looking-back "\\.  *")
             (just-one-space 2))
            ((or (looking-at   " ")
                 (looking-back " "))    ; adjust space only if it exists
             (just-one-space 1))
            (t ; do nothing otherwise, includes case where the point is at EOL
             ))))
  ;; Delete extra horizontal white space after `kill-word' and `backward-kill-word'
  (advice-add 'kill-word :after #'modi/just-one-space-post-kill-word)

word-count

Add word count in modeline; useful to prepare those pesky grant applications

  (require 'word-count)

gist

Use gist.el

   (require 'gist)

Main packages

Magit

  (require 'magit)
  (global-set-key (kbd "C-x C-g") 'magit-status)
  (magit-add-section-hook 'magit-status-sections-hook
                        #'magit-insert-modules-overview
                        #'magit-insert-unpushed-to-pushremote
                        :append)
  (magit-add-section-hook 'magit-status-sections-hook
                        #'magit-insert-untracked-files
                        #'magit-insert-modules-overview
                        :append)

magit-todos

  (require 'magit-todos)

smart-tab

This package is a gem: it allows to make tab work dwim

  (require 'smart-tab)
  (global-smart-tab-mode 1)

Outshine

  (defvar outline-minor-mode-prefix "\M-#")
  (setq outshine-use-speed-commands t)
  (with-eval-after-load 'outshine
    (define-key outshine-mode-map (kbd "C-M-i") nil))
  (add-hook 'sh-mode-hook 'outshine-mode)
  (require 'outshine)
  (require 'outorg)

Cook up some extra narrowing function

  (defun goto-next-comment-line ()
    (interactive)
    (re-search-forward "^\\S<" nil 1)
    (re-search-forward "^\\s<" nil 1)
    (beginning-of-line)
  )

  (defun goto-previous-comment-line ()
    (interactive)
    (re-search-backward "^\\s<" nil 1 )
    (re-search-backward "^\\S<" nil 1 )
    (beginning-of-line)
    (unless (bobp) (next-line))
  )

  (defun narrow-between-comments ()
    (interactive)
    (save-excursion
      (next-line)
      (goto-previous-comment-line)
      (setq beginning (point)))
    (save-excursion
      (goto-next-comment-line)
      (unless (bobp) (previous-line) (end-of-line))
      (setq ending (point)))
    (narrow-to-region beginning ending))

helm

  (require 'helm-config)
  (helm-mode 1)

  (defun fix-helm-margins ()
    (setq helm-left-margin-width left-margin-width))

  (global-set-key-alist
   '(("M-x"     . helm-M-x)
     ("C-x C-f" . helm-find-files)
     ("C-x b"   . helm-mini)
     ("C-x C-b" . helm-mini)
     ("M-y"     . helm-show-kill-ring)))
  (define-key helm-map (kbd "C-h") nil)
  (define-key helm-find-files-map (kbd "C-h") nil)
  (define-key helm-find-files-map (kbd "C-<backspace>") nil)
  (define-key helm-read-file-map (kbd "C-<backspace>") nil)

  (helm-define-key-with-subkeys helm-find-files-map (kbd "DEL") ?\d 'helm-ff-delete-char-backward
                                '(([C-c DEL] . helm-ff-run-toggle-auto-update))
                                nil 'helm-ff-delete-char-backward--exit-fn)
  (add-hook 'helm-after-initialize-hook 'fix-helm-margins)

multiple-cursors

  (require 'multiple-cursors)
  (define-key mc/keymap (kbd "<return>") nil)
  (global-set-key-alist
   '(("C->"       . mc/mark-next-like-this)
     ("C-<"       . mc/mark-previous-like-this)
     ("C-c C-<"   . mc/mark-all-like-this)
     ("C-c C-#"   . mc/insert-numbers)
     ("C-c C-\\"  . mc/mark-all-dwim)
     ("C-c <f13>" . mc/mark-pop)
     ("C-c <f14>" . mc/mark-pop)))

avy and avy-zap

These packages allow fast navigation and zapping

  (require 'avy-zap)
  (avy-setup-default)
  (global-set-key-alist
   '(("C-c C-j" . avy-resume)
     ("M-z"     . avy-zap-up-to-char-dwim)
     ("M-Z"     . avy-zap-to-char-dwim)
     ("C-c SPC" . avy-goto-word-or-subword-1)
     ("M-s"     . avy-goto-word-or-subword-1)
     ("M-g M-g" . avy-goto-line)
     ("M-g g"   . avy-goto-line)))
  (require 'ace-window)
  (global-set-key (kbd "M-o") 'ace-window)
  (setq aw-keys '(?f ?j ?d ?k ?s ?l ?a ?g ?h)
        aw-scope 'frame
        aw-ignore-current t)
  (require 'ace-link)
;     (defalias 'avy-process 'avy--process)
  (ace-link-setup-default)
  (setq avy-styles-alist nil
        avy-background t)
;     (add-to-list 'avy-styles-alist '(ace-link-org-agenda . at-full))
;     (add-to-list 'avy-styles-alist '(ace-link-org . at-full))
  (define-key org-mode-map (kbd "C-c M-o") 'ace-link-org)
  (define-key org-agenda-mode-map (kbd "C-c M-o") 'ace-link-org)

expand-region

This is an excellent package, although I do not use it that much I should find a better binding

  (require 'expand-region)
  (global-set-key (kbd "C-=") 'er/expand-region)

ERC

Enable erc dcc files transfer

  (require 'erc-dcc)

vterm

(require 'vterm)

TODO Phase out Package.el

Load package.el

  (require 'package)
  (add-to-list 'package-archives
 '("melpa-stable" . "http://stable.melpa.org/packages/") t)

Tidy-up

Save emacs-session files in appropriate directory

Save session files to the sessions directory so that they do not litter the .emacs.d base directory.

  (defun emacs-session-filename (session-id)
    "Construct a filename to save the session in based on SESSION-ID.
  If the directory ~/.emacs.d exists, we make a filename in there, otherwise
  a file in the home directory."
    (let ((basename (concat "sessions/session." session-id))
          (emacs-dir user-emacs-directory))
      (expand-file-name (if (file-directory-p emacs-dir)
                            (concat emacs-dir basename)
                          (concat "~/.emacs-" basename)))))

Moving to colemak

Set up all possible combinations of modifiers

  (defun concat-recursive (b &optional a)
    (if b
        (append (concat-recursive (cdr b) (concat a (car b)))
                (concat-recursive (cdr b) a))
      (when a (list a))))

  (setq modifier-combo (concat-recursive '("C-" "M-" "s-" "H-")))

Then list the swapped keys

  (setq tarmak1-swap-alist '(("j" . "e")
                             ("e" . "k")
                             ("k" . "n")
                             ("n" . "j")))
  (setq tarmak2-swap-alist '(("j" . "g")
                             ("g" . "t")
                             ("t" . "f")
                             ("f" . "e")
                             ("e" . "k")
                             ("k" . "n")
                             ("n" . "j")))
  (defun set-key-translation-map (pairs)
    (dolist (p pairs)
      (define-key key-translation-map  (kbd (downcase (car p))) (kbd (downcase (cdr p))))
      (define-key key-translation-map  (kbd (upcase (car p))) (kbd (upcase (cdr p))))))

  (defun set-key-translation-map-caseless (pairs)
    (dolist (p pairs)
      (define-key key-translation-map  (kbd (car p)) (kbd (cdr p)))))

  (defun reset-key-translation-map ()
    (dolist (c '("j" "k" "n" "e" "f" "t" "g"))
      (define-key key-translation-map (kbd (downcase c)) nil)
      (define-key key-translation-map (kbd (upcase c)) nil)))


  (defun tarmak1 ()
    (interactive)
    (set-key-translation-map '(("j" . "n")
                               ("k" . "e")
                               ("n" . "k")
                               ("e" . "j"))))


  (defun untarmak-modifiers ()
    (interactive)
    (set-key-translation-map-caseless
     (mapcan (lambda (swap-pair)
               (mapcar (lambda (mod-combo)
                         (cons (concat mod-combo
                                       (car swap-pair))
                               (concat mod-combo
                                       (cdr swap-pair))))
                       modifier-combo))
             tarmak2-swap-alist)))

  (defun tarmak-avy ()
    (interactive)
    (setq aw-keys '(?n ?t ?h ?j ?e ?d ?l ?s ?a)
          avy-keys '(?a ?s ?d ?t ?j ?h ?n ?e ?l)))


  (defun qwerty()
    (interactive)

    (reset-key-translation-map))

Finale

Fixup faces

This is really a workaround as I do not like either bold or italic. It needs to be at the end of the file since it sets the face for packages that have loaded in the meantime; yet it does not work perfectly as some packages are still to be loaded (most notably magit)

  (set-face-bold 'bold nil)
  (wilder/fixup-faces)
  (with-eval-after-load "info" (wilder/fixup-faces) nil)
  (with-eval-after-load "mu4e" (wilder/fixup-faces) nil)
  (with-eval-after-load "mm-view" (wilder/fixup-faces) nil)
  (with-eval-after-load 'gnus-cite (wilder/fixup-faces) nil)
  (add-hook 'gnus-art-load-hook #'wilder/fixup-faces)

Start server

;    (server-start)