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
- Prerequisites
- Known issues
- Elisp scope
- Parameters
- Paths
- Shell
- Personal details
- Bind alt, meta and super
- UI
- Navigation
- Terminal
- Files
- Calendar
- Completion
- Org-mode
- Projects
- Python
- Java
- Scala
- Swift
- Golang
- Rust
- SQL
- Misc
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
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
Nuke straight and start clean:
rm -rf $EMACSDIR/.local/straight/
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; -*-
(require 'epa-file)
(epa-file-enable)
;;(load "~/.doom.d/parameters.el.gpg")
(load "~/.config/doom/parameters.el")
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))
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"))
(setq user-full-name user-full-name-param
user-mail-address user-mail-address-param)
(cond (IS-MAC
(setq mac-command-modifier 'meta
mac-option-modifier 'alt
mac-right-option-modifier 'super)))
(setq doom-theme 'doom-nord)
(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))
Maximise Frame on startup.
(add-to-list 'default-frame-alist '(fullscreen . maximized))
Turn off unnecessary UI elements.
(menu-bar-mode -1)
(tool-bar-mode -1)
Set absolute line numbers and display in every buffer.
(global-display-line-numbers-mode 1)
(setq display-line-numbers-type t)
Set a custom splash image.
(setq fancy-splash-image (concat doom-private-dir "splash/I-am-doom-small.png"))
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)
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
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:-
kbd | action |
---|---|
f | one letter forwards (inclusive) |
F | one letter backwards (inclusive) |
t | one letter forwards (exclusive) |
T | one letter backwards (exclusive) |
; or f/t | jump to next occurrence of search |
, | jump to previous occurrence of search |
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)
Allow treemacs to be selected as other-window, for quick switching.
(setq treemacs-is-never-other-window nil)
Multi-vterm is used to manage multiple vterm buffers simultaneously.
(use-package multi-vterm)
Enable autosave.
(setq auto-save-default t
make-backup-files t)
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))
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))
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
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)
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)
M-x chatgpt
(setq openai-key openai-key-param)
Pre-requisites:-
- Clang
- Graphviz
- Pandoc
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)
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)
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))
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)
Configuration for using gnuplot in org buffers
(require 'gnuplot-mode)
Configuration for the project management tool Projectile.
(setq projectile-project-search-path projectile-project-search-path-param)
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)
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)
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 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`
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))
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)
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))))
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
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/
EJC-SQL is used for running database queries from within an org file. Pre-requisites:-
- Lein (for Clojure)
Also see https://quabr.com/64274647/clojure-cider-on-catalina-the-lein-executable-isn-t-on-your-exec-path
(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)))
Enable Pocket for viewing bookmarks.
(require 'pocket-reader)
(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)))))))
(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"))))