Emacs init.el

This is an emacs configuration file. I had this in another repository and have been adding to it over the decades, occasionally removing things when troubleshooting but otherwise it's just a jumble right now, so I'm putting it in the fish-based repository to work on it.

The tangle creates a file give-the-fish/dingehaufen/init.el that you should copy or link into the right place ~/.emacs.d right now.

At some post I should look into breaking up the configuration (see https://emacs.stackexchange.com/a/18441 for an example).

Tangle Source

<<package-management>>

<<activate-pyvenv>>

<<org-mode>>

;; make sure org-babel comes before jupyter or any other code-based settings
<<org-babel>>

<<org-export-python>>

<<emacs-settings>>

<<emacs-file-locks>>

<<toggle-input-method>>

;; <<python-elpy>>

(custom-set-variables
       ;; custom-set-variables was added by Custom.
       ;; If you edit it by hand, you could mess it up, so be careful.
       ;; Your init file should contain only one such instance.
       ;; If there is more than one, they won't work right.
       '(js-indent-level 2)
       '(js2-basic-offset 2)
       '(js2-bounce-indent-p t)
       '(org-export-backends '(ascii html icalendar latex org))
       '(package-selected-packages
         (quote
          (htmlize ox-nikola ox-rst web-mode swiper smex paredit magit jedi ido-ubiquitous idle-highlight-mode god-mode fuzzy feature-mode csv-mode autopair ac-js2))))

      (custom-set-faces
       ;; custom-set-faces was added by Custom.
       ;; If you edit it by hand, you could mess it up, so be careful.
       ;; Your init file should contain only one such instance.
       ;; If there is more than one, they won't work right.
       '(rst-level-1 ((t (:background "white" :foreground "royal blue"))))
       '(rst-level-2 ((t (:background "white"))))
       '(rst-level-3 ((t (:background "cyan"))))
       '(rst-level-4 ((t (:background "magenta")))))

      ;; rst minor-mode
      (defun turn-on-rst () (rst-minor-mode 1))
      (add-hook 'python-mode-hook 'turn-on-rst)

      ;; hide-show mode
      (defun turn-on-hideshow () (hs-minor-mode 1))
      (add-hook 'python-mode-hook 'turn-on-hideshow)

      ;; make no-tabs universal
      (setq-default indent-tabs-mode nil)

      ;; ipython shell
      (setq python-shell-interpreter "ipython"
            python-shell-interpreter-args "-i")

      <<web-mode>>

      <<auto-complete>>

      (define-global-minor-mode select-electric-pair-mode electric-pair-mode
        (lambda ()
          (when (not (memq major-mode
                           (list 'web-mode 'js2-mode)))
            (electric-pair-mode))))

      (select-electric-pair-mode 1)

      ;; magit
      (setq global-magit-file-mode 1)

      ;; setup the keybinding to launch magit
      (global-set-key (kbd "C-x g") 'magit-status)

      <<tramp-mode>>

      <<tramp-backups>>

<<god-mode>>

<<jupyter-emacs>>

<<general-text>>

<<javascript>>

<<feature-mode>>

<<emacs-gui>>

<<yaml>>

;; <<vue>>

;; <<bats>>

<<backups>>

<<no-sudo-backups>>

;; <<markdown-mode>>

<<dockerfile-mode>>

<<keychain>>

<<hideshow-org>>

;; <<flycheck-mypy>>

<<add-path>>

Package Management

;; emacs package management
(require 'package)

;; add the repositories
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)

;; refresh the list
(when (not package-archive-contents)
  (package-refresh-contents))

(require 'use-package)

Pyvenv

To prevent errors when emacs starts up and tries to load jupyter (for emacs-jupyter) we need jupyter to be on the path. Now that debian and ubuntu don't want you to install python packages globally we need another way. I had installed it with pipx, which does work, but pipx doesn't doesn't install standalone libraries and sometimes breaks when trying to install dependencies so I think for this case it's better to avoid it and instead use a virtual-environment. Since it has to be activated before anything else that uses python packages, activating the environment should be put fairly early on in the init.el file.

(require 'pyvenv)
(pyvenv-activate "~/.virtualenvs/emacs-environment/")

This assumes that there's a virtual-environment named emacs-environment setup (with jupyter at least). Note that you could load elpy instead of just pyvenv by itself, but elpy is giving me errors (or at least lots of warnings) when it loads and I don't feel like troubleshooting it right now, since it doesn't play well with org-mode anyway.

Emacs Settings

;; show column-numbers
(column-number-mode)

;; show matching parentheses
(show-paren-mode 1)
(setq show-paren-delay 0)

;; global parentheses matching (`autopair` package needs to be installed)
(electric-pair-mode 1)

;; turn off auto-fill mode
(remove-hook 'text-mode-hook #'turn-on-auto-fill)

;; hide menu-bar by default
(menu-bar-mode -1)

;; hide the toolbar
(tool-bar-mode -1)

;; disable the scrollbar
(toggle-scroll-bar -1)

(add-to-list 'default-frame-alist '(background-color . "white"))
(add-to-list 'default-frame-alist '(foreground-color . "black"))

;; dark slate blue
;; (add-to-list 'default-frame-alist '(cursor-color . "#483D8B"))
;; dark red
(add-to-list 'default-frame-alist '(cursor-color . "#8B0000"))

;; Disable Bell
(setq ring-bell-function 'ignore)

File Locks

A lock got corrupted once in the cryfs directory, making the editing file unreadable. You can fix it by copying everything but the corrupted file out, destroying and re-creating the cryfs mount and copying the files back in, but hopefully this will fix it. It does mean that two people could edit the same file and cause problems, but oh, well.

(setq create-lockfiles nil)

Toggle Input Mode

This allows you to switch to latex input and then back using C-\. This is useful to embed special characters. Although you could probably just do the same thing with math mode if you want to wait until exporting.

;; (setq default-input-method "TeX")
(setq default-input-method "TeX")

Tramp Mode

Use SSH

;; tramp mode
(setq tramp-default-method "ssh")

No Backups

This is from the emacs manual.

Turn Off For Tramp Only

The configuration is currently saving backups to a local directory, so when I use tramp I get warnings about it. It doesn't tell you why but according to the emacs wiki this is a potential security leak (although probably not in the way I'm using it). Anyway, I've never used the backups so I'll just disable them for tramp.

;; disable tramp-backups
(add-to-list 'backup-directory-alist
             (cons tramp-file-name-regexp nil))

Note: This turns out to solve the wrong problem so I added another rule in the next section.

Turn Off For Sudo

Turning off the backups for tramp only fixed one case, but it turned out that the thing that made me look into this was using sudo on my local machine to opne the /etc/hosts file so I was actually solving the wrong (or only part of the) problem. This next bit is supposed to turn off all backups where you use sudo. So it probably doesn't belong under tramp any more. Maybe I'll move it later

(setq backup-enable-predicate
      (lambda (name)
        (and (normal-backup-enable-predicate name)
             (not
              (let ((method (file-remote-p name 'method)))
                (when (stringp method)
                  (member method '("su" "sudo"))))))))

God Mode

;; god-mode
(require 'god-mode)
(global-set-key (kbd "<escape>") 'god-mode-all)
(global-set-key (kbd "C-$") 'god-mode-all)
(global-set-key (kbd "<Scroll_Lock>") 'god-mode-all)
(define-key god-local-mode-map (kbd ".") 'repeat)

(setq god-exempt-major-modes nil)
(setq god-exempt-predicates nil)

(defun my-update-cursor ()
  (setq cursor-type (if (or god-local-mode buffer-read-only)
                        'box
                      'bar)))
(defun c/god-mode-update-cursor ()
  (let ((limited-colors-p (> 257 (length (defined-colors)))))
    (cond (god-local-mode (progn
                            (set-face-background 'mode-line (if limited-colors-p "white" "#e9e2cb"))
                            (set-face-background 'mode-line-inactive (if limited-colors-p "white" "#e9e2cb"))))
          (t (progn
               (set-face-background 'mode-line (if limited-colors-p "black" "#0a2832"))
               (set-face-background 'mode-line-inactive (if limited-colors-p "black" "#0a2832")))))))

(add-hook 'god-mode-enabled-hook 'my-update-cursor)
(add-hook 'god-mode-disabled-hook 'my-update-cursor)

;; window bindings for god-mode
(global-set-key (kbd "C-x C-o") 'other-window)
(global-set-key (kbd "C-x C-1") 'delete-other-windows)
(global-set-key (kbd "C-x C-2") 'split-window-below)
(global-set-key (kbd "C-x C-3") 'split-window-right)
(global-set-key (kbd "C-x C-0") 'delete-window)
(global-set-key (kbd "C-x C-B") 'switch-to-buffer)

;; allow using 's' and 'r' for repeated searches
(require 'god-mode-isearch)
(define-key isearch-mode-map (kbd "<escape>") 'god-mode-isearch-activate)
(define-key god-mode-isearch-map (kbd "<escape>") 'god-mode-isearch-disable)

(define-key god-local-mode-map (kbd ".") 'repeat)
;; set a default virtual environment
(pyvenv-activate "~/.virtualenvs/emacs")

;; hide-show is broken by god mode.
;; this adds universal quick and dirty code-folding that works
(defvar hs-special-modes-alist
  (mapcar 'purecopy
          '((c-mode "{" "}" "/[*/]" nil nil)
            (c++-mode "{" "}" "/[*/]" nil nil)
            (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
            (java-mode "{" "}" "/[*/]" nil nil)
            (js2-mode "{" "}" "/[*/]" nil))))

(defun toggle-selective-display (column)
  (interactive "P")
  (set-selective-display
   (or column
       (unless selective-display
         (1+ (current-column))))))

(defun toggle-hiding (column)
  (interactive "P")
  (if hs-minor-mode
      (if (condition-case nil
              (hs-toggle-hiding)
            (error t))
          (hs-show-all))
    (toggle-selective-display column)))
(load-library "hideshow")
(global-set-key (kbd "C-+") 'toggle-hiding)
(global-set-key (kbd "C-|") 'toggle-selective-display)
(add-hook 'java-mode-hook       'hs-minor-mode)
(add-hook 'sh-mode-hook         'hs-minor-mode)
(add-hook 'js2-mode-hook         'hs-minor-mode)

Python and elpy

  ;; elpy
(use-package elpy
  :ensure t
  :defer t
  :init
  (advice-add 'python-mode :before 'elpy-enable))
  (add-to-list 'auto-mode-alist '("\\.py" . python-mode))

Emacs Jupyter

(org-babel-jupyter-override-src-block "python")

Fish

;; fish functions
'(sh-basic-offset 2)
'(sh-indentation 2)
(setq auto-mode-alist (cons '("\\.fish$" . shell-script-mode) auto-mode-alist))

Org-mode

  ;; org-mode
  (require 'org)
  (define-key global-map "\C-cl" 'org-store-link)
  (define-key global-map "\C-ca" 'org-agenda)
  (setq org-log-done t)

  ;; org-mode agendas
  (setq org-agenda-files (list "~/documents/roku-chiji/repository/kanban.org"))

  ;; org-capture
  (setq org-default-notes-file (concat "~/documents/roku-chiji/repository/" "bugs.org"))
  (define-key global-map "\C-cc" 'org-capture)

  (setq org-capture-templates
        '(("b" "Bug" entry (file+headline "~/documents/roku-chiji/repository/bugs.org" "Bugs")
           "* BUG %?\n  %i\n  %a")))

  ;; todo-state names
  (setq org-todo-keywords
          '((sequence "TOMORROW" "TODAY" "DOING" "|" "DONE")))

  ;; org clean-outlines

  (setq org-startup-indented t
        org-hide-leading-stars t
        org-indent-indentation-per-level 1)

  ;; word-wrap
  (global-visual-line-mode 1)

  ;; start the calendar on monday
  (setq calendar-week-start-day 1)

  ;; start with outline folded
  (setq org-startup-folded t)

org-export python mode

This just stops emitting the message that emacs is using a default 4 spaces when exporting python.

(setq python-indent-guess-indent-offset t)  
(setq python-indent-guess-indent-offset-verbose nil)

web-mode

  ;; web-mode
  (require 'web-mode)
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.tmpl\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))

  (defun my-web-mode-hook ()
    "Hooks for Web mode."
    (setq web-mode-markup-indent-offset 2)
    (setq web-mode-css-indent-offset 2)
    (setq web-mode-code-indent-offset 2)
    (setq web-mode-enable-current-column-highlight t)
    (setq web-mode-enable-current-element-highlight t)
    (setq web-mode-engines-alist
        '(("jinja"    . "\\.html\\'"))
        )
  )
  (add-hook 'web-mode-hook  'my-web-mode-hook)

auto-complete

  ;; auto-complete
  ;; (defun turn-on-autocomplete () (auto-complete-mode 1))
  (add-to-list 'load-path "~/.emacs.d/lisp")
  (require 'auto-complete-config)
  (add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict")
  (ac-config-default)
  (defadvice auto-complete-mode (around disable-auto-complete-for-python)
  (unless (eq major-mode 'python-mode) ad-do-it))

general text

;; increase/decrease text size
(global-set-key (kbd "C-c C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)

javascript

;; js2
(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))

org-babel

  ;; org-babel
(require 'ob-js)

  (add-to-list 'org-src-lang-modes '("rst" . "rst"))
  (add-to-list 'org-src-lang-modes '("feature" . "feature"))
  (add-to-list 'org-src-lang-modes '("org" . "org"))
  (add-to-list 'org-src-lang-modes '("css" . "css"))
  (add-to-list 'org-src-lang-modes '("plantuml" . "plantuml"))
  (add-to-list 'org-src-lang-modes '("conf" . "conf"))

  (org-babel-do-load-languages
   'org-babel-load-languages
   '(
     (plantuml . t)
     (shell . t)
     (emacs-lisp . t)
     (latex . t)
     (org . t)
     (js . t)
     (jupyter . t)
     ))

  (setq org-plantuml-jar-path (expand-file-name "/usr/share/java/plantuml.jar"))

  ;; Don't treat underscores as sub-script notation
  (setq org-export-with-sub-superscripts nil)

  ;; Don't re-evaluate the source blocks before exporting
  (setq org-export-babel-evaluate nil)

  ;; don't confirm block evaluation
  (setq org-confirm-babel-evaluate nil)

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

  ;; noweb expansion only when you tangle
  (setq org-babel-default-header-args
        (cons '(:noweb . "tangle")
              (assq-delete-all :noweb org-babel-default-header-args))
        )

  ;; syntax highlighting in org-files
  (setq org-src-fontify-natively t)

  ;; export org to rst
  (require 'ox-rst)

  ;; export org to nikola
  (require 'ox-nikola)

  ;; export to latex/pdf
  (require 'ox-latex)

  ;; syntax-highlighting for pdf's
  (add-to-list 'org-latex-packages-alist '("" "minted"))
  (setq org-latex-listings 'minted)
  (setq org-latex-pdf-process '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

  ;; let the user set the indentation so you can insert text between methods in classes.
  (setq org-src-preserve-indentation t)

  ;; pygmentize ipython
  (add-to-list 'org-latex-minted-langs '(ipython "python"))

Feature Mode

(add-to-list 'auto-mode-alist '("\\.feature" . feature-mode))

yaml

(add-hook 'yaml-mode-hook
          (lambda ()
            (define-key yaml-mode-map "\C-m" 'newline-and-indent)))

Vue.js

;; setup files ending in “.vue” to open in vue-mode
;; (add-to-list 'auto-mode-alist '("\\.vue\\'" . vue-mode))

Bats

The Bash Automated Test System mode.

Keybinding Description State
C-c C-a Run all bat-files in the current directory Works
C-c C-, Run all the tests in the current buffer Works
C-c M-, Run the test where the cursor is Doesn't Work

There's a ticket on github to add this feature (?) to bats, but the old developers stopped supporting it and I don't know if the fork has it yet. It isn't working if you install bats from Ubuntu's repositories as of Bionic Beaver.

(add-to-list 'auto-mode-alist '("\\.bat\\'" . bats-mode))

Backups

From the Emacs Wiki.

(setq backup-directory-alist 
      '(("." . "/tmp/")))
(setq auto-save-file-name-transforms
      `((".*" , "/tmp/" t)))

Markdown Mode

(use-package markdown-mode
 :ensure t
 :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
 :init (setq markdown-command "pandoc")
)

Dockerfile Mode

(require 'dockerfile-mode)
(add-to-list 'auto-mode-alist '("Dockerfile\\'" . dockerfile-mode))

Flycheck

;; flycheck
(use-package flycheck
  :ensure t
  :config
  (global-flycheck-mode t)
  ;; note that these bindings are optional
  (global-set-key (kbd "C-c n") 'flycheck-next-error)
  ;; this might override a default binding for running a python process,
  ;; see comments below this answer
  (global-set-key (kbd "C-c p") 'flycheck-prev-error)
  )
;; flycheck-pycheckers
;; Allows multiple syntax checkers to run in parallel on Python code
;; Ideal use-case: pyflakes for syntax combined with mypy for typing
(use-package flycheck-pycheckers
  :after flycheck
  :ensure t
  :init
  (with-eval-after-load 'flycheck
    (add-hook 'flycheck-mode-hook #'flycheck-pycheckers-setup)
    )
  (setq flycheck-pycheckers-checkers
    '(
      mypy3
      pyflakes
      )
    )
  )
;; elpy
(use-package elpy
  :after poetry
  :ensure t
  :config
  (elpy-enable)
  (add-hook 'elpy-mode-hook 'poetry-tracking-mode) ;; optional if you're using Poetry
  (setq elpy-rpc-virtualenv-path 'current)
  (setq elpy-syntax-check-command "~/.virtualenvs/neurotic-networks/bin/pyflakes") ;; or replace with the path to your pyflakes binary
  ;; allows Elpy to see virtualenv
  (add-hook 'elpy-mode-hook
        ;; pyvenv-mode
        '(lambda ()
           (pyvenv-mode +1)
           )
        )
  ;; use flycheck instead of flymake
  (when (load "flycheck" t t)
  (setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
  (add-hook 'elpy-mode-hook 'flycheck-mode))
  )
;; poetry
(use-package poetry
  :ensure t)

Keychain

This is to be able to use ssh-agent (via keychain).

  • `keychain` needs to be installed (e.g. via apt)
  • It needs to be running - Add this to the fish.config
if status --is-interactive
 keychain --eval --quiet -Q id_rsa | source
end
(require 'keychain-environment)
(keychain-refresh-environment)

Hideshow-Org

(add-to-list 'load-path "~/projects/third-party/hideshow-org/")
(require 'hideshow-org)