Skip to content

cpnat/.doom.d

Repository files navigation

Emacs Configuration

This file (in conjunction with org-babel-tangle) is used to generate a config.el for Doom Emacs (https://github.com/doomemacs/doomemacs). Run a local refresh at the head of this file (CTRL-C CTRL-C) prior to tangling.

Additionally, packages are managed in packages.el and some Doom specific initial configuration in init.el

Table of contents

Prerequisites

Setup Emacs with native compilation of Elisp Bytecode to GCC Intermediate Representation 🚀 (Note: Doom defaults to Ahead of Time compile, but this can also be configure as Just In Time, with hot-swapping from Bytecode).

https://emacsconf.org/2021/talks/native/

brew install gcc --build-from-source --force brew install emacs-plus@28 --with-native-comp

Known issues

Too many files open on native comp

By default, macOS limits processes to only opening 256 files at a time. You can temporarily raise this limit in your current shell by running:

ulimit -n 1024

https://discourse.doomemacs.org/t/fix-for-doom-build-too-many-open-files-on-native-comp/2650

doom upgrade: origin/melpa does not exist

Nuke straight and start clean:

rm -rf $EMACSDIR/.local/straight/

doomemacs/doomemacs#8003

Elisp scope

Elisp uses dynamic scoping by default, however this comes with a performance penalty. Lexical scope is set with a file parameter.

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-

Parameters

(require 'epa-file)
(epa-file-enable)
;;(load "~/.doom.d/parameters.el.gpg")
(load "~/.config/doom/parameters.el")

Paths

Set $MANPATH, $PATH and exec-path from shell, but only when executed in a GUI frame on OS X

(setq shell-file-name (executable-find "fish"))
(when (memq window-system '(mac ns x))
  (exec-path-from-shell-initialize))

Shell

Fish (and other non-POSIX shells) are known to inject garbage output into some of the child processes that Emacs spawns. Many Emacs packages/utilities will choke on this output, causing unpredictable issues. To get around this, set the default shell as bash, and configure the terminal emulator to use Fish.

(setq shell-file-name (executable-find "bash"))
(setq-default vterm-shell (executable-find "fish"))

Personal details

(setq user-full-name user-full-name-param
      user-mail-address user-mail-address-param)

Bind alt, meta and super

(cond (IS-MAC
       (setq mac-command-modifier      'meta
             mac-option-modifier       'alt
             mac-right-option-modifier 'super)))

UI

Theme

(setq doom-theme 'doom-nord)

Fonts

(setq doom-font (font-spec :family "Fira Code" :style "Retina" :size 14 :height 1.0)
      doom-big-font (font-spec :family "Fira Code" :style "Retina" :size 28 :height 1.0))

;;(setq doom-font (font-spec :family "Source Code Pro" :style "Regular" :size 14))
;;      doom-variable-pitch-font (font-spec :family "ETBembo" :style "RomanLF" :size 18 :height 1.0))

Frame

Maximise Frame on startup.

(add-to-list 'default-frame-alist '(fullscreen . maximized))

Other UI elements

Turn off unnecessary UI elements.

(menu-bar-mode -1)
(tool-bar-mode -1)

Line numbers

Set absolute line numbers and display in every buffer.

(global-display-line-numbers-mode 1)
(setq display-line-numbers-type  t)

Splash

Set a custom splash image.

(setq fancy-splash-image (concat doom-private-dir "splash/I-am-doom-small.png"))

Cursor

Flash the cursor following vertical or horizontal movement to increase visibility.

(require 'beacon)
(beacon-mode 1)
(setq beacon-blink-when-point-moves-horizontally 1)
(setq beacon-blink-when-point-moves-vertically 1)
(setq beacon-dont-blink-commands nil)

Multiple cursors

A combination of evil-mc https://github.com/gabesoft/evil-mc and evil-multiedit https://github.com/hlissner/evil-multiedit can be used where multiple cursors are required

Navigation

Snipe

Enable evil-snipe for quick horizontal movement.

(evil-snipe-mode +1)
(evil-snipe-override-mode +1)

(setq evil-snipe-repeat-scope 'buffer)

(evil-define-key 'visual evil-snipe-local-mode-map "z" 'evil-snipe-s)
(evil-define-key 'visual evil-snipe-local-mode-map "Z" 'evil-snipe-S)

Keybinds are as follow:-

kbdaction
fone letter forwards (inclusive)
Fone letter backwards (inclusive)
tone letter forwards (exclusive)
Tone letter backwards (exclusive)
; or f/tjump to next occurrence of search
,jump to previous occurrence of search

Avy

avy (https://github.com/abo-abo/avy) is used for larger movements across visible buffer regions (similar to vim easymotion); with vim /?nN used to find text in regions that are not visible.

(map! :leader
        :desc "Avy goto" "SPC" #'avy-goto-char-2)

(setq avy-all-windows 'all-frames)

Treemacs

Allow treemacs to be selected as other-window, for quick switching.

(setq treemacs-is-never-other-window nil)

Terminal

Multi-vterm

Multi-vterm is used to manage multiple vterm buffers simultaneously.

(use-package multi-vterm)

Files

Autosave

Enable autosave.

(setq auto-save-default t
      make-backup-files t)

Markdown

Use fundamental mode for markdown files to improve performance. TODO: Create a function that dynamically sets the mode based upon file size.

;; (add-to-list 'auto-mode-alist '("\\.md\\'" . fundamental-mode))

Calendar

ISO week numbers

Display ISO week numbers in calendar mode.

(copy-face font-lock-constant-face 'calendar-iso-week-face)
(set-face-attribute 'calendar-iso-week-face nil
                    :height 1)
(setq calendar-intermonth-text
      '(propertize
        (format "%2d"
                (car
                 (calendar-iso-from-absolute
                  (calendar-absolute-from-gregorian (list month day year)))))
        'font-lock-face 'calendar-iso-week-face))

Completion

Hunpell

Hunspell (https://hunspell.github.io/) is used for spellchecking and prose completion. GNU Ispell/Aspell should not be installed.

(require 'ispell)

(add-to-list 'ispell-hunspell-dictionary-alist '("en_GB-hs"
                                              "[[:alpha:]]"
                                              "[^[:alpha:]]"
                                              "[']"
                                              t
                                              ("-d" "en_GB")
                                              nil
                                              iso-8859-1))

(add-to-list 'ispell-hunspell-dictionary-alist '("en_US-hs"
                                              "[[:alpha:]]"
                                              "[^[:alpha:]]"
                                              "[']"
                                              t
                                              ("-d" "en_US")
                                              nil
                                                iso-8859-1))

(add-to-list 'ispell-hunspell-dictionary-alist '("nb_NO-hs"
                                              "[[:alpha:]]"
                                              "[^[:alpha:]]"
                                              "[']"
                                              t
                                              ("-d" "nb_NO")
                                              nil
                                              iso-8859-1))

(setq ispell-program-name (concat bin-path-param "hunspell")    ; Use hunspell to correct mistakes
      ispell-dictionary   "en_GB-hs")                            ; Default dictionary to use

Language Server Protocol

Company mode with LSP support is used for code completion.

;;(require 'company-lsp)
;;(push 'company-lsp company-backends)

Disable lenses in LSP mode to improve performance. See https://emacs-lsp.github.io/lsp-mode/tutorials/how-to-turn-off/ for a guide on enabling/disabling LSP features.

;; (setq lsp-lens-enable nil)

Increase the file watch theshold

(setq lsp-file-watch-threshold 10000)

Copilot

Some of this setup inspired by https://robert.kra.hn/posts/2023-02-22-copilot-emacs-setup/

Childframe enabled in `packages.el` to prevent overlay conflict

;; accept completion from copilot
(use-package! copilot
  :hook (prog-mode . copilot-mode))

;; enable completion in insert mode
(customize-set-variable 'copilot-enable-predicates '(evil-insert-state-p))

; modify company-mode behaviors
(with-eval-after-load 'company
  (delq 'company-preview-if-just-one-frontend company-frontends))


; bind other useful copilot commands
(map! "A-<right>" #'copilot-accept-completion
      "A-<up>" #'copilot-accept-completion-by-word
      "A-<down>" #'copilot-accept-completion-by-line
      "A-<left>" #'copilot-next-completion)

Chat GPT

M-x chatgpt

(setq openai-key openai-key-param)

Org-mode

Pre-requisites:-

  • Clang
  • Graphviz
  • Pandoc

Org

Configuration for org.

(setq org-directory org-directory-param)
(setq org-support-shift-select t)
(setq org-startup-folded 'fold)

Replace headline markers with unicode bullets.

(use-package org-bullets
  :config
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

Replace ‘…’

(setq org-ellipsis "")

Startup folded

(setq org-startup-folded t)
(setq org-image-actual-width 800)

Org-Babble

https://github.com/emacs-jupyter/jupyter https://sqrtminusone.xyz/posts/2021-05-01-org-python/

Remove conflicting advice config from Doom

(advice-remove #'org-babel-do-load-languages #'ignore)
(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t) ;; Other languages
   (shell . t)
   ;; Python & Jupyter
   (python . t)
   (jupyter . t)))

Display inline images from Babel blocks

(add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)

Org-Roam

Configuration for org-roam.

(use-package org-roam
  :after org
  :init (setq org-roam-v2-ack t) ;; Acknowledge V2 upgrade
  :custom
  (org-roam-directory (file-truename org-roam-directory-param))
  :config
  (org-roam-setup)
  :bind (("C-c n f" . org-roam-node-find)
         ("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-id-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)))))

Leader keymapping.

(map! :leader
       (:prefix ("r" . "org-roam")
        :desc "Find node" "f" #'org-roam-node-find
        :desc "Insert node" "i" #'org-roam-node-insert
        :desc "Get random node" "r" #' org-roam-node-random))

Setup for org-roam-ui.

(use-package! websocket
    :after org-roam)

(use-package! org-roam-ui
    :after org-roam ;; or :after org
;;         normally we'd recommend hooking orui after org-roam, but since org-roam does not have
;;         a hookable mode anymore, you're advised to pick something yourself
;;         if you don't care about startup time, use
;;  :hook (after-init . org-roam-ui-mode)
    :config
    (setq org-roam-ui-sync-theme t
          org-roam-ui-follow t
          org-roam-ui-update-on-save t
          org-roam-ui-open-on-start t))

Org Present

System Crafters has a nice configuration, for inspiration (https://systemcrafters.net/emacs-tips/presentations-with-org-present/).

Leader keymapping.

(map! :leader
        :desc "Org Present" "<up>" #'org-present)

(map! :leader
        :desc "Org Present" "<down>" #'org-present-quit)

(map! :leader
        :desc "Org Present Next" "<right>" #'org-present-next)

(map! :leader
        :desc "Org Present Prev" "<left>" #'org-present-prev)
;; Centering Org Documents
;; Configure fill width, used in conjuntion with writeroom-mode
(setq visual-fill-column-width 75
      visual-fill-column-center-text t)

;;Org Present

(defun my/org-present-prepare-slide (buffer-name heading)
  ;; Show only top-level headlines
  (org-overview)

  ;; Unfold the current entry
  (org-show-entry)

  ;; Show only direct subheadings of the slide but don't expand them
  (org-show-children))

(defun my/org-present-start ()

  ;; Set a blank header line string to create blank space at the top
  (setq header-line-format " ")

  ;; Display inline images automatically
  (org-display-inline-images)

  ;; Center the presentation, wrap lines, and hide modelines
  (writeroom-mode 1)

  ;; Hide line numbers
  (global-display-line-numbers-mode 0)
)

(defun my/org-present-end ()

  ;; Clear the header line string so that it isn't displayed
  (setq header-line-format nil)

  ;; Stop displaying inline images
  (org-remove-inline-images)

  ;; Stop centering the document and wrapping lines; and show modelines
  (writeroom-mode 0)

  ;; Return line numbers
  (global-display-line-numbers-mode 1)
)

;; Register hooks with org-present
(add-hook 'org-present-mode-hook 'my/org-present-start)
(add-hook 'org-present-mode-quit-hook 'my/org-present-end)
(add-hook 'org-present-after-navigate-functions 'my/org-present-prepare-slide)

Plotting

Configuration for using gnuplot in org buffers

(require 'gnuplot-mode)

Projects

Projectile

Configuration for the project management tool Projectile.

(setq projectile-project-search-path projectile-project-search-path-param)

Magit

Magit is used as an interface to git. This configuration improves performance by refreshing only the current buffer and not the status buffer. See https://magit.vc/manual/magit/Performance.html for more performance improvement tips.

(setq magit-refresh-status-buffer nil)

Treemacs

Make Treeemacs follow Projectile project

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

Use monospaced font in Treemacs

(setq doom-themes-treemacs-enable-variable-pitch nil)

Python

Pyenv

Configuration for Pyenv.

(use-package pyvenv
  :ensure t
  :init
  (setenv "WORKON_HOME" pyenv-directory-param))

(require 'pyenv-mode)

Activate a Pyenv environment with a matching name when switching to a Projectile project.

(defun projectile-pyenv-mode-set ()
  (let ((project (projectile-project-name)))
    (if (member project (pyenv-mode-versions))
        (pyenv-mode-set project)
      (pyenv-mode-unset))))

(add-hook 'projectile-after-switch-project-hook 'projectile-pyenv-mode-set)

Note, since Projectile is used for switching projects, poetry must be configured as follows:-

virtualenvs.create = false
virtualenvs.in-project = false
virtualenvs.path = pyenv-directory-param

Pyright Language Server

Pyright is configured by Doom through init.el. Pre-requisites (to be installed in the venv associated with the project):-

  • pyright
  • pylint
  • flake8

Use `lsp-workspace-folders-add` and `lsp-workspace-folders-remove` to configure the project roots.

And addition https://github.com/alefpereira/pyenv-pyright is a nice plugin for setting the `pyrightconfig.json`

Debug Adapter Protocol

DAP mode uses ptvsd by default, instead use debugpy

(use-package dap-mode)
(use-package dap-python)
(after! dap-mode
  (setq dap-python-debugger 'debugpy))

Java

Eclipse Language Server

Enable Eclipse LSP. Pre-requisites:-

  • JDK
(use-package lsp-java
:ensure t
:config (add-hook 'java-mode-hook 'lsp))

(setenv "JAVA_HOME" java-home-param)

* Scala

** Metals Language Server

Enable Metals LSP. Pre-requisites:-

- JDK
- Coursier (https://get-coursier.io/)
- Metals (installed via Coursier, as below) (https://scalameta.org/metals/)

cs bootstrap \
        --java-opt -Xss4m \
        --java-opt -Xms100m \ f
        --java-opt -Dmetals.client=emacs \
        org.scalameta:metals_2.12:0.10.1 \
        -r bintray:scalacenter/releases \
        -r sonatype:snapshots \
        -o /usr/local/bin/metals-emacs -f -v -v -v
;; Enable scala-mode and sbt-mode
(use-package scala-mode
  :mode "\\.s\\(cala\\|bt\\)$")

(use-package sbt-mode
  :commands sbt-start sbt-command
  :config
  ;; WORKAROUND: https://github.com/ensime/emacs-sbt-mode/issues/31
  ;; allows using SPACE when in the minibuffer
  (substitute-key-definition
   'minibuffer-complete-word
   'self-insert-command
   minibuffer-local-completion-map))

;; Enable nice rendering of diagnostics like compile errors.
(use-package flycheck
  :init (global-flycheck-mode))

(use-package lsp-mode
  ;; Optional - enable lsp-mode automatically in scala files
  :hook (scala-mode . lsp)
  :config (setq lsp-prefer-flymake nil))

(use-package lsp-ui)

;; Add company-lsp backend for metals
(use-package company-lsp)

Swift

Sourcekit Language Server

Enable Apple Sourcekit LSP. Pre-requisites:-

  • XCode
(use-package lsp-sourcekit
  :after lsp-mode
  :config
  (setq lsp-sourcekit-executable lsp-sourcekit-executable-param))

(use-package swift-mode
  :hook (swift-mode . (lambda () (lsp))))

Golang

Several packages need to be installed to support Doom’s default Go configuration, with the gopls language server. See https://docs.doomemacs.org/latest/modules/lang/go/ and https://wmanger.com/articles/go-on-doom-emacs/

In addition, Delve should be installed for debugging https://github.com/go-delve/delve

Rust

The Doom default Rust configuration can be referenced here https://docs.doomemacs.org/latest/modules/lang/rust/ and a nice guide can be found here https://robert.kra.hn/posts/rust-emacs-setup/

SQL

EJC-SQL

EJC-SQL is used for running database queries from within an org file. Pre-requisites:-

(require 'ejc-sql)
(setq nrepl-sync-request-timeout nil)

Create an EJC-SQL database connection. This requires a JDBC driver for the given database.

(ejc-create-connection
   ejc-connection-name-param
   :dependencies ejc-dependencies-param
   :classpath ejc-classpath-param
   :connection-uri ejc-connection-uri-param
   )

Set the format of results from EJC-SQL.

(setq ejc-result-table-impl 'orgtbl-mode)

(add-hook 'ejc-sql-connected-hook
          (lambda ()
            (ejc-set-fetch-size 50)
            (ejc-set-max-rows 50)
            (ejc-set-show-too-many-rows-message t)
            (ejc-set-column-width-limit 1000)
            (ejc-set-use-unicode t)))

Misc

Pocket

Enable Pocket for viewing bookmarks.

(require 'pocket-reader)

camelCase to snake_case

(defun toggle-camelcase-underscores ()
  "Toggle between camelcase and underscore notation for the symbol at point."
  (interactive)
  (save-excursion
    (let* ((bounds (bounds-of-thing-at-point 'symbol))
           (start (car bounds))
           (end (cdr bounds))
           (currently-using-underscores-p (progn (goto-char start)
                                                 (re-search-forward "_" end t))))
      (if currently-using-underscores-p
          (progn
            (upcase-initials-region start end)
            (replace-string "_" "" nil start end)
            (downcase-region start (1+ start)))
        (replace-regexp "\\([A-Z]\\)" "_\\1" nil (1+ start) end)
        (downcase-region start (cdr (bounds-of-thing-at-point 'symbol)))))))

Yank Path

(defun yank-path-to-clipboard ()
  "Get the PATH environment variable and yank it to the clipboard."
  (interactive)
  (let ((path (getenv "PATH")))
    (when path
      ;; Copy PATH to the clipboard
      (kill-new path)
      (message "PATH yanked to clipboard"))))

About

Emacs configuration

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published