Skip to content

Latest commit

 

History

History
executable file
·
2437 lines (1976 loc) · 74.8 KB

config.org

File metadata and controls

executable file
·
2437 lines (1976 loc) · 74.8 KB

Emacs Configuration

Introduction

This is my emacs configuration entry point. It is written in the literate programming style in this org-mode file. The embedded code blocks are extracted when the init.el file is loaded, and then the extracted files are loaded to complete the environmental configuration.

Pieces of this configuration have been taken from Magnar Sveen, Sascha Chua, Uncle Dave, David Wilson and a host of others referenced in various places on the internet, but primarily Emacs Wiki.

Personal Information

Obviously, you’ll want to change this to match your personal credentials.

(setq user-full-name "Brian O'Reilly"
      user-mail-address "[email protected]")

Which Key

which-key is a useful UI panel that appears when you start pressing any key binding in Emacs to offer you all possible completions for the prefix. For example, if you press C-c (hold control and press the letter c), a panel will appear at the bottom of the frame displaying all of the bindings under that prefix and which command they run. This is very useful for learning the possible key bindings in the mode of your current buffer.

(use-package which-key
  :ensure t
  :diminish which-key-mode
  :config
  (which-key-mode)
  (setq which-key-idle-delay 1))

Sane defaults

Sources for this section include Magnar Sveen and Sacha Chua.

The diminish package appears to have been subsumed into the Crux package by Bodizar Bhatzov.

(use-package diminish
  :ensure t)
;; These functions are useful. Activate them. This use of #'put is
;; strange, but this feature uses symbol properties.
(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'dired-find-alternate-file 'disabled nil)

;; Answering just 'y' or 'n' will do
(defalias 'yes-or-no-p 'y-or-n-p)

;; Keep all backup and auto-save files in one directory
(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
(setq auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t)))

;; UTF-8 please
(setq locale-coding-system 'utf-8) ; pretty
(set-terminal-coding-system 'utf-8) ; pretty
(set-keyboard-coding-system 'utf-8) ; pretty
(set-selection-coding-system 'utf-8) ; please
(prefer-coding-system 'utf-8) ; with sugar on top

;; tabs never in code. 
(setq-default indent-tabs-mode nil)
(setq-default indicate-empty-lines t)

;; Don't count two spaces after a period as the end of a sentence.
;; Just one space is needed.
(setq sentence-end-double-space nil)

;; delete the region when typing, as is conventional these days.
(delete-selection-mode t)

(show-paren-mode t)

(column-number-mode t)

(global-visual-line-mode)
(diminish 'visual-line-mode)

(setq uniquify-buffer-name-style 'forward)

;; -i gets alias definitions from .bash_profile
(setq shell-command-switch "-ic")

;; Don't beep at me
(setq visible-bell t)

;; when editing a script file, make sure it's executable when you save
;; it.

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

The following function for occur-dwim is taken from Oleh Krehel from his blog post at (or emacs irrelevant). It takes the current region or the symbol at point as the default value for occur.

;; in practice, I don't use this much. The keybinding has been given
;; to another mode.

(defun occur-dwim ()
  "Call `occur' with a sane default."
  (interactive)
  (push (if (region-active-p)
            (buffer-substring-no-properties
             (region-beginning)
             (region-end))
          (thing-at-point 'symbol))
        regexp-history)
  (call-interactively 'occur))

;; (bind-key "M-s o" 'occur-dwim)

Here we make page-break characters look pretty, instead of appearing as ^L in Emacs. Here’s an informative article called “Using Page-Breaks in GNU Emacs” by Eric J. M. Ritz.

(use-package page-break-lines
  :straight t)

Mark multiple files in dired and act upon them.

In dired mode, it is useful to mark a bunch of files and then open them all in separate buffers. Function implementation taken from Stack Overflow, here: In Emacs dired, how to find/visit multiple files?

(eval-after-load "dired"
  '(progn
     (define-key dired-mode-map "F" 'my-dired-find-file)
     (defun my-dired-find-file (&optional arg)
       "Open each of the marked files, or the file under the
        point, or when prefix arg, the next N files. "
       (interactive "P")
       (let* ((fn-list (dired-get-marked-files nil arg)))
         (mapc 'find-file fn-list)))))

Mac customizations

There are configurations to make when running Emacs on macOS (hence the “darwin” system-type check).

(when (string-equal system-type "darwin")
  ;; delete files by moving them to the trash
  (setq delete-by-moving-to-trash t)
  (setq trash-directory "~/.Trash")

  ;; Don't make new frames when opening a new file with Emacs
  (setq ns-pop-up-frames nil)

  ;; set the Fn key as the hyper key
  (setq ns-function-modifier 'hyper)

  ;; Use Command-` to switch between Emacs windows (not frames)
  (bind-key "s-`" 'other-window)
  
  ;; Use Command-Shift-` to switch Emacs frames in reverse
  (bind-key "s-~" (lambda() () (interactive) (other-window -1)))

  ;; Because of the keybindings above, set one for `other-frame'
  (bind-key "s-1" 'other-frame)

  ;; Fullscreen!
  (setq ns-use-native-fullscreen nil) ; Not Lion style
  (bind-key "<s-return>" 'toggle-frame-fullscreen)

  ;; buffer switching
  (bind-key "s-{" 'previous-buffer)
  (bind-key "s-}" 'next-buffer)

  ;; Compiling
  (bind-key "H-c" 'compile)
  (bind-key "H-r" 'recompile)
  (bind-key "H-s" (defun save-and-recompile () (interactive) (save-buffer) (recompile)))

  ;; disable the key that minimizes emacs to the dock because I don't
  ;; minimize my windows
  ;; (global-unset-key (kbd "C-z"))

  (defun open-dir-in-finder ()
    "Open a new Finder window to the path of the current buffer"
    (interactive)
    (start-process "mai-open-dir-process" nil "open" "."))
  (bind-key "C-c o f" 'open-dir-in-finder)

  (defun open-dir-in-iterm ()
    "Open the current directory of the buffer in iTerm."
    (interactive)
    (let* ((iterm-app-path "/Applications/iTerm.app")
           (iterm-brew-path "/opt/homebrew-cask/Caskroom/iterm2/1.0.0/iTerm.app")
           (iterm-path (if (file-directory-p iterm-app-path)
                           iterm-app-path
                         iterm-brew-path)))
      (start-process "mai-open-dir-process" nil "open" "-a" iterm-path ".")))
  (bind-key "C-c o t" 'open-dir-in-iterm)

  ;; Not going to use these commands
  (put 'ns-print-buffer 'disabled t)
  (put 'suspend-frame 'disabled t))

exec-path-from-shell makes the command-line path with Emacs’s shell match the same one on macOS.

(use-package exec-path-from-shell
  :if (memq window-system '(mac ns))
  :ensure t
  :init
  (exec-path-from-shell-initialize))

El Capitan fixes

El Capitan Fixes

(cond
 ((string-equal system-type "darwin")
  (let* ((cmd "sw_vers -productVersion")
         (macos-version (string-to-number
                         (cadr (split-string
                                (shell-command-to-string cmd)
                                "\\."))))
         (elcapitan-version 11))
    (when (>= macos-version elcapitan-version)
      (setq visible-bell nil)
      (setq ring-bell-function 'ignore)

      ;; El Capitan full screen animation is quick and delightful (enough to start using it).
      (setq ns-use-native-fullscreen t))))
 ;; other system specific things in separate test subclauses
 ((string-equal system-type "gnu/linux")
  (progn
    (message "Gnu Linux System!")))
 ((string-equal system-type "windows-nt")
  (progn
    (message "Oh dear... you're using Windows. :("))))

Org mode

Org mode is one of the killer applications that run inside Emacs. It turns plain text into data that can be used for computation. Often, that computation takes the form of making lists and organising your life, but it can be anything you can conceive that is ultimately computable.

It goes without saying that I also use it to manage my Emacs config.

Installation

Although Org mode ships with Emacs, the latest version can be installed externally. The configuration here follows the Org mode ELPA installation instructions.

Org mode is currently being installed right after use-package is initialised in init.el. It must be configured immediately, particularly if the package is being provided via the straight package manager, or you can get peculiar errors tangling this configuration file, and also when you enter an org file of any kind, where the configuration around faces and org functions just doesn’t work.

On Org mode version 9 I wasn’t able to execute source blocks out of the box. Others have run into the same issue too. The solution is to remove the .elc files from the package directory:

rm ${ORG_DIR}/*.elc

Better Font Faces

The efs/org-font-setup function configures various text faces to tweak the sizes of headings and use variable width fonts in most cases so that it looks more like we’re editing a document in org-mode. We switch back to fixed width (monospace) fonts for code blocks and tables so that they display correctly.

(defun efs/org-font-setup ()
  ;; Replace list hyphen with dot
  (font-lock-add-keywords 'org-mode
                          '(("^ *\\([-]\\) "
                             (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) ""))))))

  ;; Set faces for heading levels
  (dolist (face '((org-level-1 . 1.2)
                  (org-level-2 . 1.1)
                  (org-level-3 . 1.05)
                  (org-level-4 . 1.0)
                  (org-level-5 . 1.1)
                  (org-level-6 . 1.1)
                  (org-level-7 . 1.1)
                  (org-level-8 . 1.1)))
    (if (string-equal system-type "darwin")
        (set-face-attribute (car face) nil :font "Cantarell" :weight 'regular :height (cdr face))
      (set-face-attribute (car face) nil :font "Droid Sans" :weight 'regular :height (cdr face))))

  ;; Ensure that anything that should be fixed-pitch in Org files appears that way
  (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-code nil   :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-table nil   :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
  (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
  (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch))

(efs/org-font-setup)

Org setup

Speed commands are a nice and quick way to perform certain actions while at the beginning of a heading. It’s not activated by default.

See the doc for speed keys by checking out the documentation for speed keys in Org mode.

(setq org-use-speed-commands t)
(require 'org-tempo)
(setq org-image-actual-width 550)
(setq org-highlight-latex-and-related '(latex script entities))
(setq org-refile-targets
  '(("Archive.org" :maxlevel . 1)
    ("Tasks.org" :maxlevel . 1)))

;; Save Org buffers after refiling!
(advice-add 'org-refile :after 'org-save-all-org-buffers)

Org Tables .. Extended functionality

This package is useful when you have a lot of data in various org tables in a given document, and you want to drop it into a table that synthesizes various pieces of data from the other tables, with or without additional processing.

(use-package orgtbl-aggregate
  :straight t
  :after org)

Org capture

(bind-key "C-c c" 'org-capture)
(setq org-default-notes-file "~/Dropbox/Notes/notes.org")

Org agenda

Learned about this delq and mapcar trick from Sacha Chua’s config. This form will add the agenda file to the org-agenda-files list if the file actually exists at the place indicated. Remember to touch the file if you change this list.

(setq org-agenda-files
      (delq nil
            (mapcar (lambda (x) (and (file-exists-p x) x))
                    (list (expand-file-name "personal-agenda.org" site-org-files)
                          (expand-file-name "notes.org" site-org-files)
                          (expand-file-name "todos.org" site-org-files)
                          (expand-file-name "Tasks.org" site-org-files)
                          (expand-file-name "people.org" site-org-files)
                          (expand-file-name "Archive.org" site-org-files)))))

;; when we finish a todo, just mark it DONE and fold down the entry.
(defun org-toggle-todo-and-fold ()
  (interactive)
  (save-excursion
    (org-back-to-heading t) ;; Make sure command works even if point is
    ;; below target heading
    (cond ((looking-at "\*+ TODO")
           (org-todo "DONE")
           (hide-subtree))
          ((looking-at "\*+ DONE")
           (org-todo "TODO")
           (hide-subtree))
          (t (message "Can only toggle between TODO and DONE.")))))

(define-key org-mode-map (kbd "C-c C-d") 'org-toggle-todo-and-fold)

Org Roam

(use-package org-roam
  :straight t
  :init
  (setq org-roam-v2-ack t)
  :config
  (setf org-roam-directory (expand-file-name "Roam/" site-org-files))
  (setf org-roam-dailies-directory (expand-file-name "Dailies/" org-roam-directory))

  ;; New capture template
  (setq org-roam-dailies-capture-templates
        '(("d" "daily" entry #'org-roam-capture--get-point
           "* %?\n")))
  (org-roam-setup)

  :bind
  (("C-c n l" . org-roam-buffer-toggle)
   ("C-c n f" . org-roam-node-find)
   ("C-c n g" . org-roam-graph)
   ("C-c n r" . org-roam-node-random)
   (:map org-mode-map
    ("C-c n i" . org-roam-node-insert)
    ("C-c n o" . org-roam-get-create)
    ("C-c n t" . org-roam-tag-add)
    ("C-c n a" . org-roam-alias-add)
    ("C-c n l" . org-roam-buffer-toggle))))

(use-package  org-roam-bibtex
  :straight t
  :after org-roam)

;; (use-package org-roam-server
;;   :ensure t
;;   :after org-roam)

Org activation bindings

Set up some global key bindings that integrate with Org Mode features.

(bind-key "C-c l" 'org-store-link)
(bind-key "C-c c" 'org-capture)
(bind-key "C-c a" 'org-agenda)

Center Org Buffers

visual-fill-column will center org-mode buffers. This gives a more pleasing effect when writing long documents in natural languages.

(defun efs/org-mode-visual-fill ()
  (setq visual-fill-column-width 100
        visual-fill-column-center-text t)
  (visual-fill-column-mode 1))

(use-package visual-fill-column
  :after org
  :straight t
  :hook (org-mode . efs/org-mode-visual-fill))

Org Bullets

Makes it all look a bit nicer, I hate looking at asterisks. Also, see org-mode-setup configuration function at the top of this file.

(use-package org-bullets
  :straight t
  :after org
    :hook (org-mode . org-bullets-mode)
    :custom
    (org-bullets-bullet-list '("" "" "" "" "" "" "")))

Org tags

The default value is -77, which is weird for smaller width windows. I’d rather have the tags align horizontally with the header. 45 is a good column number to do that.

(setq org-tags-column 45)

(setq org-tag-alist
      '((:startgroup)
                                        ; Put mutually exclusive tags here
        (:endgroup)
        ("@errand" . ?E)
        ("@home" . ?H)
        ("@work" . ?W)
        ("agenda" . ?a)
        ("planning" . ?p)
        ("publish" . ?P)
        ("batch" . ?b)
        ("note" . ?n)
        ("idea" . ?i)))

;; Configure custom agenda views
(setq org-agenda-custom-commands
      '(("d" "Dashboard"
         ((agenda "" ((org-deadline-warning-days 7)))
          (todo "NEXT"
                ((org-agenda-overriding-header "Next Tasks")))
          (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))

        ("n" "Next Tasks"
         ((todo "NEXT"
                ((org-agenda-overriding-header "Next Tasks")))))

        ("W" "Work Tasks" tags-todo "+work-email")

        ;; Low-effort next actions
        ("e" tags-todo "+TODO=\"NEXT\"+Effort<15&+Effort>0"
         ((org-agenda-overriding-header "Low Effort Tasks")
          (org-agenda-max-todos 20)
          (org-agenda-files org-agenda-files)))

        ("w" "Workflow Status"
         ((todo "WAIT"
                ((org-agenda-overriding-header "Waiting on External")
                 (org-agenda-files org-agenda-files)))
          (todo "REVIEW"
                ((org-agenda-overriding-header "In Review")
                 (org-agenda-files org-agenda-files)))
          (todo "PLAN"
                ((org-agenda-overriding-header "In Planning")
                 (org-agenda-todo-list-sublevels nil)
                 (org-agenda-files org-agenda-files)))
          (todo "BACKLOG"
                ((org-agenda-overriding-header "Project Backlog")
                 (org-agenda-todo-list-sublevels nil)
                 (org-agenda-files org-agenda-files)))
          (todo "READY"
                ((org-agenda-overriding-header "Ready for Work")
                 (org-agenda-files org-agenda-files)))
          (todo "ACTIVE"
                ((org-agenda-overriding-header "Active Projects")
                 (org-agenda-files org-agenda-files)))
          (todo "COMPLETED"
                ((org-agenda-overriding-header "Completed Projects")
                 (org-agenda-files org-agenda-files)))
          (todo "CANC"
                ((org-agenda-overriding-header "Cancelled Projects")
                 (org-agenda-files org-agenda-files)))))))

Org Capture Templates

(use-package doct
  :straight t)
(setq org-capture-templates
    `(("t" "Tasks / Projects")
      ("tt" "Task" entry (file+olp "~/Dropbox/OrgFiles/Tasks.org" "Inbox")
           "* TODO %?\n  %U\n  %a\n  %i" :empty-lines 1)

      ("j" "Journal Entries")
      ("jj" "Journal" entry
           (file+olp+datetree "~/Dropbox/OrgFiles/Journal.org")
           "\n* %<%I:%M %p> - Journal :journal:\n\n%?\n\n"
           ;; ,(dw/read-file-as-string "~/Notes/Templates/Daily.org")
           :clock-in :clock-resume
           :empty-lines 1)
      ("jm" "Meeting" entry
           (file+olp+datetree "~/Dropbox/OrgFiles/Journal.org")
           "* %<%I:%M %p> - %a :meetings:\n\n%?\n\n"
           :clock-in :clock-resume
           :empty-lines 1)

      ("w" "Workflows")
      ("we" "Checking Email" entry (file+olp+datetree "~/Dropbox/OrgFiles/Journal.org")
           "* Checking Email :email:\n\n%?" :clock-in :clock-resume :empty-lines 1)

      ;; ("m" "Metrics Capture")
      ;; ("mw" "Weight" table-line (file+headline "~/Dropbox/OrgFiles/Metrics.org" "Weight")
      ;;  "| %U | %^{Weight} | %^{Notes} |" :kill-buffer t)
      ))

Org babel languages

(use-package ob-restclient
  :straight t
  :after org)
(use-package ob-js
  :ensure t
  :after org)
(org-babel-do-load-languages
 'org-babel-load-languages
 '((python . t)
   (C . t)
   (calc . t)
   (latex . t)
   (java . t)
   (ruby . t)
   (lisp . t)
   (scheme . t)
   (shell . t)
   (sqlite . t)
   (js . t)
   (restclient . t)))


(defun my-org-confirm-babel-evaluate (lang body)
  "Do not confirm evaluation for these languages."
  (not (or (string= lang "C")
           (string= lang "java")
           (string= lang "python")
           (string= lang "emacs-lisp")
           (string= lang "sqlite")
           (string= lang "resclient"))))

(setq org-confirm-babel-evaluate 'my-org-confirm-babel-evaluate)

Org babel/source blocks

I like to have source blocks properly syntax highlighted and with the editing popup window staying within the same window so all the windows don’t jump around. Also, having the top and bottom trailing lines in the block is a waste of space, so we can remove them.

I noticed that fontification doesn’t work with markdown mode when the block is indented after editing it in the org src buffer—the leading #s for headers don’t get fontified properly because they appear as Org comments. Setting org-src-preserve-indentation makes things consistent as it doesn’t pad source blocks with leading spaces.

(setq org-src-fontify-natively t
      org-src-window-setup 'current-window
      org-src-strip-leading-and-trailing-blank-lines t
      ;; org-src-preserve-indentation t
      org-src-tab-acts-natively t)

Org exporting

Pandoc exporter

Pandoc converts between a huge number of different file formats.

(use-package ox-pandoc
  :no-require t
  :defer 10
  :straight t)

LaTeX exporting

I’ve had issues with getting BiBTeX to work correctly with the LaTeX exporter for PDF exporting. By changing the command to `latexmk` references appear in the PDF output like they should. Source: http://tex.stackexchange.com/a/161619.

(setq org-latex-pdf-process (list "latexmk -pdf %f"))

exporting to html sometimes (always?) requires htmlize

(use-package htmlize
  :straight t)

Hydra

Hail Hydra!

(use-package hydra
  :straight t)

(defhydra hydra-zoom (global-map "<f2>")
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

Projectile

Projectile is an awesome project manager, mostly because it recognizes directories with a .git directory as projects and helps you manage them accordingly.

Enable projectile globally

This makes sure that everything can be a project.

(use-package projectile
  :straight t
  :init
  (projectile-mode 1))

Let projectile call make

(global-set-key (kbd "<f5>") 'projectile-compile-project)

Perspectives

My emacs session tends to build up an enormous buffer list over time, which is (barely) manageable with the use of Helm. I have stopped using Helm, so this might still be a good idea. What I’d like to do is associate specific groups of buffers with a ‘workspace’ in emacs, so that when I switch to that workspace, only the associated buffers appear in the buffer list. Apparently perspective.el can provide this functionality. Including here on a provisional basis. In practice I have not made this a part of my workflow, yet, so I’m not going to generate the package clause when this file is tangled.

(use-package perspective
  :straight t
  ;; :bind
  ;; ("C-x C-b" . persp-list-buffers)   ; or use a nicer switcher, see below
  :config
  (persp-mode))

Default web browser

Taken, with thanks, from dakrone/eos at github.

(global-set-key (kbd "C-x m") 'browse-url-at-point)

(use-package eww
  :defer t
  :init
  (setq browse-url-browser-function
        '((".*google.*maps.*" . browse-url-generic)
          ;; Github goes to firefox, but not gist
          ("http.*\/\/github.com" . browse-url-generic)
          ("groups.google.com" . browse-url-generic)
          ("docs.google.com" . browse-url-generic)
          ("melpa.org" . browse-url-generic)
          ("build.*\.elastic.co" . browse-url-generic)
          (".*-ci\.elastic.co" . browse-url-generic)
          ("internal-ci\.elastic\.co" . browse-url-generic)
          ("zendesk\.com" . browse-url-generic)
          ("salesforce\.com" . browse-url-generic)
          ("stackoverflow\.com" . browse-url-generic)
          ("apache\.org\/jira" . browse-url-generic)
          ("thepoachedegg\.net" . browse-url-generic)
          ("zoom.us" . browse-url-generic)
          ("t.co" . browse-url-generic)
          ("twitter.com" . browse-url-generic)
          ("\/\/a.co" . browse-url-generic)
          ("youtube.com" . browse-url-generic)
          ("amazon.com" . browse-url-generic)
          ("slideshare.net" . browse-url-generic)
          ("." . eww-browse-url)))
  (setq browser-url-secondary-browser-function 'browse-url-generic)
  (setq browse-url-generic-program (executable-find "nyxt"))
  (add-hook 'eww-mode-hook #'toggle-word-wrap)
  (add-hook 'eww-mode-hook #'visual-line-mode)
  :config
  (use-package s :ensure t)
  (define-key eww-mode-map "o" 'eww)
  (define-key eww-mode-map "O" 'eww-browse-with-external-browser)
  (define-key eww-mode-map "j" 'next-line)
  (define-key eww-mode-map "k" 'previous-line))

(use-package eww-lnum
    :straight t
    :after eww
    :config
    (bind-key "f" #'eww-lnum-follow eww-mode-map)
    (bind-key "U" #'eww-lnum-universal eww-mode-map))

(require 'ffap)
(defun browse-last-url-in-brower ()
  (interactive)
  (save-excursion
    (ffap-next-url t t)))

;; (global-set-key (kbd "C-c u") 'browse-last-url-in-brower)

Dashboard

This is your new startup screen, together with projectile it works in unison and provides you with a quick look into your latest projects and files. Change the welcome message to whatever string you want and change the numbers to suit your liking, I find 5 to be enough.

(use-package dashboard
  :ensure t
  :config
    (dashboard-setup-startup-hook)
    (setq dashboard-startup-banner "~/.emacs.d/img/dashLogo.png")
    (setq dashboard-items '((recents  . 5)
                            (projects . 5)))
    (setq dashboard-banner-logo-title "DeepSky Emacs"))

The terminal

VTerm works for ncurses programs

(use-package vterm
  :straight t)

Default shell should be zsh

Don’t ask me what shell I want to use. In general this is a solved problem..

(defvar my-term-shell "/usr/bin/zsh")
(defadvice ansi-term (before force-bash)
  (interactive (list my-term-shell)))
(ad-activate 'ansi-term)

Moving around in emacs

Spending too much time flapping around between buffers, stuck in the interstitial space where work goes to die.

swiper and why is the default search so lame

Also revisiting this in our retooling around orderless, consult, marginalia, and embark.

(use-package swiper
  :ensure t
  :bind ("C-s" . 'swiper))

List buffers

source: http://ergoemacs.org/emacs/emacs_buffer_management.html

Auto-revert-mode updates buffers so that they reflect what is on the disk. This is particularly useful in the presence of git or other version control software which can change the files from beneath the buffers in emacs. source: Magnar Sveen

(add-hook 'dired-mode-hook 'auto-revert-mode)
(global-auto-revert-mode t)

;; Also auto refresh dired, but be quiet about it
(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose nil)

Recentf

(use-package recentf
  :bind ("C-x C-r" . helm-recentf)
  :config
  (recentf-mode t)
  (setq recentf-max-saved-items 200))

SparQL mode

most relevantly, sparql is used to define queries to the WikiData knowledge database.

(use-package sparql-mode
  :straight t
  ;; :load-path "~/SourceCode/lisp/emacs_stuff/sparql-mode"
  )

PDF Tools

This really is the best PDF management system I’ve ever used.

(use-package pdf-tools
  :ensure t
  :config
  ;; (pdf-tools-install)
  (setq-default pdf-view-display-size 'fit-width)
  (setq pdf-annot-activate-created-annotations t))

Tramp

(use-package tramp
  :ensure t
  :config
  ;; tramp hangs when remote has 'weird' prompt. Check in for this terminal type.
  (setf tramp-terminal-type "tramp")
  (add-to-list 'tramp-connection-properties
               (list (regexp-quote "/ssh:[email protected]:")
                     "remote-shell" "/bin/sh"))) 

Window

Convenient keybindings to resize windows.

(bind-key "C-s-<left>"  'shrink-window-horizontally)
(bind-key "C-s-<right>" 'enlarge-window-horizontally)
(bind-key "C-s-<down>"  'shrink-window)
(bind-key "C-s-<up>"    'enlarge-window)

Whenever I split windows, I usually do so and also switch to the other window as well, so might as well rebind the splitting key bindings to do just that to reduce the repetition.

(defun vsplit-other-window ()
  "Splits the window vertically and switches to that window."
  (interactive)
  (split-window-vertically)
  (other-window 1 nil))
(defun hsplit-other-window ()
  "Splits the window horizontally and switches to that window."
  (interactive)
  (split-window-horizontally)
  (other-window 1 nil))

(bind-key "C-x 2" 'vsplit-other-window)
(bind-key "C-x 3" 'hsplit-other-window)

Whitespace mode

Because sometimes you have to look at python code that came from a person with unusual editor defaults.

(use-package whitespace
  :bind ("s-<f10>" . whitespace-mode))

Aggressive Indent Mode

(use-package aggressive-indent
  :straight t
  :config
  (global-aggressive-indent-mode 1)
  (add-to-list 'aggressive-indent-excluded-modes 'html-mode)
  (add-to-list 'aggressive-indent-excluded-modes 'python-mode))

File Management

Dired

Dired configuration is split between init.el and this clause in config.org, for reasons related to the way that emacs is initialised in this regime. If dired is not configured early, emacs throws to the debugger with an error when dired is called in regular use. (I don’t know if this is still true.)

;; (use-package dired-single
;;   :ensure t
;;   :after dired)

(use-package all-the-icons-dired
  :straight t
  :after dired
  :diminish all-the-icons-dired-mode
  :hook (dired-mode . all-the-icons-dired-mode))

Mail with mu4e

(use-package mu4e
  :ensure nil
  :defer 120
  :load-path "/usr/share/emacs/site-lisp/mu4e/"

  :config
  ;; this setting avoids mbsync problems
  (setq mu4e-change-filenames-when-moving t)

  ;; update every 10 minutes
  (setq mu4e-update-interval (* 10 60))
  (setq mu4e-get-mail-command "mbsync -a")
  (setq mu4e-maildir "~/Mail/GMail/")

  (setq mu4e-drafts-folder "/[Gmail].Drafts")
  (setq mu4e-sent-folder "/[Gmail].Sent Mail")
  (setq mu4e-refile-folder "/[Gmail].All Mail")
  (setq mu4e-trash-folder "/[Gmail].Trash")

  (setq mu4e-headers-fields
        '((:human-date . 25)
          (:flags . 6)
          (:from . 22)
          (:to . 22)
          (:thread-subject . nil)))

  (setq mu4e-maildir-shortcuts
        '(("/Inbox"               . ?i)
          ("/[Gmail].Sent Mail"   . ?s)
          ("/[Gmail].Trash"       . ?t)
          ("/[Gmail].Drafts"      . ?d)
          ("/[Gmail].All Mail"    . ?a))))

Minor conveniences

Emacs is at it’s best when it just does things for you, or shows you the way. This can best be achieved using a number of small extensions. While on their own they might not be particularly impressive. Together they create a nice environment for you to work in.

visiting the configuration

Quickly edit ~/.emacs.d/config.org. The Emacs way being the Emacs way, this specific keybinding turns out to be one of the most useful quality of life changes in this config, which is odd, considering the triviality of the feature.

(defun config-visit ()
  (interactive)
  (find-file "~/.emacs.d/config.org"))
(global-set-key (kbd "C-c e") 'config-visit)

Reloading the configuration

Simply pressing Control-c r will reload this file, very handy. You can also manually invoke config-reload.

(defun config-reload ()
  "Reloads ~/.emacs.d/config.org at runtime"
  (interactive)
  (org-babel-load-file (expand-file-name "~/.emacs.d/config.org")))
(global-set-key (kbd "C-c r") 'config-reload)

Subwords

Emacs treats camelCase strings as a single word by default, this changes said behaviour.

(global-subword-mode 1)

Beacon

While changing buffers or workspaces, the first thing you do is look for your cursor. Unless you know its position, you can not move it efficiently. Every time you change buffers, the current position of your cursor will be briefly highlighted now.

(use-package beacon
  :straight t
  :config
  (beacon-mode 1))

ELPA packages

These are the packages that are neither built into Emacs nor required to achieve the base configuration state. feel free to add or remove as many or as few of these as you want; they generally reflect my own biases and developmental requirements, so it is unlikely that this list will be perfectly harmonic with your own needs.

Avy - a better Ace

Avy integrates with Ace window, and works like Ace Jump mode.

(use-package avy
  :straight t
  :config 
  (avy-setup-default)
  (set-face-attribute 'avy-lead-face-0 nil :background "blue" :foreground "yellow")
  (set-face-attribute 'avy-lead-face-1 nil :background "purple4" :foreground "goldenrod")
  (set-face-attribute 'avy-lead-face-1 nil :background "SlateBlue4" :foreground "light goldenrod")
  :bind ("s-s c" . avy-goto-char))

Ace Window

ace-window is a package that uses the same idea from ace-jump-mode for buffer navigation, but applies it to windows. The default keys are 1-9.

(use-package ace-window
  :ensure t
  :config
  (ace-window-display-mode)
  :bind ("s-o" . ace-window))

Ag – The Silver Searcher.

(use-package ag
  :commands ag
  :ensure t
  :config
  (setq ag-highlight-search t
        ag-reuse-window nil
        ag-reuse-buffers t))

Android mode

(use-package android-mode
  :ensure t
  :defer t)

C-Eldoc

This package displays function signatures in the mode line.
(use-package c-eldoc
  :commands c-turn-on-eldoc-mode
  :ensure t
  :init (add-hook 'c-mode-hook #'c-turn-on-eldoc-mode))

Clojure

;; (use-package clojure-mode
;;   :defer t
;;   :ensure t)

Crux

Collection of Ridiculously Useful eXtensions

(use-package crux
  :straight t
  :bind (("C-c o o" . crux-open-with)
         ("C-c u" . crux-view-url)))

Vagrant

(use-package vagrant
  :straight t)

(use-package vagrant-tramp
  :straight t)

Docker

(use-package docker
  :defer t
  :straight t)

(use-package docker-cli
  :straight t)

(use-package docker-api
  :straight t)

(use-package docker-compose-mode
  :straight t)

;; (use-package tramp-docker
;;   :straight t)

(use-package dockerfile-mode
  :straight t)

Emmet

According to their website, “Emmet — the essential toolkit for web-developers.”

(use-package emmet-mode
  :ensure t
  :commands emmet-mode
  :config
  (add-hook 'html-mode-hook 'emmet-mode)
  (add-hook 'css-mode-hook 'emmet-mode))

flycheck

(use-package flycheck
  :ensure t
  :diminish flycheck-mode
  :init (global-flycheck-mode))

(use-package flycheck-cython
  :ensure t
  :after flycheck)

(use-package flycheck-clojure
  :ensure t
  :init (flycheck-clojure-setup))

(use-package flycheck-nim
  :ensure t
  :after flycheck)

0x0

Make low friction pastes to 0x0, forex sharing code to IRC

(use-package 0x0
  :ensure t)

Gists

(use-package gist
  :ensure t
  :commands gist-list)

Helm

;; (use-package helm
;;   :ensure t
;;   ;; :diminish helm-mode
;;   :init (progn
;;           (use-package helm-config)
;;           (setq helm-locate-command "mdfind -interpret -name %s %s"
;;                 helm-ff-newfile-prompt-p nil
;;                 helm-M-x-fuzzy-match t)
;;           (helm-mode 1))

;;   :bind ((:map helm-map
;;                ("<tab>" . helm-execute-persistent-action)
;;                ("C-c h" . helm-command-prefix)
;;                ("C-x b" . helm-mini)
;;                ("C-x C-b" . 'helm-buffers-list)
;;                ("C-`" . helm-resume)))
;;   :bind   (("M-x" . helm-M-x)
;;             ("C-x C-f" . helm-find-files))
;;   :config
;;   (helm-autoresize-mode 1))

;; (use-package helm-ag
;;   :defer 10
;;   :ensure t
;;   :after helm
;;   :bind ("C-c M-s" . helm-do-ag)
;;   :config
;;   (custom-set-variables
;;    '(helm-ag-base-command "ag --nocolor --nogroup --ignore-case")
;;    '(helm-ag-command-option "--all-text")
;;    '(helm-ag-insert-at-point 'symbol)
;;    '(helm-ag-ignore-buffer-patterrns '("\\.txt\\'" "\\.mkd\\'"))))

Completion

;; vertico is the base for our Helm exodus.
(use-package vertico
  :straight t
  :init
  (vertico-mode 1)
  :custom
  (vertico-count 13)
  (vertico-resize t)
  (vertico-cycle t)
  :config
  (vertico-mode))

;; this will put most recent items at the top of any given vertico selection.
(use-package savehist
  :straight t
  :init
  (savehist-mode))

;; completion selection (narrowing) enhancements.
(use-package consult
  :straight t
  :bind
  ("s-s o" . consult-outline)
  ("C-s" . consult-line)
  ("s-s s" . consult-ripgrep))

;; this is a completion style, which defines how we match against input.
(use-package orderless
  :straight t
  :custom
  (completion-styles '(orderless))
  (completion-category-overrides '((file (styles . (partial-completion)))))
  (setq completion-category-defaults nil))

;; metadata around completion selections
(use-package marginalia
  :straight t
  :custom 
  (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  :init
  (marginalia-mode 1))

;; actions within completion selections
(use-package embark
  :straight t
  :bind ("C-." . embark-act))

Company

(use-package company
  :ensure nil
  :diminish company-mode
  ;; :bind (:map company-mode-map
  ;;             (("C-n" . company-select-next)
  ;;              ("C-p" . company-select-previous)
  ;;              ("C-d" . company-show-doc-buffer)
  ;;              ("M-." . company-show-location)))
  :config
  (progn
    ;; less than this and it disrupts typing when you aren't interested in completion.
    (setq company-idle-delay 0.9)
    (setq company-minimize-prefix-length 3)
    ;; company completion everywhere.
    (add-hook 'after-init-hook 'global-company-mode)
    (require 'color)

    (let ((bg (face-attribute 'default :background)))
      (custom-set-faces
       `(company-tooltip ((t (:inherit default :background ,(color-lighten-name bg 2)))))
       `(company-scrollbar-bg ((t (:background ,(color-lighten-name bg 10)))))
       `(company-scrollbar-fg ((t (:background ,(color-lighten-name bg 5)))))
       `(company-tooltip-selection ((t (:inherit font-lock-function-name-face))))
       `(company-tooltip-common ((t (:inherit font-lock-constant-face))))))

    (with-eval-after-load 'company
      (define-key company-active-map (kbd "M-n") nil)
      (define-key company-active-map (kbd "M-p") nil)
      (define-key company-active-map (kbd "C-n") #'company-select-next)
      (define-key company-active-map (kbd "C-p") #'company-select-previous)
      (define-key company-active-map (kbd "SPC") #'company-abort))))

;; (use-package company-box
;;   :after company)

(use-package company-quickhelp
  :after (company)
  :hook (company-mode . company-quickhelp-mode)
  :config
  (setq company-quickhelp-delay 1.0)
  :ensure t)

Dictionary (Websters) support

I was struggling to find an acceptable english dictionary for local off-line use, and googling lead me to a salubrious link tree, starting with the ever productive Marcin Borkowski: Marcin Borkowski on using the right dictionary.

the tldr is:

  1. Download the Webster’s dictionary in StarDict format, as Somers tells you to do. (Apparently it’s not “some strange format”, but a standard format for a digital dictionary.)
  2. Unzip the files and put them in ~/.stardict/dic
  3. Install sdcv, a command-line utility for accessing StarDict dictionaries. (On Arch GNU/Linux with from the AUR with yay, it is yay -S sdcv.)
  4. My config is using straight, so I’m accessing the sdcv package with the package manager, as below
  5. With point on a word to look up, say M-x sdcv-search, or M-x sdcv-search anywhere and type in the word.
  6. You can press RET on any word in the definitionto look that one up. This is an inescapable rabbit hole for people of a certain disposition.
(use-package sdcv
  :straight t)

Helpful

This package gives richer help information, and makes interrogating emacs more fruitful.

(use-package helpful
  :ensure t
  :config
  (global-set-key (kbd "C-h f") #'helpful-callable)
  (global-set-key (kbd "C-h v") #'helpful-variable)
  (global-set-key (kbd "C-h k") #'helpful-key)
  ;; Lookup the current symbol at point. C-c C-d is a common keybinding
  ;; for this in lisp modes.
  (global-set-key (kbd "C-c C-d") #'helpful-at-point)

  ;; Look up *F*unctions (excludes macros).
  ;;
  ;; By default, C-h F is bound to `Info-goto-emacs-command-node'. Helpful
  ;; already links to the manual, if a function is referenced there.
  (global-set-key (kbd "C-h F") #'helpful-function)

  ;; Look up *C*ommands.
  ;;
  ;; By default, C-h C is bound to describe `describe-coding-system'. I
  ;; don't find this very useful, but it's frequently useful to only
  ;; look at interactive functions.
  (global-set-key (kbd "C-h C") #'helpful-command))

LaTeX Extra

(use-package latex-extra
  :defer t
  :ensure t)

LaTeX Preview Mode

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

Magit

A great interface for git projects. It’s much more pleasant to use than the git interface on the command line. Use an easy keybinding to access magit.

(use-package magit
  :straight t
  :defer t
  :bind ("C-c g" . magit-status)
  :config
  (define-key magit-status-mode-map (kbd "q") 'magit-quit-session))

(use-package forge
  :straight t
  :defer t
  :after magit
  :config
  (setq auth-source '("~/.authinfo")))

Fullscreen magit

The following code makes magit-status run alone in the frame, and then restores the old window configuration when you quit out of magit.

No more juggling windows after commiting. It’s magit bliss.

Source: Magnar Sveen

;; full screen magit-status
(defadvice magit-status (around magit-fullscreen activate)
  (window-configuration-to-register :magit-fullscreen)
  ad-do-it ;; ad-do-it is a special marker for 'around advice that refers to the wrapped function.
  (delete-other-windows))

(defun magit-quit-session ()
  "Restores the previous window configuration and kills the magit buffer"
  (interactive)
  (kill-buffer)
  (jump-to-register :magit-fullscreen))

Markdown mode

(use-package markdown-mode
  :ensure t
  :mode (("\\.markdown\\'" . markdown-mode)
         ("\\.md\\'"       . markdown-mode)))

Multiple cursors

We’ll also need to (require 'multiple-cusors) because of an autoload issue.

(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c" . mc/edit-lines)
         ("C->"         . mc/mark-next-like-this)
         ("C-<"         . mc/mark-previous-like-this)
         ("C-c C-<"     . mc/mark-all-like-this)
         ("C-!"         . mc/mark-next-symbol-like-this)
         ("s-d"         . mc/mark-all-dwim)))

Perspective

Workspaces in Emacs.

(use-package perspective
  :ensure t
  :defer t
  :config (persp-mode))

Projectile

Projectile Home

Project navigation and management library for Emacs.

(use-package projectile
  :ensure t
  :diminish projectile-mode
  :commands (projectile-mode projectile-switch-project)
  :bind ("C-c p p" . projectile-switch-project)
  :config
  (projectile-global-mode t)
  (setq projectile-enable-caching t)
  (setq projectile-switch-project-action 'projectile-dired))

Quickrun

(use-package quickrun
  :defer 10
  :ensure t
  :bind ("H-q" . quickrun))

Restclient

See Emacs Rocks! Episode 15 to learn how restclient can help out with testing APIs from within Emacs. The HTTP calls you make in the buffer aren’t constrainted within Emacs; there’s the restclient-copy-curl-command to get the equivalent curl call string to keep things portable.

(use-package restclient
  :ensure t
  ;; :load-path "~/SourceCode/lisp/emacs_stuff/restclient.el"
  :mode ("\\.restclient\\'" . restclient-mode))

Scratch

Convenient package to create *scratch* buffers that are based on the current buffer’s major mode. This is more convienent than manually creating a buffer to do some scratch work or reusing the initial *scratch* buffer.

(use-package scratch
  :ensure t
  :commands scratch)

Shell pop

(use-package shell-pop
  :ensure t
  :bind ("M-<f12>" . shell-pop))

Skeletor

I’m constantly looking for tools that make starting projects faster, and more correct. There seem to be dozens of them, at least one for every language. The workflow in these tools is always “Run the tool, then find the resulting project in Emacs.” … since most of my projects are written in Common Lisp, I live in Emacs pretty much all the time. It seems like a redundancy in tooling which is not necessary. Starting in emacs, and running the project skeleton tool is practically ideal, and would be bested only by a system running in an Emacs written in Common Lisp. At any rate, I’m looking at Skeletor to see how it fares under my generally unusual requirements.

(use-package skeletor
  :ensure t
  :custom
  (skeletor-project-directory "~/SourceCode/lisp/"))

Skewer mode

Live coding for HTML/CSS/JavaScript.

(use-package skewer-mode
  :commands skewer-mode
  :ensure t
  :config (skewer-setup))

Smartscan

Quickly jumps between other symbols found at point in Emacs.

http://www.masteringemacs.org/article/smart-scan-jump-symbols-buffer

(use-package smartscan
  :ensure t
  :config (global-smartscan-mode 1)
  :bind (("s-n" . smartscan-symbol-go-forward)
         ("s-p" . smartscan-symbol-go-backward)))

Smoothscrolling

This makes it so C-n-ing and C-p-ing won’t make the buffer jump around so much.

(use-package smooth-scrolling
  :ensure t)

Undo Tree

(use-package undo-tree
  :straight t
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  :custom
  (undo-tree-auto-save-history nil))

Visible mode

I found out about this mode by looking through simple.el. I use it to see raw org-mode files without going to a different mode like text-mode, which is what I had done in order to see invisible text (with org hyperlinks). The entire buffer contents will be visible while still being in org mode.

(use-package visible-mode
  :bind (("H-v" . visible-mode)
         ("s-<f2>" . visible-mode)))

w3m for webby reading

;; (use-package w3m
;;   :ensure t
;;   :defer t
;;   :config
;;   (progn
;;     (setq browse-url-browser-function 'w3m-browse-url)
;;     (autoload 'w3m-browse-url "w3m" "Ask a WWW browser to show a URL." t)
;;     (global-set-key "\C-xm" 'browse-url-at-point)
;;     (setq w3m-use-cookies t)))

XQuery mode

(use-package xquery-mode
  :ensure t
  :defer t)

Yasnippet

Yeah, snippets! I start with snippets from Andrea Crotti’s collection and have also modified them and added my own.

It takes a few seconds to load and I don’t need them immediately when Emacs starts up, so we can defer loading yasnippet until there’s some idle time.

(use-package yasnippet
  :straight t
  :config
  ;; (setq yas-snippet-dirs (concat user-emacs-directory "snippets"))
  (yas-reload-all)
  (yas-global-mode))

(use-package yasnippet-snippets
    :straight t
    :after yasnippet)

(use-package common-lisp-snippets
    :straight t
    :after yasnippet)

Zoom-frm

zoom-frm is a nice package that allows you to resize the text of entire Emacs frames (this includes text in the buffer, mode line, and minibuffer). The zoom-in/out command acts similar to the text-scale-adjust command—you can chain zooming in, out, or resetting to the default size once the command has been initially called.

Changing the frame-zoom-font-difference essentially enables a “presentation mode” when calling toggle-zoom-frame.

This mode is not available in elpa/melpa, so use-package will obviously not work in this case. If you are giving a lot of presentations with emacs, it is very useful, and you can still find the system at Emacs WIKI zoom-frm.el. Include it from init.el.

;; (use-package zoom-frm 
;;   :ensure t
;;   :bind (("C-M-=" . zoom-in/out)
;;          ("H-z"   . toggle-zoom-frame)
;;          ("s-<f1>" . toggle-zoom-frame))
;;   :config
;;   (setq frame-zoom-font-difference 10))

Computer-specific settings

Load some computer-specific settings, such as the name and and email address. The way the settings are loaded is based off of Magnar Sveen’s config.

In my case, the computers I use usually use the same username (my name, go figure), so instead of basing the specific settings from the username, I use the hostname. The shell command hostname -s gets the hostname for the computer without any “domain information,” such as the “.local” suffix.

Not using this right now.

;; (require 'subr-x) ;; #'string-trim
;; (defvar fade/user-settings-dir nil
;;   "The directory with user-specific Emacs settings for this
;;   user.")

;; ;; Settings for currently logged in user
;; (setq fade/user-settings-dir
;;       (concat user-emacs-directory
;;               "users/"
;;               (string-trim (shell-command-to-string "hostname -s"))))
;; (add-to-list 'load-path fade/user-settings-dir)

;; ;; Load settings specific for the current user
;; (when (file-exists-p fade/user-settings-dir)
;;   (mapc 'load (directory-files fade/user-settings-dir nil "^[^#].*el$")))

Languages

Generically useful programming utilities

(use-package yatemplate
  :straight t)   

C/Java

I don’t like the default way that Emacs handles indentation. For instance,

int main(int argc, char *argv[])
{
  /* What's with the brace alignment? */
  if (check)
    {
    }
  return 0;
}
switch (number)
    {
    case 1:
        doStuff();
        break;
    case 2:
        doStuff();
        break;
    default:
        break;
    }

Luckily, I can modify the way Emacs formats code with this configuration.

(defun my-c-mode-hook ()
  (setq c-basic-offset 4)
  (c-set-offset 'substatement-open 0)   ; Curly braces alignment
  (c-set-offset 'case-label 4))         ; Switch case statements alignment

(add-hook 'c-mode-hook 'my-c-mode-hook)
(add-hook 'java-mode-hook 'my-c-mode-hook)

Rust

(use-package rust-mode
  :straight t
  :defer t)

CSV mode

(use-package csv-mode
  :ensure t)

Extempore mode

Extempore is a scheme defined for live performance programming. Leaving this stub here for now.

;; (use-package extempore-mode
;;   :ensure t
;;   :config
;;   (setq extempore-path "/usr/bin/extempore"))

Common Lisp

SLY

The jury has returned. Sly is superior to Slime.

(use-package sly
  :load-path "~/SourceCode/lisp/sly"
  :straight t
  :defer t
  :commands sly
  :bind ("C-c M-o" . sly-mrepl-clear-repl)
  :init
  (progn
    (setq sly-lisp-implementations
          '((sbcl ("/usr/local/bin/sbcl" "--dynamic-space-size" "2500"))
            (ccl ("/usr/bin/ros" "-L" "ccl-bin" "run"))
            (ccl ("/usr/bin/ccl"))
            (abcl ("/usr/local/src/abcl/abcl"))
            (clisp ("/usr/bin/clisp"))
            (ecl ("/usr/local/bin/ecl"))
            (decl ("/usr/bin/ecl"))
            (clojure ("/usr/bin/clojure"))))

    (setq sly-kill-without-query-p t
          sly-net-coding-system 'utf-8-unix
          sly-complete-symbol*-fancy t
          common-lisp-hyperspec "~/SourceCode/lisp/HyperSpec"))

  :config
  (progn
    (require 'sly-autoloads)))

(use-package sly-asdf
  ;; :load-path "~/SourceCode/lisp/sly-asdf"
  :straight t
  :after sly)

(use-package sly-macrostep
  :straight t
  :after sly)

(use-package sly-named-readtables
  :straight t
  :after sly)

(use-package sly-repl-ansi-color
  :straight t
  :after sly)

(use-package sly-quicklisp
  :straight t
  :after sly)

Paredit

I spend almost all of my time in emacs writing common lisp code, and in that endeavour, Paredit is the single most useful package in my configuration. It allows me to treat code as structure, moving forms in their entirety. It also ensures that the famous parenthesis are always balanced, and that I usually only have to type the opening 50% of them. This mode is useful in all programming languages for the paren matching features, but it is indespensible if you write any lisp dialect regularly.

(use-package paredit
  :straight t
  ;; :diminish paredit-mode
  :config
  (progn
    (autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
    (add-hook 'emacs-lisp-mode-hook       #'enable-paredit-mode)
    (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
    (add-hook 'ielm-mode-hook             #'enable-paredit-mode)
    (add-hook 'lisp-mode-hook             #'enable-paredit-mode)
    (add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
    (add-hook 'scheme-mode-hook           #'enable-paredit-mode)
    ;; (add-hook 'slime-repl-mode-hook       #'enable-paredit-mode)
    (add-hook 'sly-mrepl-mode-hook        #'enable-paredit-mode)
    ;; (add-hook 'slime-mode-hook            #'enable-paredit-mode)
    ;; (add-hook 'clojure-mode-hook          #'enable-paredit-mode)
    ;; (add-hook 'cider-repl-mode-hook       #'enable-paredit-mode)
    ))

Haskell

At the moment, we’re only really investigating Haskell in conjunction with the “Integrated Haskell Platform”, which itself carries a lot of dependency baggage. At any rate, we need to be able to edit haskell with at least the minimum viable editing facilities…

(use-package dante
  :straight t)

(use-package direnv
  :straight t)

(use-package attrap
  :straight t)

Shen

(use-package shen-mode
  :straight t
  :ensure t)

Hashicorp Configuration Language

(use-package hcl-mode
  :defer t
  :straight t)

(use-package terraform-mode
  :defer t
  :straight t
  :after hcl-mode
  :config
  (add-hook 'terraform-mode-hook #'terraform-format-on-save-mode)
  :custom
  '(terraform-indent-level 2))

(use-package terraform-doc
  :defer t
  :straight t
  :after terraform-mode
  )

JavaScript

(use-package js2-mode
  :ensure t
  :init
  (setq js-basic-indent 2)
  (setq-default ;; js2-basic-indent 2
                ;; js2-basic-offset 2
                ;; js2-auto-indent-p t
                ;; js2-cleanup-whitespace t
                ;; js2-enter-indents-newline t
                ;; js2-indent-on-enter-key t
                js2-global-externs (list "window" "module" "require" "buster" "sinon" "assert" "refute" "setTimeout" "clearTimeout" "setInterval" "clearInterval" "location" "__dirname" "console" "JSON" "jQuery" "$"))

  (add-hook 'js2-mode-hook
            (lambda ()
              (push '("function" . ) prettify-symbols-alist)))

  (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
  :custom
  (js2-basic-indent 2)
  (js2-basic-offset 2)
  (js2-auto-indent-p t)
  (js2-cleanup-whitespace t)
  (js2-enter-indents-newline t)
  (js2-indent-on-enter-key t))

Color defined variables with color-identifiers-mode:

(use-package color-identifiers-mode
    :ensure t
    :init
      (add-hook 'js2-mode-hook 'color-identifiers-mode))

While editing mode for JavaScript is baked into Emacs, it is quite important to have flycheck validate the source based on jshint, and eslint. Let’s prefer eslint:

(add-hook 'js2-mode-hook
          (lambda () (flycheck-select-checker "javascript-eslint")))

Refactoring JavaScript

The js2-refactor mode should start with C-c . and then a two-letter mnemonic shortcut.

  • ef is extract-function: Extracts the marked expressions out into a new named function.
  • em is extract-method: Extracts the marked expressions out into a new named method in an object literal.
  • ip is introduce-parameter: Changes the marked expression to a parameter in a local function.
  • lp is localize-parameter: Changes a parameter to a local var in a local function.
  • eo is expand-object: Converts a one line object literal to multiline.
  • co is contract-object: Converts a multiline object literal to one line.
  • eu is expand-function: Converts a one line function to multiline (expecting semicolons as statement delimiters).
  • cu is contract-function: Converts a multiline function to one line (expecting semicolons as statement delimiters).
  • ea is expand-array: Converts a one line array to multiline.
  • ca is contract-array: Converts a multiline array to one line.
  • wi is wrap-buffer-in-iife: Wraps the entire buffer in an immediately invoked function expression
  • ig is inject-global-in-iife: Creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression
  • ag is add-to-globals-annotation: Creates a /*global */ annotation if it is missing, and adds the var at point to it.
  • ev is extract-var: Takes a marked expression and replaces it with a var.
  • iv is inline-var: Replaces all instances of a variable with its initial value.
  • rv is rename-var: Renames the variable on point and all occurrences in its lexical scope.
  • vt is var-to-this: Changes local var a to be this.a instead.
  • ao is arguments-to-object: Replaces arguments to a function call with an object literal of named arguments. Requires yasnippets.
  • 3i is ternary-to-if: Converts ternary operator to if-statement.
  • sv is split-var-declaration: Splits a var with multiple vars declared, into several var statements.
  • uw is unwrap: Replaces the parent statement with the selected region.
(use-package js2-refactor
  :ensure t
  :init   (add-hook 'js2-mode-hook 'js2-refactor-mode)
  :config (js2r-add-keybindings-with-prefix "C-c ."))

Skewer

I also configure Skewer for my HTML and CSS files, we need to do the same for JavaScript:

(use-package skewer-mode
   :ensure t
   :init (add-hook 'js2-mode-hook 'skewer-mode))

Kick things off with run-skewer, and then:

C-x C-e
`skewer-eval-last-expression’
C-M-x
`skewer-eval-defun’
C-c C-k
`skewer-load-buffer’

Nim

(use-package nim-mode
  :ensure t)

Python

Integrates with IPython., using elpy jedi, and virtualenvwrapper.

(use-package elpy
  :ensure t
  :config
  (setq elpy-rpc-backend "jedi")
  (setq python-shell-interpreter "ipython"
        python-shell-interpreter-args "-i --simple-prompt")
  (elpy-enable))

(use-package jedi
  :ensure t
  :init
  (add-hook 'python-mode-hook 'jedi:setup)
  :config
  (local-set-key (kbd "M-.") 'jedi:goto-definition)
  (local-set-key (kbd "M-,") 'jedi:goto-definition-pop-marker)
  (local-set-key (kbd "M-?") 'jedi:show-doc)
  (local-set-key (kbd "M-/") 'jedi:get-in-function-call)
  (setq jedi:complete-on-dot t))

(use-package company-jedi
  :ensure jedi
  :ensure t
  :config
  (add-to-list 'company-backends 'company-jedi))

(use-package jinja2-mode
  :ensure t)

Virtualenvwrapper

(use-package virtualenvwrapper
  :ensure t
  :defer t
  :config
  (setq venv-location "~/.virtualenvs"))

Racket

Not using Racket much any more. When I do, drracket is sufficient.

;; (use-package racket-mode
;;   :ensure t
;;   :commands racket-mode
;;   :config
;;   (setq racket-smart-open-bracket-enable t))

;; (use-package geiser
;;   :ensure t
;;   :defer t
;;   :config
;;   (setq geiser-default-implementation '(racket)))

YAML mode

(use-package yaml-mode
  :ensure t
  :defer t
  :config
  (add-hook 'yaml-mode-hook '(lambda () (ansible 1))))

Ansible

(use-package ansible
  :ensure t
  ;; :load-path "~/SourceCode/lisp/emacs_stuff/emacs-ansible"
  :defer t
  :config
  (use-package ansible-doc
  :ensure t
  :defer t)
  (use-package ansible-vault
    :ensure t
    :defer t)
  (use-package company-ansible
    :ensure t
    :defer t))

Typescript mode

;; (use-package typescript-mode
;;   :ensure t
;;   :defer t)

Webmode

(use-package web-mode
  :ensure t)

Highlight line containing the point

(when window-system (add-hook 'prog-mode-hook 'hl-line-mode))

(defadvice hl-line-mode (after
                         dino-advise-hl-line-mode
                         activate compile)
  (set-face-attribute 'hl-line nil
                      :inherit nil
                      :background (face-background 'highlight))
  (set-face-background hl-line-face "#191970"))

Rainbow

Mostly useful if you are into web development or game development. Every time emacs encounters a hexadecimal code that resembles a color, it will automatically highlight it in the appropriate color. This is a lot cooler than you may think.

(use-package rainbow-mode
  :ensure t
  :diminish rainbow-mode
  ;; apply this mode to all programming modes.
  :init
  (add-hook 'prog-mode-hook 'rainbow-mode))

Modeline

The modeline is the heart of emacs, it offers information at all times, it’s persistent and verbose enough to gain a full understanding of modes and states you are in.

One modeline-related setting that is missing and is instead placed at the bottom is diminish.

All the icons!

(use-package all-the-icons
  :straight t)

Spaceline!

I may not use spacemacs, since I do not like evil-mode and find spacemacs incredibly bloated and slow, however it would be stupid not to acknowledge the best parts about it, the theme and their modified powerline setup.

This enables spaceline, it looks better and works very well with my theme of choice.

;; (when window-system
;;     (progn
;;       (use-package spaceline
;;         :ensure t
;;         :config
;;         ;; (mis)using use-package here to put config in an envelope.
;;         (use-package spaceline-config
;;           :config
;;           (setq spaceline-buffer-encoding-abbrev-p t)
;;           (setq spaceline-line-column-p t)
;;           (setq spaceline-line-p t)

;;           (spaceline-toggle-flycheck-info-off)
;;           (spaceline-toggle-flycheck-error-off)
;;           (spaceline-toggle-flycheck-warning-off)
;;           (spaceline-toggle-version-control-on)

;;           (spaceline-spacemacs-theme)))

;;       (use-package spaceline-all-the-icons
;;         :ensure t
;;         :after spaceline
;;         :config
;;         (spaceline-all-the-icons-theme))))

Telephone Line

;; (use-package telephone-line
;;   :ensure t
;;   :config
;;   (setf telephone-line-primary-left-separator 'telephone-line-cubed-left
;;         telephone-line-secondary-left-separator 'telephone-line-cubed-hollow-left
;;         telephone-line-primary-right-separator 'telephone-line-cubed-right
;;         telephone-line-secondary-right-separator 'telephone-line-cubed-hollow-right)
;;   (setf telephone-line-height 24
;;         telephone-line-evil-use-short-tag t)
;;   ;; actually use it.
;;   (telephone-line-mode 1))

No separator!

(setq powerline-default-separator nil)

Cursor position

Show the current line and column for your cursor. We are not going to have relative-linum-mode in every major mode, so this is useful.

;; (setq line-number-mode t)
;; (setq column-number-mode t)

Clock

If you prefer the 12hr-format, change the variable to nil instead of t.

Time format

(setq display-time-24hr-format t)
(setq display-time-format "%H:%M - %d %B %Y")
(display-time-mode 1)

Theme

Autothemer

;; (use-package autothemer
;;   :ensure t)

Emacs’ startup screen is naf

(setq inhibit-startup-message t)

Colours On Terminal

custom colour themes generally enhance my experience of writing inside emacs, but when that theme is applied to an instance running inside a terminal, the effect is really just terrible. This mode kind of approximates the effect of a graphical emacs frame, in a text console.

(use-package color-theme-approximate
  :ensure t
  :config
  (unless (display-graphic-p)
    (autoload 'color-theme-approximate-on "color-theme-approximate")
    (color-theme-approximate-on)))

Cursor tomfoolery

A fun hack that is in practice unusable.

;; if this is set here, it is overwritten by the colour theme.
;; (set-cursor-color "yellow")

;; (when (display-graphic-p) 
;;   (progn
;;     (defvar blink-cursor-colors (list
;;                                  "dark slate blue"
;;                                  "medium slate blue"
;;                                  "light slate blue"
;;                                  "steel blue"
;;                                  "royal blue"
;;                                  "light blue"
;;                                  "cyan"
;;                                  "cyan1"
;;                                  "cyan2"
;;                                  "cyan3"
;;                                  "cyan4"
;;                                  "spring green"
;;                                  "yellow"
;;                                  "orange"
;;                                  "red"
;;                                  "hot pink")
;;       "On each blink the cursor will cycle to the next color in this list.")
  
;;     (setq blink-cursor-count 0)
;;     (setq blink-cursor-interval 0.3)
;;     (defun blink-cursor-timer-function ()
;;       "Zarza wrote this cyberpunk variant of timer `blink-cursor-timer'. 
;;      Warning: overwrites original version in `frame.el'.

;;      This one changes the cursor color on each blink. Define colors in `blink-cursor-colors'."

;;       (when (not (internal-show-cursor-p))
;;         (when (>= blink-cursor-count (length blink-cursor-colors))
;;           (setq blink-cursor-count 0))
;;         (set-cursor-color (nth blink-cursor-count blink-cursor-colors))
;;         (setq blink-cursor-count (+ 1 blink-cursor-count)))
;;       (internal-show-cursor nil (not (internal-show-cursor-p))))))

DeepSky Theme

Load the appropriate theme, and a utility for arbitrarily loading others.

(progn
  ;; on the terminal, the theme situation needs more attention.
  (message "Loading DeepSky theme... ")
  (load-theme 'deepsky-modus-fade t)
  (message "Configuring mode-line appearance...")
  (set-face-attribute `mode-line nil
                      :box nil)
  (message "Setting cursor colour...")
  (set-cursor-color "yellow"))
(defun switch-theme (theme)
  "Disables any currently active themes and loads THEME."
  ;; This interactive call is taken from `load-theme'
  (interactive
   (list
    (intern (completing-read "Load custom theme: "
                             (mapc 'symbol-name
                                   (custom-available-themes))))))
  (let ((enabled-themes custom-enabled-themes))
    (mapc #'disable-theme custom-enabled-themes)
    (load-theme theme t)))

(defun disable-active-themes ()
  "Disables any currently active themes listed in `custom-enabled-themes'."
  (interactive)
  (mapc #'disable-theme custom-enabled-themes))

(bind-key "s-<f12>" 'switch-theme)
(bind-key "s-<f11>" 'disable-active-themes)

Font

And here’s how we tell Emacs which font we want.

(if window-system
    (progn
      (add-to-list 'default-frame-alist '(font . "Envy Code R"))
      ;; (set-face-attribute 'variable-pitch nil :font "Cantarell" :height 120 :weight 'regular)
      (set-face-attribute 'default nil :font "Envy Code R" :height 120)
      (set-face-attribute 'fixed-pitch nil :font "Envy Code R-11")))

;; (set-face-attribute 'fixed-pitch nil :font "Fira Code Retina" :height 120)

Misc

Display Time

When displaying the time with display-time-mode, I don’t care about the load average.

(setq display-time-default-load-average nil)

Swap Buffer Windows

(use-package buffer-move
  :ensure t
  :config
  (progn
    (global-set-key (kbd "<C-M-s-up>")     'buf-move-up)
    (global-set-key (kbd "<C-M-s-down>")   'buf-move-down)
    (global-set-key (kbd "<C-M-s-left>")   'buf-move-left)
    (global-set-key (kbd "<C-M-s-right>")  'buf-move-right)))

Display Battery Mode

See the documentation for battery-mode-line-format for the format characters.

;; (setq battery-mode-line-format "[%b%p%% %t]")

Docview keybindings

Convenience bindings to use doc-view with the arrow keys.

(use-package doc-view
  :commands doc-view-mode
  :config
  (define-key doc-view-mode-map (kbd "<right>") 'doc-view-next-page)
  (define-key doc-view-mode-map (kbd "<left>") 'doc-view-previous-page))

OS X scrolling

(setq mouse-wheel-scroll-amount (quote (0.01)))

Emacsclient

(use-package server
  :config
  (server-mode t))