Skip to content

Latest commit

 

History

History
2605 lines (2398 loc) · 88.4 KB

emacs.org

File metadata and controls

2605 lines (2398 loc) · 88.4 KB

~/dotfiles/emacs.org

emacs.org

What is this?

This is my emacs configuration in org-mode. It’s loaded using (org-babel-load-file "~/dotfiles/emacs.org") from my init.el. It contains a lot of things inspired (stolen) from places around the on web such as:

It is divided into two major parts:

  1. Emacs - settings and packages that change how emacs works/looks/etc
  2. Languages - setup for programming languages

How to Add/Modify

To add a code block, type <el and press tab, this adds an emacs-lisp code block. To modify a code block, press C-c ' to open an emacs-lisp buffer and hack away. Use SPC m e b to eval-buffer and implement the changes. Save or clear the changes with evil’s :w, :x, or :q.

Emacs

Lexical binding

Lexical binding is supposed to make stuff faster

;;; -*- lexical-binding: t -*-

Personal Information

Who am I?

(setq user-full-name "Kevin Pavao"
      user-mail-address "[email protected]")

Package Setup

Set up straight.el instead of the built-in package.el to manage my packages.

Using straight because:

  • it allows me to exactly reproduce my config on other machines, it creates a default.el file that acts as a lockfile for package versions
  • it gets the latest package versions from git
  • it’s integated well with use-package
  • I can edit package code if I want to, and straight will rebuild the package
  • lots of other stuff, the README is quite good

Use the develop branch, this needs to be set before the bootstrap code below.

(setq straight-repository-branch "develop")

Bootstrap code from the straight.el README

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

From the straight docs:

By setting the variable straight-cache-autoloads to a non-nil value, you can cause straight.el to cache the autoloads of all used packages in a single file on disk, and load them from there instead of from the individual package files if they are still up to date. This reduces the number of disk IO operations during startup from O(number of packages) to O(1), so it should improve performance. No other configuration should be necessary to make this work; however, you may wish to call straight-prune-build occasionally, since otherwise this cache file may grow quite large over time.

(setq straight-cache-autoloads t)

Automatically enable :straight t, which is basically the same as :ensure t but for straight

(setq straight-use-package-by-default t)

install use-package and related packages

(straight-use-package 'use-package)
(use-package diminish) ;; for :diminish
(use-package bind-key) ;; for :bind

Install ensure-system-package

(use-package use-package-ensure-system-package)

Garbage Collection

Modify garbage collection. This is supposed to speed things up a bit.

(use-package gcmh
  :hook (after-init . gcmh-mode))

Increase the amount of data which Emacs reads from the process. Again the emacs default is too low 4k considering that the some of the language server responses are in 800k - 3M range.

(setq read-process-output-max (* 1024 1024)) ;; 1mb

Core

Things that modify or replace the core functionality of Emacs, or are needed by the rest of the config.

Saner Defaults

Settings for things that are defined in the C source code, so we use emacs as the package.

(use-package emacs
  :straight nil
  :init
  ;; answer with y/n instead of typing out yes/no
  (defalias 'yes-or-no-p 'y-or-n-p)
  :custom
  ;; load new source files instead of stale elisp bytecode
  (load-prefer-newer t)
  ;; allow emacs to be any size, removes black bars
  (frame-resize-pixelwise t))

Refresh (revert in Emacs’ terms) buffers when files change on disk. Makes sure to update any version control info that changes also.

(use-package autorevert
  :straight nil
  :custom
  (global-revert-check-vc-info t)
  :config
  (global-auto-revert-mode +1))

Use utf-8 for everything.

(use-package mule
  :straight nil
  :config
  (prefer-coding-system 'utf-8)
  (set-default-coding-systems 'utf-8)
  (set-language-environment "UTF-8"))

Emacs likes to create lots of extra files for things, these settings prevent that. Also, create a newline at the end of the file on save.

(use-package files
  :straight nil
  :custom
  (make-backup-files nil)    ;; stop creating backup~ files
  (auto-save-default nil)    ;; stop creating #autosave# files
  (create-lockfiles nil)     ;; stop creating .# files
  (require-final-newline t)) ;; auto add newline at the end of file

Use the system clipboard for killing/yanking (copying/pasting) and display column information in the modeline.

(use-package simple
  :straight nil
  :custom
  ;; killing and yanking uses the system clipboard
  (save-interprogram-paste-before-kill t)
  :config
  ;; display column info in the modeline
  (column-number-mode +1))

When the lines in a file are so long that performance could suffer to an unacceptable degree, we say “so long” to the slow modes and options enabled in that buffer, and invoke something much more basic in their place.

(use-package so-long
  :straight nil
  :config
  (global-so-long-mode +1))

When you visit a file, point goes to the last place where it was when you previously visited the same file.

(use-package saveplace
  :straight nil
  :config
  (save-place-mode +1))

Create ~/.emacs.d/etc/ and ~/.emacs.d/var/ to store files and data used by Emacs packages.

(use-package no-littering
  :init
  (setq no-littering-etc-directory
        (expand-file-name "etc/" user-emacs-directory))
  (setq no-littering-var-directory
        (expand-file-name "var/" user-emacs-directory)))

show-paren-mode highlights matching parentheses. The default delay is annoying so change it to 0.

(use-package paren
  :straight nil
  :custom
  (show-paren-delay 0)
  :config
  (show-paren-mode +1))

Keys

To set up custom keys, I use a combination of:

  • general - provides a leader key and gives us an easy way to define custom keys in use-package
  • which-key - shows a list of all available keybindings, it works nicely with general, as it will show all the keybindings available after pressing SPC
  • hydra - create a “mode” (similar to how i3 does resize mode) for repeated actions

general

general.el provides a more convenient method for binding keys in emacs … Like use-package

This creates a leader, which allows you to set up custom keys after pressing a certain key

  • Keys for all modes appear after pressing SPC in normal and visual mode, or M-SPC in everything else.
  • Mode specific keys appear after pressing SPC m in normal and visual mode, or M-, in everything else.

It also adds a :general use-package keyword, so this needs to be setup before that is used anywhere.

(use-package general
  :custom
  (general-override-states '(insert emacs hybrid normal visual motion operator replace))
  :config
  (general-override-mode)
  (general-evil-setup)
  (general-create-definer my-leader-def
    :states '(normal visual insert emacs)
    :prefix "SPC"
    :non-normal-prefix "M-SPC")

  (general-create-definer my-local-leader-def
    :states '(normal visual insert emacs)
    :prefix "SPC m"
    :non-normal-prefix "M-,")

  (my-leader-def
    "c" 'comment-dwim
    "RET" 'make-frame-command
    ;; bookmarks
    "r" '(:ignore t :wk "bookmarks")
    "rm" 'bookmark-set
    "rb" 'bookmark-jump
    "rl" 'bookmark-bmenu-list
    ;; quit / restart
    "q" '(:ignore t :wk "quit / restart")
    "qq" 'save-buffers-kill-terminal
    "qr" 'restart-emacs))

which-key

(use-package which-key
  :custom
  (which-key-idle-delay 0)
  :config
  (which-key-mode +1)
  (which-key-setup-minibuffer)
  (which-key-setup-side-window-bottom))

hydra

Add a zoom hydra from hydras github and a straight hydra from its github.

(use-package hydra
  :defer t
  :general
  (my-leader-def
   "P" '(hydra-straight-helper/body :wk "pkgs"))
  :config
  (defhydra hydra-zoom (global-map "<f5>")
    "zoom"
    ("g" text-scale-increase "in")
    ("l" text-scale-decrease "out")
    ("r" (text-scale-set 0) "reset")
    ("0" (text-scale-set 0) :bind nil :exit t))
  (defhydra hydra-straight-helper (:hint nil :color green)

    "
_c_heck all       |_f_etch all     |_m_erge all      |_n_ormalize all   |p_u_sh all
_C_heck package   |_F_etch package |_M_erge package  |_N_ormlize package|p_U_sh package
----------------^^+--------------^^+---------------^^+----------------^^+------------||_q_uit||
_r_ebuild all     |_p_ull all      |_v_ersions freeze|_w_atcher start   |_g_et recipe
_R_ebuild package |_P_ull package  |_V_ersions thaw  |_W_atcher quit    |prun_e_ build"
    ("c" straight-check-all)
    ("C" straight-check-package)
    ("r" straight-rebuild-all)
    ("R" straight-rebuild-package)
    ("f" straight-fetch-all)
    ("F" straight-fetch-package)
    ("p" straight-pull-all)
    ("P" straight-pull-package)
    ("m" straight-merge-all)
    ("M" straight-merge-package)
    ("n" straight-normalize-all)
    ("N" straight-normalize-package)
    ("u" straight-push-all)
    ("U" straight-push-package)
    ("v" straight-freeze-versions)
    ("V" straight-thaw-versions)
    ("w" straight-watcher-start)
    ("W" straight-watcher-quit)
    ("g" straight-get-recipe)
    ("e" straight-prune-build)
    ("q" nil)))

Vim Emulation

This allows you to use emacs keybindings while in evil’s insert mode. from https://stackoverflow.com/questions/25542097/emacs-evil-mode-how-to-change-insert-state-to-emacs-state-automatically

(defun my-emacs-in-normal-mode ()
  (setq evil-insert-state-map (make-sparse-keymap))
  (define-key evil-insert-state-map (kbd "<escape>") 'evil-normal-state))

Evil mode is vim in emacs!

(use-package evil
  :custom
  (evil-want-keybinding nil)  ;; evil-collection assumes this
  (evil-undo-system 'undo-fu)
  :config
  (evil-mode +1)
  (my-emacs-in-normal-mode))

Use evil bindings in various modes.

(use-package evil-collection
  :after evil
  :config
  (evil-collection-init))

surround.vim emulation.

(use-package evil-surround
  :after evil
  :config
  (global-evil-surround-mode 1))

vim-commentary emulation

(use-package evil-commentary
  :config
  (evil-commentary-mode 1))

Jump around a file with a few keystrokes.

(use-package evil-avy
  :after evil
  :general
  (my-leader-def
    "jgg" 'evil-avy-goto-word-0
    "jgj" 'avy-goto-word-0-below
    "jgk" 'avy-goto-word-0-above))

(use-package evil-easymotion
  :after evil
  :general
  (my-leader-def
    "j" '(:ignore t :wk "easymotion")
    "jj" 'evilem-motion-next-line
    "jk" 'evilem-motion-previous-line
    "jw" 'evilem-motion-forward-word-begin
    "jb" 'evilem-motion-backward-word-begin
    "je" 'evilem-motion-forward-word-end
    "jW" 'evilem-motion-forward-WORD-begin
    "jE" 'evilem-motion-forward-WORD-end)
  :init
  (evilem-default-keybindings "S-SPC"))

Show tildes in the fringe on empty lines.

;; (use-package vi-tilde-fringe
;;   :config
;;   (global-vi-tilde-fringe-mode 1))

Mouse

Better mouse scrolling - the default scrolling is too quick.

(setq scroll-margin 10
      scroll-step 1
      next-line-add-newlines nil
      scroll-conservatively 10000
      scroll-preserve-screen-position 1
      mouse-wheel-follow-mouse 't
      mouse-wheel-scroll-amount '(1 ((shift) . 1)))

Ivy / Counsel / Swiper

Ivy is a generic completion mechanism for Emacs

(use-package ivy
  :demand t
  :general
  ("<f6>" 'ivy-resume)
  :custom
  (ivy-use-virtual-buffers t)
  (enable-recursive-minibuffers t)
  (ivy-count-format "(%d/%d) ")
  (ivy-height 20)
  :config
  (ivy-mode 1))

Counsel, a collection of Ivy-enhanced versions of common Emacs commands.

(use-package counsel
  :after ivy
  :demand t
  :general
  ("M-x" 'counsel-M-x)
  ("C-x C-f" 'counsel-find-file)
  ("<f1> f" 'counsel-describe-function)
  ("<f1> v" 'counsel-describe-variable)
  ("<f1> l" 'counsel-find-library)
  ("<f2> i" 'counsel-info-lookup-symbol)
  ("<f2> u" 'counsel-unicode-char)
  ("C-c g" 'counsel-git)
  ("C-c j" 'counsel-git-grep)
  ("C-c k" 'counsel-rg)
  ("C-x l" 'counsel-locate)
  ("C-S-r" 'counsel-expression-history)
  (my-leader-def
    "f" 'counsel-find-file
    "x" 'counsel-M-x)
  :config
  ;; use ripgrep for counsel-git-grep
  (setq counsel-git-cmd "rg --files")
  (setq counsel-rg-base-command
        "rg -i -M 120 --no-heading --line-number --color never %s ."))
(use-package counsel-etags
  :after counsel)

Make ivy look a bit nicer

(use-package ivy-rich
  :after (ivy counsel)
  :config
  (ivy-rich-mode 1)
  (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line))

Sort results with prescient

;; (use-package prescient
;;   :after counsel)

;; (use-package ivy-prescient
;;   :after prescient
;;   :custom
;;   (ivy-prescient-sort-commands t)
;;   (ivy-prescient-retain-classic-highlighting t)
;;   (ivy-prescient-enable-filtering t)
;;   (ivy-prescient-enable-sorting t)
;;   :config
;;   (ivy-prescient-mode +1))

Search / Replace

Replace keybindings for emacs search and evil search with swiper.

(use-package swiper
  :after ivy
  :general
  ("C-s" 'swiper)
  (evil-normal-state-map "/" 'swiper))

Add find and replace info to the modeline.

(use-package anzu
  :config
  (global-anzu-mode)
  (global-set-key [remap query-replace] 'anzu-query-replace)
  (global-set-key [remap query-replace-regexp] 'anzu-query-replace-regexp))

Undo

Using this for evil undo/redo.

(use-package undo-fu)

Text Editing

multiple cursors

(use-package multiple-cursors
  :defer t
  :general
  (my-leader-def
    "v" 'mc/edit-lines))

iedit

Iedit - Edit multiple regions in the same way simultaneously

Using the default keybinding of C-;.

  • All occurrences of a symbol, string or a region in the buffer are highlighted corresponding to the thing under the point, current mark and prefix argument. Refer to the document of iedit-mode for details.
  • Edit one of the occurrences The change is applied to other occurrences simultaneously.
  • Finish - by pressing C-; again
(use-package iedit)

Startup

Display the scratch buffer when starting up, use org-mode for the scratch buffer, and remove the default message.

(use-package emacs
  :straight nil
  :custom
  (inhibit-startup-screen t)
  (initial-major-mode 'org-mode)
  (initial-scratch-message nil))

See how long startup takes with M-x esup

(use-package esup
  :commands (esup))

Custom File

Use a separate custom file to remove the autogenerated code from init.el.

(use-package cus-edit
  :straight nil
  :custom
  (custom-file (expand-file-name "custom.el" user-emacs-directory))
  :config
  (if (file-exists-p custom-file)
      (load-file custom-file)))

Look and Feel

Change defaults

Use a non-blinking cursor for a more zen-like experience.

(use-package frame
  :straight nil
  :config
  (blink-cursor-mode -1)) ;; dont blink the cursor

Theme

Theme I’m currently using

Modus themes are WCAG AAA compliant, easy on the eyes, and super customizeable.

(use-package modus-themes
  :init
  (modus-themes-load-themes)
  :custom
  (modus-themes-bold-constructs t)
  (modus-themes-slanted-constructs t)
  (modus-themes-intense-paren-match t)
  (modus-themes-completions 'opinionated)
  ;; org specific settings
  (modus-themes-org-blocks 'grayscale)
  (modus-themes-headings '((t . rainbow)))
  (modus-themes-scale-headings t)
  :config
  (modus-themes-load-vivendi))

Font

Font I’m currently using

(add-to-list 'default-frame-alist '(font . "Iosevka-12"))

Modeline

doom modeline

You need to run M-x all-the-icons-install-fonts to get the fancy fonts in the modeline

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

column-number-mode displays the cursors current line on the modeline

(use-package doom-modeline
  :demand t
  :preface
  (defun my-doom-modeline-setup ()
    (column-number-mode +1)
    (doom-modeline-mode +1))
  :init (my-doom-modeline-setup)
  :custom
  (doom-modeline-vcs-max-length 50)
  (doom-modeline-buffer-file-name-style 'truncate-upto-project))

rainbow delimiters

Add rainbow delimiters in all programming language modes

(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))

Custom Functions

what-minor-mode

list minor modes

(defun my-active-minor-modes ()
  "Get a list of active minor-mode symbols."
  (delq nil
        (mapcar
         (lambda (x)
           (let ((car-x (car x)))
             (when (and (symbolp car-x) (symbol-value car-x))
               x)))
         minor-mode-alist)))

(defun my/what-minor-mode (mode)
  "Get information on an active minor mode. Use `describe-minor-mode' for a
selection of all minor-modes, active or not."
  (interactive
   (list (completing-read "Minor mode: "
                          (my-active-minor-modes))))
  (describe-minor-mode-from-symbol
   (cl-typecase mode
     (string (intern mode))
     (symbol mode)
     (t (error "Expected a symbol/string, got a %s" (type-of mode))))))

Add a key for it:

(my-leader-def
  "l" 'my/what-minor-mode)

Window and Buffer Management

Keys

(my-leader-def
  "b" '(:ignore t :wk "buffers")
  "bb" 'switch-to-buffer
  "bk" 'kill-buffer
  "wo" 'split-window-horizontally
  "wu" 'split-window-vertically
  "wd" 'delete-window)

eyebrowse

Eyebrowse provides a way to manage workspaces like tiling window managers.

(use-package eyebrowse
  :general
  (my-leader-def
    "w." 'eyebrowse-switch-to-window-config
    "w," 'eyebrowse-rename-window-config
    "w1" 'eyebrowse-switch-to-window-config-1
    "w2" 'eyebrowse-switch-to-window-config-2
    "w3" 'eyebrowse-switch-to-window-config-3
    "w4" 'eyebrowse-switch-to-window-config-4
    "w4" 'eyebrowse-switch-to-window-config-4
    "w5" 'eyebrowse-switch-to-window-config-5
    "w6" 'eyebrowse-switch-to-window-config-6
    "w7" 'eyebrowse-switch-to-window-config-7
    "w8" 'eyebrowse-switch-to-window-config-8
    "w9" 'eyebrowse-switch-to-window-config-9
    "w0" 'eyebrowse-switch-to-window-config-0)
  :config
  (eyebrowse-mode t))

windmove

Windmove provides a way to move around emacs windows.

Default keybindings are: S-arrowkey (e.g. S-Left) to move around

(use-package windmove
  :straight nil
  :general
  (my-leader-def
    "w" '(:ignore t :wk "windows")
    "wh" 'windmove-left
    "wj" 'windmove-down
    "wk" 'windmove-up
    "wl" 'windmove-right)
  :config
  (windmove-default-keybindings))

Project and File Management

dired

Some tips for using dired:

  • Toggle dired-details-mode with (
  • Toggle writeable mode with C-x C-q
(use-package dired
  :straight nil
  :defer t
  :hook (dired-mode . dired-hide-details-mode)
  :general
  (my-leader-def
    "d" 'dired))

;; Colourful columns.
(use-package diredfl
  :after dired
  :config
  (diredfl-global-mode +1))

Press C-( to get git info

(use-package dired-git-info
    :bind (:map dired-mode-map
                ("C-(" . dired-git-info-mode)))

projectile

Projectile allows some nice things for projects, such as searching for files, managing buffers, etc.

(use-package projectile
  :config
  (projectile-mode +1))

(use-package counsel-projectile
  :after (counsel projectile)
  :general
  (my-leader-def
    "p" '(:ignore t :wk "projects")
    "pf" 'counsel-projectile-find-file
    "pd" 'counsel-projectile-find-dir
    "pb" 'counsel-projectile-switch-to-buffer
    "pp" 'counsel-projectile-switch-project
    "pg" 'counsel-projectile-rg) ;;ripgrep
  :config
  (counsel-projectile-mode +1))

treemacs

A file tree.

(use-package treemacs
  :defer t
  :general ([f8] 'treemacs))

(use-package treemacs-evil
  :after (evil treemacs))

(use-package treemacs-projectile
  :after (projectile treemacs))

(use-package treemacs-magit
  :after (treemacs))

Org Mode

Setup org-mode. Most of these are functions that will get called in either the :hook or :config part of the use-package setup for org.

Look and Feel

Settings to make org mode look a bit nicer.

A lot of this stuff is from:

The prettify hook:

  • turn-on-visual-line-mode for visual word wrap
  • variable-pitch-mode to use a non monospaced font
  • org-bullets provides good looking bullets for headers
(defun my-org-prettify-hook ()
  (turn-on-visual-line-mode)
  (variable-pitch-mode +1)
  (org-bullets-mode +1))

(use-package org-bullets)

Various settings to make things look nicer:

  • org-startup-indented starts up org-indent-mode
  • org-src-fontify-natively turns on syntax highlighting for #+SRC blocks
  • org-hide-emphasis-markers hides the things that make text bold, italics, monospaced, etc.
  • org-fontify-whole-heading-line is useful when setting background colors for org-level-* faces
  • org-fontify-done-headline make DONE headlines look nicer
  • org-fontify-quote-and-verse-blocks makes quotes and verses italic
  • line-spacing to give the text a bit more breathing room
  • the font-lock part is a regex that uses a unicode bullet for lists (lines that start with “- ” or “+ “)
    • this is only for the first level of lists, other levels arent replaced
(defun my-org-prettify-settings ()
  (setq org-startup-indented t
        org-src-fontify-natively t
        org-hide-emphasis-markers t
        org-fontify-whole-heading-line t
        org-fontify-done-headline t
        org-fontify-quote-and-verse-blocks t
        line-spacing 0.2)
  ;; (font-lock-add-keywords 'org-mode
  ;;                         '(("^\\([-+]\\) "
  ;;                            (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
  ;; (my-org-faces)
  )

htmlize

Provides syntax highlighting for #+SRC blocks in html exports.

Needed by pelican and nikola

(use-package htmlize
  :defer t)

Setup for TODOs

  • org-use-fast-todo-selection
    • Change the status of the todo state by pressing C-c C-c t <KEY>
    • the <KEY> is the the letter in the parens after the state (e.g. TODO(t))
  • org-todo-keywords
  • org-log-done
    • insert time/date when moved to DONE
(defun my-org-todo-setup ()
  (setq org-use-fast-todo-selection t)
  (setq org-todo-keywords
        '((sequence "TODO(t)" "NEXT(n)" "CURRENT(c)" "|" "DONE(d)")
          (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(a@/!)")))
  ;; (setq org-todo-keyword-faces
  ;;       (quote (("TODO" :foreground "#BF616A" :weight bold)
  ;;               ("NEXT" :foreground "#5E81AC" :weight bold)
  ;;               ("CURRENT" :foreground "#88C0D0" :weight bold)
  ;;               ("DONE" :foreground "#A3BE8C" :weight bold)
  ;;               ("WAITING" :foreground "#D08770" :weight bold)
  ;;               ("HOLD" :foreground "#848EAD" :weight bold)
  ;;               ("CANCELLED" :foreground "#8FBCBB" :weight bold))))
  (setq org-log-done 'time))

Structure Templates

Add structure templates, e.g. type <el TAB for #+BEGIN_SRC emacs-lisp #+END_SRC Existing templates for reference:

As of Emacs 27.1, org-tempo is required to use these.

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

Capture Templates

(use-package org-capture
  :straight nil
  :general
  (my-leader-def
    "C" 'org-capture)
  :config
  (setq org-capture-templates
        '(("t" "Todo" entry (file+headline "~/org/agenda/todo.org" "Tasks")
           "* TODO %?\n %i\n %a")
          ("s" "Standup" entry (file+olp+datetree "~/org/agenda/todo.org" "Standup")
           "* Planned\n- %?\n %i\n %a")
          ("g" "Grow Log" entry (file+olp+datetree "~/grow/grow.org" "Log")
           "* Day Xn\n** Log\n** Notes\n %?\n %i\n")))

  (defun org-hugo-new-subtree-post-capture-template ()
    "Returns `org-capture' template string for new Hugo post.
See `org-capture-templates' for more information."
    (let* ((title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title
           (fname (org-hugo-slug title)))
      (mapconcat #'identity
                 `(
                   ,(concat "* TODO " title)
                   ":PROPERTIES:"
                   ,(concat ":EXPORT_FILE_NAME: " fname)
                   ":END:"
                   "%?\n")          ;Place the cursor here finally
                 "\n")))

  (add-to-list 'org-capture-templates
               '("b"
                 "Blog Post"
                 entry
                 ;; It is assumed that below file is present in `org-directory'
                 ;; and that it has a "Blog Ideas" heading. It can even be a
                 ;; symlink pointing to the actual location of all-posts.org!
                 (file+olp "blog-posts.org" "Ideas")
                 (function org-hugo-new-subtree-post-capture-template))))

Use Package

Put it all together with use-package.

The org-src-mode-map bit in the :general block maps :x to confirm and :q to abort when editing SRC blocks.

I dont need documentation for elisp in this config, so my-disable-flycheck-for-elisp disables flycheck for it.

:custom-face is mainly the setup for variable pitch mode:

  • Set fonts for both variable and fixed pitch modes
  • org-indent is to make org-indent-mode look right, otherwise the spacing is off
  • The org-level-* stuff makes headings bigger.
  • Several things should be in fixed-pitch, such as tables so they are indented correctly
(use-package org
  :straight nil
  :general
  (org-src-mode-map
   [remap evil-save-and-close]          'org-edit-src-exit
   [remap evil-save-modified-and-close] 'org-edit-src-exit
   [remap evil-quit]                    'org-edit-src-abort)
  (my-leader-def
    "a" 'org-agenda)
  (my-local-leader-def 'org-mode-map
    "b" 'org-babel-tangle
    "t" 'org-todo)
  :gfhook
  #'my-org-prettify-hook
  ('org-src-mode-hook #'my-disable-flycheck-for-elisp)
  :preface
  (defun my-disable-flycheck-for-elisp ()
    (setq flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
  :custom-face
  (variable-pitch ((t (:family "EtBembo" :height 160 :weight normal :slant normal))))
  (fixed-pitch ((t (:family "Iosevka" :height 0.8))))
  ;; this is all handled in modus-vivendi!
  ;; (org-indent ((t (:inherit (org-hide fixed-pitch)))))
  ;; (org-document-title ((t (:foreground "#B48EAD" :weight bold :height 1.4))))
  ;; (org-level-1 ((t (:inherit outline-1 :height 1.3 :weight bold ;; :foreground "#8fbcbb"
  ;;                            ))))
  ;; (org-level-2 ((t (:inherit outline-1 :height 1.2 :weight bold ;; :foreground "#88c0d0"
  ;;                            ))))
  ;; (org-level-3 ((t (:inherit outline-1 :height 1.1 :weight bold ;; :foreground "#81a1c1"
  ;;                            ))))
  ;; (org-level-4 ((t (:inherit outline-1 :height 1.0 :weight bold ;; :foreground "#5e81ac"
  ;;                            ))))
  ;; (org-level-5 ((t (:inherit outline-1 :height 1.0 :weight bold))))
  ;; (org-block-begin-line ((t (:inherit 'fixed-pitch :background nil))))
  ;; (org-block-end-line ((t (:inherit 'org-block-begin-line))))
  ;; (org-code ((t (:inherit 'fixed-pitch))))
  ;; (org-link ((t (:inherit 'fixed-pitch))))
  ;; (org-block ((t (:inherit 'fixed-pitch))))
  ;; (org-table ((t (:inherit 'fixed-pitch))))
  ;; (org-verbatim ((t (:inherit 'fixed-pitch))))
  ;; (org-meta-line ((t (:inherit 'fixed-pitch))))
  ;; (org-document-info-keyword ((t (:inherit 'fixed-pitch))))
  :custom
  (org-agenda-files (list "~/org/agenda/"))
  :config
  (my-org-prettify-settings)
  (my-org-todo-setup)
  (my-org-structure-templates))

Org Babel

org-babel-do-load-languages enables languages for in-buffer evaluation

(use-package org-babel
  :no-require
  :straight nil
  :config
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((python . t))))

Writing

Some things to make writing nicer.

Olivetti centers the text and sets a minimum width. It makes reading things, especially on widescreens, a bit nicer.

(use-package olivetti
  :defer t
  :custom
  (olivetti-body-width 90))

Writegood highlights text based on a set of weasel-words, passive-voice and duplicate words.

(use-package writegood-mode
  :defer t)

Enable the minor modes I use for writing

(defun my/writing-modes ()
  (interactive)
  (flyspell-mode +1)
  (olivetti-mode +1)
  (writegood-mode +1))

ox-hugo

org mode for hugo blogs. Having an issue with loading this on OSX so only install it on Linux for now.

;; this seems to be required for ox-hugo to work
(use-package ox :straight nil)

(when (eq system-type 'gnu/linux)
  (use-package ox-hugo
    :after ox))

Code

Things that are used when coding.

Line Numbers

Add line numbers to programming mode buffers. I think they look wierd in my org config due to the different sized fonts.

(use-package display-line-numbers
  :straight nil
  :ghook
  ('prog-mode-hook #'display-line-numbers-mode))

flycheck

Enable error checking everywhere.

(use-package flycheck
  :config
  (global-flycheck-mode +1))

company

Company provides code completion.

(use-package company
  :config
  (global-company-mode +1))

language server protocol

Setup for Microsoft’s (GASP!) Language Server Protocol. Any language that uses this calls lsp in the language mode’s :hook / :ghook

The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc.

;; (setq lsp-keymap-prefix "C-l")

(use-package lsp-mode
  :hook (lsp-mode . lsp-enable-which-key-integration)
  :commands lsp
  :custom
  (lsp-completion-provider :capf)
  (lsp-keymap-prefix "C-l"))

(use-package lsp-ui
  :commands lsp-ui-mode)

(use-package lsp-ivy :commands lsp-ivy-workspace-symbol)
(use-package lsp-treemacs :commands lsp-treemacs-errors-list)
(use-package dap-mode)

Some handy links

electric pair

Use the built in electric-pair-mode to autocomplete brackets.

(use-package elec-pair
  :straight nil
  :hook
  (prog-mode . electric-pair-mode)
  (org-mode . electric-pair-mode))

yasnippet

Use snippets in specific modes

(use-package yasnippet
 :custom
 (yas-snippet-dirs
  '("~/.emacs.d/snippets"))
 :config
 (yas-global-mode +1))

Install the official snippets

(use-package yasnippet-snippets
  :after yasnippet)

editorconfig

Use editorconfig for projects that have them

(use-package editorconfig
  :delight
  :config
  (editorconfig-mode +1))

agressive-indent

Keep code nicely aligned automatically! This will be turned in on language modes that work will with it (e.g. lisps).

(use-package aggressive-indent
  :defer t)

Version Control

magit

use git in emacs!

magit-yank-branch-name is from https://emacs.stackexchange.com/questions/30487/add-copy-to-kill-ring-current-branch-name-with-magit

(use-package magit
  :defer t
  :general
  ("C-x g" 'magit-status)
  (my-leader-def
    "g" '(:ignore t :wk "git")
    "gs" 'magit-status
    "gc" 'magit-checkout
    "gC" 'magit-commit
    "gb" 'magit-blame
    "gS" 'magit-stage-file
    "gU" 'magit-unstage-file
    "gg" 'hydra-my-git-menu/body
    "gy" 'my/magit-yank-branch-name)
  :custom
  (magit-completing-read-function 'ivy-completing-read)
  :config
  (defun my/magit-yank-branch-name ()
    "Show the current branch in the echo-area and add it to the `kill-ring'."
    (interactive)
    (let ((branch (magit-get-current-branch)))
      (if branch
          (progn (kill-new branch)
                 (message "%s" branch))
        (user-error "There is not current branch")))))

Forge

This adds integration with github

(use-package forge
  :after magit)

git-timemachine

(use-package git-timemachine
  :defer t)

git-messenger

Show commit info

(use-package git-messenger
  :defer t)

git-gutter-fringe

Show whether something has been added, modified, or deleted on the side of the screen.

(use-package git-gutter-fringe
  :config
  (global-git-gutter-mode +1)
  (setq-default fringes-outside-margins t))

git-link

Get the URLs for links/commits/repo homepages. This is useful for PRs and tickets when you need to link to a certain line of code.

(use-package git-link
  :general
  (my-leader-def
    "gl" '(:ignore t :wk "git link")
    "gll" 'git-link
    "glc" 'git-link-commit
    "glh" 'git-link-homepage))

browse-at-remote

This is almost the opposite of git-link, it will open selected line(s) on the remote (e.g. github).

(use-package browse-at-remote
  :general
  (my-leader-def
    "glg" 'browse-at-remote))

My Git Hydra

(defhydra hydra-my-git-menu (global-map "<f7>"
                                        :color blue)
  "
^Navigate^        ^Action^               ^Info^
^^^^^^^^^^^^---------------------------------------------------
_j_: next hunk    _s_: stage hunk        _d_: diff
_k_: prev hunk    _S_: stage file        _c_: show commit
^ ^               _U_: unstage file      _g_: magit status
^ ^               ^ ^                    _t_: git timemachine
^ ^               ^ ^                    ^ ^
"
  ("j" git-gutter:next-hunk)
  ("k" git-gutter:previous-hunk)
  ("s" git-gutter:stage-hunk)
  ("S" magit-stage-file)
  ("U" magit-unstage-file)
  ("c" git-messenger:popup-show)
  ("g" magit-status :exit t)
  ("d" magit-diff-buffer-file)
  ("t" git-timemachine :exit t)
  ("q" quit-window "quit-window")
  ("<ESC>" git-gutter:update-all-windows "quit" :exit t))

Git timemachine

(defhydra hydra-my-git-timemachine-menu (:color blue)
  ("s" git-timemachine "start")
  ("j" git-timemachine-show-next-revision "next revision")
  ("k" git-timemachine-show-previous-revision "prev revision")
  ("c" git-timemachine-show-current-revision "curr revision")
  ("<ESC>" git-timemachine-show-current-revision "quit" :exit t))

System Specific

OSX

Paths need to be explicitly defined for some reason in OSX. exec-path-from-shell fixes it.

(use-package exec-path-from-shell
  :if (eq system-type 'darwin)
  :config
  (exec-path-from-shell-initialize))

Enable ligatures for fonts that have them Only seems to work on railwaycat/homebrew-emacsmacport

;; (when (eq system-type 'darwin)
;;   (mac-auto-operator-composition-mode))

Use python 3 by default

(when (eq system-type 'darwin)
  (setq python-shell-interpreter "/usr/local/bin/python3"))

OSX displays a big yellow warning sign for a visual bell and I think its annoying. This flashes the modeline instead. Taken from here https://www.emacswiki.org/emacs/AlarmBell

(when (eq system-type 'darwin)
  (setq visible-bell nil
        ring-bell-function 'flash-mode-line)
  (defun flash-mode-line ()
    (invert-face 'mode-line)
    (run-with-timer 0.1 nil #'invert-face 'mode-line)))

Point to the git executable, this is supposed to speed up magit

(when (eq system-type 'darwin)
  (setq magit-git-executable "/usr/bin/git"))

Linux

StumpWM

(when (eq window-system 'x)
  (use-package stumpwm-mode
    :defer t))

Connect to a sly repl that can control stumpwm

(when (eq window-system 'x)
  (defun my/stumpwm-connect ()
    (interactive)
    (sly-connect "localhost" "4004")))

Local file

The local file contains machine specific stuff, eg for my home and my work configs.

(org-babel-load-file "~/dotfiles/emacs-local.org")

Chat

Configuration for the built in erc client.

This uses IRC credentials in the ~/.authinfo file:

machine irc.freenode.net login <nickname> password <password> port 6697
(use-package erc
  :defer t
  :straight nil
  :preface
  (defun erc-start-or-switch ()
    "Start ERC or switch to ERC buffer if it has started already."
    (interactive)
    (if (get-buffer "irc.freenode.net:6697")
        (erc-track-switch-buffer 1)
      (erc-tls :server "irc.freenode.net" :port 6697 :nick my-irc-nick :full-name user-full-name)))
  :init
  (defcustom my-irc-nick "kpav"
    "Nickname used to log into IRC"
    :type 'string)
  :custom
  (erc-autojoin-channels-alist '(("freenode.net" "#emacs" "#archlinux" "#python" "#clojure" "#hy" "#stumpwm")))
  (erc-track-exclude-types '("NICK" "PART" "MODE" "324" "329" "332" "333" "353" "477"))
  (erc-server-coding-system '(utf-8 . utf-8))
  (erc-interpret-mirc-color t)
  (erc-kill-buffer-on-part t)
  (erc-kill-queries-on-quit t)
  (erc-kill-server-buffer-on-quit t))

Other

restart

Yo dawg, use restart-emacs to restart emacs within emacs. Using this because I’m constantly making changes to this file and sometimes I need to restart things for changes to take affect.

(use-package restart-emacs
  :defer t)

vterm

(use-package vterm)
(use-package multi-vterm
  :general
  (my-leader-def
    "t" '(:ignore t :wk "term")
    "tt" 'multi-vterm
    "tn" 'multi-vterm-next
    "tp" 'multi-vterm-prev)
  :config
  (add-hook 'vterm-mode-hook
            (lambda ()
              ;; (setq-local evil-insert-state-cursor 'box)
              (evil-insert-state)))
  (define-key vterm-mode-map [return]                      #'vterm-send-return)

  (setq vterm-keymap-exceptions nil)
  (evil-define-key 'insert vterm-mode-map (kbd "C-e")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-f")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-a")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-v")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-b")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-w")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-u")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-d")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-n")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-m")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-p")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-j")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-k")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-r")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-t")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-g")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-c")      #'vterm--self-insert)
  (evil-define-key 'insert vterm-mode-map (kbd "C-SPC")    #'vterm--self-insert)
  (evil-define-key 'normal vterm-mode-map (kbd "C-d")      #'vterm--self-insert)
  (evil-define-key 'normal vterm-mode-map (kbd ",c")       #'multi-vterm)
  (evil-define-key 'normal vterm-mode-map (kbd ",n")       #'multi-vterm-next)
  (evil-define-key 'normal vterm-mode-map (kbd ",p")       #'multi-vterm-prev)
  (evil-define-key 'normal vterm-mode-map (kbd "i")        #'evil-insert-resume)
  (evil-define-key 'normal vterm-mode-map (kbd "o")        #'evil-insert-resume)
  (evil-define-key 'normal vterm-mode-map (kbd "<return>") #'evil-insert-resume))

restclient

Test RESTful APIs in emacs!

(use-package restclient
  :defer  t)

(use-package company-restclient
  :defer t)

(use-package ob-restclient
  :defer t)

Languages

Configuration for programming languages

C

Example taken from EmacsWIki: Indenting C

(setq c-default-style "linux"
      c-basic-offset 4)

Docker

Docker is not necessarily a programming langage, but....

Dockerfile is

(use-package dockerfile-mode
  :defer t)

Use docker commands in emacs

(use-package docker
  :defer t)

Haskell

For xmonad and beyond

(use-package haskell-mode
  :mode "\\.hs\\'"
  :hook (haskell-mode . turn-on-haskell-indent))

Javascript

Vanilla

Setup for JavaScript using js2-mode and LSP.

LSP mode is using typescript-language-server.

(use-package js2-mode
  :mode "\\.js$"
  :hook (js2-mode . lsp)
  :interpreter "node"
  :ensure-system-package ((typescript-language-server . "npm i -g typescript-language-server")
                          (eslint_d . "npm i -g eslint_d"))
  :custom
  ;; set the indent level to 2
  (js2-basic-offset 2)
  (js-chain-indent t)
  (js-indent-level 2)
  ;; use eslint_d instead of eslint for faster linting
  (flycheck-javascript-eslint-executable "eslint_d"))

JSON

(use-package json-mode
  :mode "\\.json\\'")

TypeScript

(use-package typescript-mode
  :mode "\\.ts$"
  :hook (typescript-mode . lsp))
;; (use-package tide
;;   :config
;;   ;; aligns annotation to the right hand side
;;   (setq company-tooltip-align-annotations t)
;;   ;; formats the buffer before saving
;;   (add-hook 'before-save-hook 'tide-format-before-save)
;;   (add-hook 'typescript-mode-hook
;;             (lambda ()
;;               (interactive)
;;               (tide-setup)
;;               (flycheck-mode +1)
;;               (setq flycheck-check-syntax-automatically '(save-mode-enabled))
;;               (eldoc-mode +1)
;;               (tide-hl-identifier-mode +1)))
;;   (add-hook 'tide-mode-hook
;;             (lambda ()
;;               (define-key tide-mode-map (kbd "<f12>") 'tide-jump-to-definition))))

React

rjsx-mode is for editing .jsx files

Dont need too much here because it uses js2-mode where most of the config is done

(use-package rjsx-mode
  :mode "\\.jsx\\'")

REPL

Setup up a javascript repl using skewer

(use-package skewer-mode
  :defer t
  :ghook ('js2-mode-hook)
  :general
  (my-local-leader-def 'js2-mode-map
    "eb" 'skewer-eval-defun
    "el" 'skewer-eval-last-expression))

To use, M-x run-skewer and then M-x skewer-repl

Lisp

Keys

All lisp languages have a set of shared keys:

KeyCommand
SPC m e beval buffer
SPC m e leval last sexp
SPC m e deval defun
SPC m e reval region

Some languages have some more, but those are the base keys for all lisps.

Replace +prefix with +eval in which-key for SPC m e

(which-key-add-major-mode-key-based-replacements 'clojure-mode "SPC m e" "eval")
(which-key-add-major-mode-key-based-replacements 'emacs-lisp-mode "SPC m e" "eval")
(which-key-add-major-mode-key-based-replacements 'hy-mode "SPC m e" "eval")
(which-key-add-major-mode-key-based-replacements 'lisp-interaction-mode "SPC m e" "eval")
(which-key-add-major-mode-key-based-replacements 'scheme-mode "SPC m e" "eval")

Shared

Shared setup for all lisp modes.

A list of all lisp modes that I use. This is used with :ghook to enable lispy in all of these modes.

(defconst my-lisp-mode-hooks
  '(lisp-mode-hook
    sly-mrepl-mode-hook
    emacs-lisp-mode-hook
    scheme-mode-hook
    geiser-repl-mode-hook
    hy-mode-hook
    inferior-hy-mode-hook
    clojure-mode-hook
    cider-repl-mode-hook))

Now setup packages that will be used for all the lisp modes above.

  • lispy inserts matching parentheses, among other things.
  • turn off smartparens because it is not needed with lispy (it also adds pairs for single quotes, which is annoying in lisp)
  • lispyville makes evil-mode play nice with lispy
(defun my-lisp-setup ()
  (aggressive-indent-mode +1)
  (electric-pair-mode -1))

(use-package paredit
  :defer t
  :ghook my-lisp-mode-hooks
  :gfhook #'my-lisp-setup)

;; (defun my-lisp-setup ()
;;   (turn-off-smartparens-mode)
;;   (lispyville-mode 1))

;; (use-package lispyville)

;; (use-package lispy
;;   :defer t
;;   :ghook my-lisp-mode-hooks
;;   :gfhook #'my-lisp-setup
;;   :general
;;   ("\"" 'lispy-quotes)
;;   ("(" 'lispy-parens)
;;   (")" 'lispy-right-nostring)
;;   ("}" 'lispy-brackets)
;;   ("{" 'lispy-braces)
;;   ("[" 'lispy-forward)
;;   ("]" 'lispy-backward)
;;   (";" 'lispy-comment))

Emacs Lisp

(my-local-leader-def
  :keymaps 'emacs-lisp-mode-map
  "eb" 'eval-buffer
  "el" 'eval-last-sexp
  "ed" 'eval-defun
  "er" 'eval-region)
(my-local-leader-def
  :keymaps 'lisp-interaction-mode-map
  "eb" 'eval-buffer
  "el" 'eval-last-sexp
  "ed" 'eval-defun
  "er" 'eval-region)
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)

Clojure

lsp is using snoe/clojure-lsp

(use-package clojure-mode
  :hook ((clojure-mode . lsp)
         (clojurec-mode . lsp)
         (clojurescript-mode . lsp))
  :config
  (dolist (m '(clojure-mode
               clojurec-mode
               clojurescript-mode
               clojurex-mode))
    (add-to-list 'lsp-language-id-configuration `(,m . "clojure")))
  (setq lsp-enable-indentation nil))

CIDER is the Clojure(Script) Interactive Development Environment that Rocks!

cider-repl-set-ns sets the repl’s namespace (ns) to the current file so you can eval and then use functions without adding the ns

(use-package cider
  :after clojure-mode
  :hook (cider-repl-mode . rainbow-delimiters-mode)
  :general
  (my-local-leader-def 'clojure-mode-map
    "r" 'cider
    "n" 'cider-repl-set-ns
    "er" 'cider-eval-region
    "eb" 'cider-eval-buffer
    "ef" 'cider-eval-sexp-at-point
    "el" 'cider-eval-last-sexp))

Common Lisp

Sly

(use-package sly
  :defer t
  :hook (sly-mrepl-mode . rainbow-delimiters-mode)
  :general
  (my-local-leader-def
    :keymaps 'lisp-mode-map
    "eb" 'sly-eval-buffer
    "el" 'sly-eval-last-expression
    "ed" 'sly-eval-defun
    "er" 'sly-eval-region)
  :config
  (setq inferior-lisp-program "/usr/bin/sbcl"))

(use-package sly-quicklisp
  :after sly)

(use-package sly-asdf
  :after sly)

Hy

Let’s get hy. A lisp for Python.

(use-package hy-mode
  :mode "\\.hy\\'"
  :general
  (my-local-leader-def 'hy-mode-map
    "er" 'hy-shell-eval-region
    "eb" 'hy-shell-eval-buffer
    "el" 'hy-shell-eval-last-sexp
    "ed" 'hy-shell-eval-current-form))

Scheme

geiser provides a nice repl for scheme and other things

(use-package geiser
  :defer t
  :general
  (my-local-leader-def
    :keymaps 'scheme-mode-map
    "r" 'run-geiser
    "er" 'geiser-eval-region
    "eR" 'geiser-eval-region-and-go
    "eb" 'geiser-eval-buffer
    "eB" 'geiser-eval-buffer-and-go
    "ed" 'geiser-eval-definition
    "eD" 'geiser-eval-definition-and-go
    "el" 'geiser-eval-eval-sexp)
  :custom
  (geiser-active-implementations '(guile mit racket)))

PHP

I use PHP for my job, so I need to use the WellspringCodingStandard.

(use-package php-mode
  :mode "\\.php\\'"
  :gfhook #'my-php-setup
  :general
  (general-define-key
   :keymaps 'php-mode-map
   "C-c a" 'my/align-php-dbl-arrow)
  (my-local-leader-def 'php-mode-map
    "a" 'my/align-php-dbl-arrow
    "j" 'lsp-find-definition)
  :custom
  ;; align -> on successive lines
  (php-lineup-cascaded-calls t)
  (flycheck-phpcs-standard "WellspringCodingStandard"))

Setup the default coding style and LSP for php. Need to set lsp-enable-file-watchers to nil because the project has a large amount of files and it causes performance issues.

(defun my-php-setup ()
  (php-enable-default-coding-style)
  (setq lsp-enable-file-watchers nil)
  (lsp))

Align the ==>= in arrays

(defun my/align-php-dbl-arrow ()
  "Align the => in arrays."
  (interactive)
  (align-regexp
   (region-beginning) (region-end)
   "\\(\\s-*\\) => " 1 0 nil))

Use PHP_CodeSniffer to format files

(use-package phpcbf
  :after (php-mode)
  ;;:hook ((php-mode . phpcbf-enable-on-save))
  :custom
  (phpcbf-executable "/usr/local/bin/phpcbf")
  (phpcbf-standard "WellspringCodingStandard"))

psysh is a php repl

(use-package psysh
  :defer t)

Python

For flycheck to work, install flake8.

LSP uses the palantir python language server (pyls).

(use-package python
  :mode "\\.py\\'"
  :ghook
  ('python-mode-hook #'lsp)
  :general
  (my-local-leader-def 'python-mode-map
    "er" 'python-shell-send-region
    "eb" 'python-shell-send-buffer
    "ef" 'python-shell-send-file
    "es" 'python-shell-send-string))

Use pipenv to handle virtual environments

(use-package pipenv
  :hook ((python-mode . pipenv-mode)
         (hy-mode . pipenv-mode))
  :init
  (setq pipenv-projectile-after-switch-function #'pipenv-projectile-after-switch-extended))

Elpy - OLD

trying out LSP instead of elpy, keeping this in case I want to go back.

elpy is an “Emacs Lisp Python Environment”

;; (use-package elpy
;;   :config
;;   (elpy-enable))

Web Mode

Set up web mode for html and css files

(use-package web-mode
  :defer t
  :preface
  (defun my-web-mode-hook ()
    ;; set the html indent to 2
    (setq web-mode-markup-indent-offset 2)
    (setq evil-shift-width 2)
    ;; highlight matching elements in html
    (setq web-mode-enable-current-element-highlight 1))
  :hook (web-mode . my-web-mode-hook)
  :init
  ;; (setq web-mode-ac-sources-alist
  ;;       '(("css" . (ac-source-css-property))
  ;;         ("html" . (ac-source-words-in-buffer ac-source-abbrev))))
  (add-hook 'web-mode-before-auto-complete-hooks
            '(lambda ()
               (let ((web-mode-cur-language
                      (web-mode-language-at-pos))))))
  (add-to-list `auto-mode-alist '("\\.html?\\'" . web-mode))
  (add-to-list `auto-mode-alist '("\\.css\\'" . web-mode)))

YAML

For editing .yml files

(use-package yaml-mode
  :defer t)

Things to do

An on-going list of things I want to change

  • [X] Add more keybindings for evil-easymotion
  • [ ] Look into why org-superstar doesnt work on mac
  • [ ] Figure out why lispy doesn’t bind its keys correctly, e.g. ( to lispy-parens
  • [ ] Look into the build in js-mode in place of js2-mode and rjsx, it can now work with jsx files
  • [ ] Look into web-mode for tsx files
  • [-] make org prettier [1/2]
    • [ ] fix company results in variable-pitch-mode
    • [X] bullets?
      • only did the first level of bullets though
  • [ ] setup and use org capture
  • [ ] Configure C#
    • use the C# lsp??
  • [ ] setup forge to replace magithub
  • [ ] window management hydra?
  • [-] telephone-line [3/6]
    • [X] my-buffer-segment [3/3]
      • [X] display truncated path up to project name, full path up to file name
      • [X] color project name
      • [X] different colors for path / file name?
    • [X] fix colors
    • [X] git
    • [ ] eyebrowse
    • [ ] anzu
    • [ ] flycheck
  • [ ] make jumping better
    • [ ] use ‘ac’ package jumps along with smart and dumb jump?
    • [ ] make keybindings consistent
    • [ ] lsp!

Cool looking packages to check out