1619 lines
47 KiB
Org Mode
1619 lines
47 KiB
Org Mode
#+TITLE: Emacs config
|
|
#+AUTHOR: Erwin Boskma
|
|
#+OPTIONS: toc:nil h:4
|
|
#+STARTUP: overview
|
|
#+PROPERTY: header-args:emacs-lisp :tangle init.el
|
|
#+PROPERTY: header-args:emacs-lisp+ :noweb tangle
|
|
|
|
This is my emacs configuration. It is structured as an org-mode file, to easily provide context and documentation.
|
|
|
|
Last export: {{{modification-time(%Y-%m-%d %H:%M)}}}
|
|
|
|
#+TOC: headlines 4
|
|
|
|
|
|
* Setup
|
|
** Early init
|
|
|
|
This ends up in =early-init.el=.
|
|
|
|
#+begin_src emacs-lisp
|
|
;; -*- lexical-binding: t; -*-
|
|
;; Prevent package.el from loading packages until we're ready for it
|
|
(setq package-enable-at-startup nil)
|
|
;; Don't resize the frame to preserve the number of columns or lines
|
|
;; being displayed when setting font, menu bar, tool bar, tab bar,
|
|
;; internal borders, fringes, or scroll bars. Since I use a tiling
|
|
;; window manager, this option is 1. useless anyways and 2. _terribly_ expensive.
|
|
(setq frame-inhibit-implied-resize t)
|
|
;; Suppress warnings and errors during asynchronous native compilation
|
|
(setq native-comp-async-report-warnings-errors nil)
|
|
;; Prevent unwanted runtime builds; packages are compiled ahead-of-time when
|
|
;; they are installed and site files are compiled when gccemacs is installed.
|
|
;; (setq comp-deferred-compilation nil)
|
|
(setq native-comp-deferred-compilation nil)
|
|
|
|
;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are
|
|
;; compiled ahead-of-time when they are installed and site files are compiled
|
|
;; when gccemacs is installed.
|
|
(setq comp-deferred-compilation nil)
|
|
#+end_src
|
|
|
|
** Personal variables
|
|
|
|
This sets some variables with my personal preferences for easy customization
|
|
|
|
#+begin_src emacs-lisp
|
|
(defvar my/default-font "Iosevka Nerd Font")
|
|
(defvar my/variable-width-font "Iosevka Aile")
|
|
(defvar my/default-font-height 110)
|
|
(defvar my/default-font-weight 'normal)
|
|
(defvar my/default-font-width 'normal)
|
|
(defvar my/variable-width-font-height 1.2)
|
|
(defvar my/config-file-path (expand-file-name "config.org" user-emacs-directory))
|
|
(defvar my/snippets-dir (expand-file-name "snippets" user-emacs-directory))
|
|
(defvar my/local-init-file (expand-file-name "local-init.el" user-emacs-directory))
|
|
(defvar my/leader "C-c")
|
|
#+end_src
|
|
|
|
And my personal info.
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq user-full-name "Erwin Boskma"
|
|
user-mail-address "erwin@datarift.nl")
|
|
#+end_src
|
|
|
|
** Garbage collector
|
|
Increasing the garbage collector threshold should also improve startup time. This increases it from 800 kB to 128MB
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq gc-cons-threshold (* 128 1024 1024))
|
|
#+end_src
|
|
|
|
This resets the threshold back to it's default. This should not be done if =lsp-mode= is enabled, it needs the higher threshold.
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(add-hook 'after-init-hook
|
|
(lambda ()
|
|
(setq gc-cons-threshold 800000)
|
|
(message "gc-cons-threshold restored to %s"
|
|
gc-cons-threshold)))
|
|
#+end_src
|
|
|
|
** Increase process output buffer
|
|
|
|
LSP responses can be rather large, in the 800KiB - 3MiB range. 2MiB is a decent value
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq read-process-output-max (* 2 1024 1024))
|
|
#+end_src
|
|
|
|
** Package sources
|
|
|
|
Add repositories where packages are installed from. Setting =package-enable-at-startup= to =nil= prevents a second package load and improves startup time
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq package-enable-at-startup nil)
|
|
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
|
|
("nongnu" . "https://elpa.nongnu.org/nongnu/")
|
|
("melpa" . "https://melpa.org/packages/")
|
|
("org" . "https://orgmode.org/elpa/")
|
|
("onpa" . "https://olanilsson.bitbucket.io/packages/")))
|
|
#+end_src
|
|
|
|
** Bootstrap use-package
|
|
|
|
If =use-package= is not installed, install it.
|
|
|
|
#+begin_src emacs-lisp
|
|
(require 'package)
|
|
(package-initialize)
|
|
(unless (package-installed-p 'use-package)
|
|
(package-refresh-contents)
|
|
(package-install 'use-package)
|
|
(cl-eval-when 'compile (require 'use-package)))
|
|
#+end_src
|
|
|
|
By default packages should always be installed from the package manager. This is equivalent to setting =:ensure t= on each call to =use-package=. To override this for a package (e.g. because it is builtin, or a subpackage), use =:ensure nil=. This is done automatically for packages that use =:load-path=.
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq use-package-always-ensure t)
|
|
#+end_src
|
|
|
|
** Bootstrap straight.el and use-package [DISABLED]
|
|
|
|
[[https://github.com/radian-software/straight.el][straight.el]] is a pure functional package manager and installs packages from git instead of downloading tars
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(defvar bootstrap-version)
|
|
;; Workaround for flycheck. See https://github.com/radian-software/straight.el/issues/508 for more info
|
|
(setq straight-fix-flycheck t)
|
|
(let ((bootstrap-file
|
|
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
|
|
(bootstrap-version 6))
|
|
(unless (file-exists-p bootstrap-file)
|
|
(with-current-buffer
|
|
(url-retrieve-synchronously
|
|
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
|
|
'silent 'inhibit-cookies)
|
|
(goto-char (point-max))
|
|
(eval-print-last-sexp)))
|
|
(load bootstrap-file nil 'nomessage))
|
|
#+end_src
|
|
|
|
Install =use-package= and make it use =straight.el= by default.
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(straight-use-package 'use-package)
|
|
(setq straight-use-package-by-default t)
|
|
#+end_src
|
|
|
|
** general.el
|
|
|
|
[[https://github.com/noctuid/general.el][general.el]] provides a more convenient way for binding keys in emacs. It also integrates with =use-package= with the =:general= keyword.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package general
|
|
:demand t
|
|
:config
|
|
(progn
|
|
(general-define-key
|
|
:prefix my/leader
|
|
"a" 'org-agenda
|
|
"k" 'general-describe-keybindings)
|
|
(general-define-key
|
|
"C-M-z" 'zap-to-char
|
|
"M-z" 'zap-up-to-char)))
|
|
|
|
#+end_src
|
|
|
|
** Setup asdf [DISABLED]
|
|
|
|
[[https://asdf-vm.com][asdf]] is a tool to install and use multiple versions of development tools and programming languages.
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(when (executable-find "asdf")
|
|
(use-package asdf-vm
|
|
:straight (:host github :repo "delonnewman/asdf-vm.el")
|
|
;; :load-path "~/.config/emacs/elisp/asdf-vm.el/"
|
|
:config
|
|
(asdf-vm-init)))
|
|
#+end_src
|
|
|
|
** Set custom settings to load in temp file [DISABLED]
|
|
|
|
Setting =custom-file= stops emacs from adding customised settings to =init.el=. I prefer to specify everything in this file, so this creates a temporary file where the customisations are stored. This effectively localises customisations to a session
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(setq custom-file (make-temp-file "emacs-custom"))
|
|
#+end_src
|
|
|
|
** Disable the customize interface
|
|
|
|
The =customize= functionality is annoying and messes up regularly. Stuff it has done so far:
|
|
|
|
- Clobber the path to =mix= in Elixir projects
|
|
|
|
This has been borrowed from [[https://github.com/doomemacs/doomemacs/blob/35865ef5e89442e3809b8095199977053dd4210f/core/core-ui.el#L628-L639][Doom Emacs]]
|
|
#+begin_src emacs-lisp
|
|
(dolist (sym '(customize-option customize-browse customize-group customize-face
|
|
customize-rogue customize-saved customize-apropos
|
|
customize-changed customize-unsaved customize-variable
|
|
customize-set-value customize-customized customize-set-variable
|
|
customize-apropos-faces customize-save-variable
|
|
customize-apropos-groups customize-apropos-options
|
|
customize-changed-options customize-save-customized))
|
|
(put sym 'disabled (concat "This config doesn't support `customize', configure Emacs from " user-emacs-directory "/config.org instead")))
|
|
(put 'customize-themes 'disabled (concat "Use `load-theme' in " user-emacs-directory "/config.org instead"))
|
|
#+end_src
|
|
|
|
** Custom packages location
|
|
|
|
Emacs only includes files directly under =user-emacs-directory=. I like to keep custom packages in a separate =elisp/= subdirectory.
|
|
|
|
#+begin_src emacs-lisp
|
|
(add-to-list 'load-path (expand-file-name "elisp/" user-emacs-directory))
|
|
#+end_src
|
|
|
|
** Record key frequency
|
|
|
|
Records what keys are used the most, so I can see if I can optimise shortcuts
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package keyfreq
|
|
:config
|
|
(keyfreq-mode 1)
|
|
(keyfreq-autosave-mode 1))
|
|
#+end_src
|
|
|
|
** Save minibuffer history
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package savehist
|
|
:ensure nil
|
|
:init
|
|
(savehist-mode))
|
|
#+end_src
|
|
|
|
* Preferences
|
|
|
|
Don't display the help screen at startup
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq inhibit-startup-screen t)
|
|
#+end_src
|
|
|
|
Enable line wrapping
|
|
|
|
#+begin_src emacs-lisp
|
|
(global-visual-line-mode 1)
|
|
#+end_src
|
|
|
|
Disable toolbar and scroll bar
|
|
|
|
#+begin_src emacs-lisp
|
|
(tool-bar-mode -1)
|
|
(menu-bar-mode -1)
|
|
(scroll-bar-mode -1)
|
|
#+end_src
|
|
|
|
Don't show the warnings buffer for anything lesser than an error.
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq warning-minimum-level :error)
|
|
#+end_src
|
|
|
|
Keep buffers up-to-date automatically
|
|
|
|
#+begin_src emacs-lisp
|
|
(global-auto-revert-mode t)
|
|
#+end_src
|
|
|
|
Automatically scroll the compile buffer
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq compilation-scroll-output 'first-error)
|
|
#+end_src
|
|
|
|
Always display line numbers, and the relative line number
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq display-line-numbers-type 'relative)
|
|
(global-display-line-numbers-mode)
|
|
#+end_src
|
|
|
|
Show matching parenthesese
|
|
|
|
#+begin_src emacs-lisp
|
|
(show-paren-mode 1)
|
|
(setq show-paren-style 'expression)
|
|
#+end_src
|
|
|
|
Centralise backup files (the =filename~= files), so they don't pollute the project.
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq backup-directory-alist '((".*" . "~/.local/share/emacs/backup"))
|
|
backup-by-copying t ; Don't delink hardlinks
|
|
version-control t ; Use version numbers on backup files
|
|
delete-old-versions t ; Automatically delete obsolete backups
|
|
kept-new-versions 20 ; How many of the newest versions to keep
|
|
kept-old-versions 5 ; And how many of the oldest
|
|
)
|
|
#+end_src
|
|
|
|
Same for auto save files (the ones with the =#=)
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq auto-save-file-name-transforms '((".*" "~/.local/share/emacs/autosave/" t)))
|
|
#+end_src
|
|
|
|
Default indenting to spaces. If tabs are necessary, this can be set buffer-local. A single tab character can be added using =C-q TAB=
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq-default indent-tabs-mode nil)
|
|
#+end_src
|
|
|
|
Delete trailing whitespace on save.
|
|
|
|
#+begin_src emacs-lisp
|
|
(add-hook 'before-save-hook 'delete-trailing-whitespace)
|
|
#+end_src
|
|
|
|
Don't move files to trash when deleting.
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq delete-by-moving-to-trash nil)
|
|
#+end_src
|
|
|
|
Restore cursor position when re-opening a file
|
|
|
|
#+begin_src emacs-lisp
|
|
(save-place-mode t)
|
|
#+end_src
|
|
|
|
Prefer to open frames in a horizontal split
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq split-height-threshold nil)
|
|
#+end_src
|
|
|
|
Set fill column to 80
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq-default fill-column 80)
|
|
#+end_src
|
|
|
|
* Interface
|
|
** Easy edit config file
|
|
|
|
#+begin_src emacs-lisp
|
|
(defun find-config ()
|
|
"Edit config.org"
|
|
(interactive)
|
|
(find-file my/config-file-path))
|
|
|
|
(general-define-key
|
|
:prefix my/leader
|
|
"C" 'find-config)
|
|
#+end_src
|
|
** Appearance
|
|
|
|
I prefer the [[https://draculatheme.com][dracula theme]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package dracula-theme
|
|
:init
|
|
(load-theme 'dracula t))
|
|
#+end_src
|
|
|
|
[[https://github.com/belak/emacs-monokai-pro-theme][Monokai Pro]] is also pretty.
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package monokai-pro-theme
|
|
:init
|
|
(load-theme 'monokai-pro t))
|
|
#+end_src
|
|
|
|
Use Iosevka as font.
|
|
|
|
#+begin_src emacs-lisp
|
|
(set-face-attribute 'default nil
|
|
:family my/default-font
|
|
:weight my/default-font-weight
|
|
:width my/default-font-width
|
|
:height my/default-font-height)
|
|
(set-face-attribute 'variable-pitch nil
|
|
:family my/variable-width-font
|
|
:weight my/default-font-weight
|
|
:width my/default-font-width
|
|
:height my/variable-width-font-height)
|
|
#+end_src
|
|
|
|
Emoji support
|
|
|
|
#+begin_src emacs-lisp
|
|
(defun set-emoji-font ()
|
|
(when (member "Twitter Color Emoji" (font-family-list))
|
|
(set-fontset-font t 'emoji (font-spec :family "Twitter Color Emoji") nil 'prepend)))
|
|
|
|
(use-package emojify
|
|
:defer t
|
|
:init
|
|
(setq emojify-display-style 'unicode)
|
|
:config
|
|
(set-emoji-font)
|
|
:hook (server-after-make-frame . set-emoji-font))
|
|
#+end_src
|
|
|
|
Enable ligatures
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package ligature
|
|
:config
|
|
;; Enable all Iosevka ligatures in programming modes
|
|
(ligature-set-ligatures 'prog-mode '("<---" "<--" "<<-" "<-" "->" "-->" "--->" "<->" "<-->" "<--->" "<---->" "<!--"
|
|
"<==" "<===" "<=" "=>" "=>>" "==>" "===>" ">=" "<=>" "<==>" "<===>" "<====>" "<!---"
|
|
"<~~" "<~" "~>" "~~>" "::" ":::" "==" "!=" "===" "!=="
|
|
":=" ":-" ":+" "<*" "<*>" "*>" "<|" "<|>" "|>" "+:" "-:" "=:" "<******>" "++" "+++"))
|
|
;; Enables ligature checks globally in all buffers. You can also do it
|
|
;; per mode with `ligature-mode'.
|
|
(global-ligature-mode t))
|
|
#+end_src
|
|
|
|
Add a dashboard on startup
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package dashboard
|
|
:after all-the-icons
|
|
:hook (dashboard-mode . (lambda ()
|
|
(setq show-trailing-whitespace nil)))
|
|
:custom
|
|
(dashboard-set-navigator t)
|
|
(dashboard-center-content t)
|
|
(dashbaord-set-file-icons t)
|
|
(dashboard-set-heading-icons t)
|
|
(dashboard-set-init-info t)
|
|
(dashboard-image-banner-max-height 250)
|
|
(dashboard-banner-logo-title "Bûter, brea en griene tsiis, wa dat net sizze kin is gjin oprjochte Fries.")
|
|
(dashboard-startup-banner (concat user-emacs-directory "images/ue-colorful.png"))
|
|
:config
|
|
(dashboard-setup-startup-hook)
|
|
(setq dashboard-footer-icon (all-the-icons-octicon "dashboard"
|
|
:height 1.1
|
|
:v-adjust -0.05
|
|
:face 'font-lock-keyword-face))
|
|
(setq dashboard-navigator-buttons
|
|
`(((,(all-the-icons-octicon "search" :height 0.9 :v-adjust -0.1)
|
|
" Find file" nil
|
|
(lambda (&rest _) (find-file)) nil "" " C-x C-f"))
|
|
((,(all-the-icons-octicon "file-directory" :height 1.0 :v-adjust -0.1)
|
|
" Open project" nil
|
|
(lambda (&rest _) (projectile-switch-project)) nil "" " C-c p p"))
|
|
((,(all-the-icons-octicon "three-bars" :height 1.1 :v-adjust -0.1)
|
|
" File explorer" nil
|
|
(lambda (&rest _) (projectile-dired)) nil "" " C-c p D"))
|
|
((,(all-the-icons-octicon "settings" :height 0.9 :v-adjust -0.1)
|
|
" Open settings" nil
|
|
(lambda (&rest _) (find-config)) nil "" " C-c C "))))
|
|
(setq
|
|
dashboard-projects-backend 'projectile
|
|
dashboard-items '((recents . 5)
|
|
(projects . 5)
|
|
(registers . 5)))
|
|
;; Also show dashboard on new emacsclient window
|
|
(setq initial-buffer-choice (lambda ()
|
|
(get-buffer-create "*dashboard*")))
|
|
:custom-face
|
|
(dashboard-heading ((t (:weight bold)))))
|
|
|
|
#+end_src
|
|
|
|
** Modeline
|
|
|
|
[[https://github.com/myrjola/diminish.el][diminish]] hides modes from the modeline
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package diminish)
|
|
#+end_src
|
|
|
|
[[https://github.com/domtronn/all-the-icons.el][all-the-icons]] provides ALL the icons. Run `all-the-icons-install-fonts` after installing to download the actual font.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package all-the-icons
|
|
:if (display-graphic-p))
|
|
#+end_src
|
|
|
|
[[https://github.com/tarsius/minions][minions]] adds a menu for minor modes to the modeline
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package minions
|
|
:hook
|
|
(doom-modeline-mode . minions-mode))
|
|
#+end_src
|
|
|
|
Use [[https://github.com/seagle0128/doom-modeline][doom-modeline]] for a nice and fancy modeline
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package doom-modeline
|
|
:init
|
|
(doom-modeline-mode 1)
|
|
:config
|
|
(setq doom-modeline-height 25
|
|
doom-modeline-bar-width 6
|
|
doom-modeline-lsp t
|
|
doom-modeline-github nil
|
|
doom-modeline-mu4e nil
|
|
doom-modeline-irc nil
|
|
doom-modeline-minor-modes t
|
|
doom-modeline-persp-name nil
|
|
doom-modeline-buffer-file-name-style 'truncate-except-project
|
|
doom-modeline-icon t)
|
|
:custom-face
|
|
(mode-line ((t (:height 0.85))))
|
|
(mode-line-inactive ((t (:height 0.85)))))
|
|
#+end_src
|
|
|
|
** Command completion
|
|
|
|
*** Ivy / Counsel
|
|
|
|
*Disabled in favor of [[https://github.com/minad/vertico][vertico]]*
|
|
|
|
Ivy is a generic completion framework which uses the minibuffer.
|
|
[[https://github.com/abo-abo/swiper][ivy GitHub page]]
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package ivy
|
|
:diminish t
|
|
:bind
|
|
<<ivy-binds>>
|
|
:config
|
|
<<ivy-config>>
|
|
)
|
|
#+end_src
|
|
|
|
Ivy config
|
|
|
|
#+name: ivy-config
|
|
#+begin_src emacs-lisp :tangle no
|
|
(ivy-mode t)
|
|
(setq ivy-initial-inputs-alist nil
|
|
ivy-use-virtual-buffers nil)
|
|
(define-key read-expression-map (kbd "C-r") 'counsel-expression-history)
|
|
#+end_src
|
|
|
|
Ivy keybindings
|
|
|
|
#+name: ivy-binds
|
|
#+begin_src emacs-lisp :tangle no
|
|
("C-x s" . swiper)
|
|
("C-x C-r" . ivy-resume)
|
|
#+end_src
|
|
|
|
Counsel enhances emacs commands with ivy.
|
|
[[https://github.com/abo-abo/swiper][counsel GitHub page]]
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package counsel
|
|
:bind
|
|
("M-x" . counsel-M-x)
|
|
("C-x C-m" . counsel-M-x)
|
|
("C-x C-f" . counsel-find-file)
|
|
("C-x c k" . counsel-yank-pop))
|
|
#+end_src
|
|
|
|
Company provides completion in the main buffer.
|
|
[[https://company-mode.github.io/][company website]]
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package company
|
|
:diminish t
|
|
:hook
|
|
(after-init . global-company-mode))
|
|
#+end_src
|
|
|
|
Hydra allows you to group commands behind a custom prefix.
|
|
[[https://github.com/abo-abo/hydra][hydra GitHub page]]
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package ivy-hydra)
|
|
#+end_src
|
|
|
|
=major-mode-hydra= binds a single key to open a context sensitive hydra based on the current major mode. Hydras can be defined in =use-package= definitions via the =:mode-hydra= integration.
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package major-mode-hydra
|
|
:bind
|
|
("C-M-SPC" . major-mode-hydra)
|
|
:config
|
|
(major-mode-hydra-define org-mode
|
|
()
|
|
("Tools"
|
|
(("l" org-lint "lint")))))
|
|
#+end_src
|
|
|
|
*** Vertico / Corfu
|
|
|
|
[[https://github.com/minad/vertico][vertico]] is a minimalistic completion UI based on the default completion system integrated in emacs.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package vertico
|
|
:custom
|
|
(vertico-cycle t)
|
|
:init
|
|
(vertico-mode))
|
|
#+end_src
|
|
|
|
[[https://github.com/minad/marginalia][marginalia]] adds extra information to the minibuffer completions.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package marginalia
|
|
:after vertico
|
|
:custom
|
|
(marginalia-annotaters '(marginalia-annotaters-heavy marginalia-annotaters-light nil))
|
|
:init
|
|
(marginalia-mode))
|
|
#+end_src
|
|
|
|
[[https://github.com/minad/consult][consult]] is an alternative to counsel for ivy, but for vertico.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package consult
|
|
:general
|
|
("C-s" 'consult-line)
|
|
("C-x c k" 'consult-yank-pop)
|
|
:config
|
|
(setq consult-project-function (lambda ()
|
|
(when (fboundp 'projectile-project-root)
|
|
(projectile-project-root)))))
|
|
#+end_src
|
|
|
|
[[https://github.com/minad/corfu][corfu]] enhances the completion at point function popups
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package corfu
|
|
;; :bind
|
|
;; ("TAB" . corfu-insert)
|
|
:custom
|
|
(corfu-cycle t)
|
|
(corfu-auto t)
|
|
:init
|
|
(global-corfu-mode))
|
|
#+end_src
|
|
|
|
[[https://github.com/oantolin/orderless][orderless]] is a flexible completion style that allows flexible matching using literal strings, regex and more.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package orderless
|
|
:init
|
|
(setq completion-styles '(orderless partial-completion basic)
|
|
;; completion-category-defaults nil
|
|
completion-category-overrides '((file (styles basic partial-completion)))))
|
|
#+end_src
|
|
|
|
Use =corfu= with =dabbrev= (included with emacs)
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package dabbrev
|
|
:ensure nil
|
|
:general
|
|
("M-/" 'dabbrev-completion)
|
|
("C-M-/" 'dabbrev-expand)
|
|
:custom
|
|
(dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'")))
|
|
#+end_src
|
|
|
|
*** Misc
|
|
which-key shows suggestions when you type an incomplete command and wait for a bit (1 second by default).
|
|
[[https://github.com/justbur/emacs-which-key][which-key GitHub page]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package which-key
|
|
:defer 0
|
|
:diminish which-key-mode
|
|
:config
|
|
(which-key-mode)
|
|
(setq which-key-idle-delay 1))
|
|
#+end_src
|
|
|
|
|
|
*** Possible candidates
|
|
|
|
The following packages look interesting, and are worth investigating further:
|
|
|
|
- [[https://github.com/abo-abo/avy][avy]]: quick text navigation
|
|
- [[https://github.com/abo-abo/ace-window][ace-window]]: window navigation
|
|
- [[https://github.com/magnars/expang-region.el][expand-region]]: context aware text selection
|
|
- [[https://github.com/minad/cape][cape]]: A set of completion at point extensions
|
|
|
|
** File tree
|
|
|
|
[[https://github.com/Alexander-Miller/treemacs][treemacs]] is Emacs' equivalent of neovim's NeoTree or vim's NERDTree.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package treemacs
|
|
:defer t
|
|
:init
|
|
(with-eval-after-load 'winum
|
|
(define-key winum-keymap (kbd "M-0") #'treemacs-select-window))
|
|
:general
|
|
("M-0" 'treemacs-select-window)
|
|
(:prefix "C-c"
|
|
"t 1" 'treemacs-delete-other-windows
|
|
"t t" 'treemacs
|
|
"t d" 'treemacs-select-directory
|
|
"t B" 'treemacs-bookmark
|
|
"t C-t" 'treemacs-find-file
|
|
"t M-t" 'treemacs-find-tag)
|
|
:config
|
|
(progn
|
|
(treemacs-project-follow-mode)))
|
|
#+end_src
|
|
|
|
Enable integration with =projectile=
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package treemacs-projectile
|
|
:after (treemacs projectile))
|
|
#+end_src
|
|
|
|
Add icons
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package treemacs-icons-dired
|
|
:hook (dired-mode . treemacs-icons-dired-enable-once))
|
|
#+end_src
|
|
|
|
Enable =magit= integration
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package treemacs-magit
|
|
:after (treemacs magit))
|
|
#+end_src
|
|
|
|
* Programming
|
|
|
|
** General settings
|
|
|
|
Auto balance parenthesese.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package smartparens
|
|
:ghook 'prog-mode-hook)
|
|
#+end_src
|
|
|
|
Rainbow delimiters FTW!
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package rainbow-delimiters
|
|
:ghook 'prog-mode-hook)
|
|
#+END_src
|
|
|
|
Paredit is a minor mode for editing parentheses
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package paredit
|
|
:hook (emacs-lisp-mode . paredit-mode)
|
|
(racket-mode . paredit-mode)
|
|
(racket-repl-mode . paredit-mode)
|
|
:general
|
|
(:keymaps 'paredit-mode-map
|
|
"{" 'paredit-open-curly
|
|
"}" 'paredit-close-curly
|
|
"M-[" 'paredit-wrap-square
|
|
"M-{" 'paredit-wrap-curly))
|
|
#+end_src
|
|
|
|
** Project management
|
|
|
|
Projectile works great to manage projects. It includes fuzzy search and supports jumping between files (e.g. .h <-> .cpp).
|
|
[[https://github.com/bbatsov/projectile][projectile GitHub page]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package projectile
|
|
:diminish projectile-mode
|
|
:config
|
|
;; (setq projectile-completion-system 'ivy)
|
|
(projectile-mode)
|
|
:general
|
|
(:prefix "C-c"
|
|
"p" '(:keymap projectile-command-map))
|
|
:init
|
|
(setq projectile-switch-project-action #'projectile-dired
|
|
projectile-project-search-path '("~/workspace" "~/workspace/horus" "~/workspace/horus/web" "~/workspace/horus/horus-vr")))
|
|
#+end_src
|
|
|
|
There is also an integration with counsel.
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package counsel-projectile
|
|
:after projectile
|
|
:general
|
|
("C-SPC" 'counsel-projectile-switch-project)
|
|
:config
|
|
(counsel-projectile-mode))
|
|
#+end_src
|
|
|
|
Enable [[https://github.com/BurntSushi/ripgrep][ripgrep]] support
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package rg
|
|
:after projectile
|
|
:config
|
|
(rg-enable-default-bindings))
|
|
#+end_src
|
|
|
|
** Git
|
|
|
|
Magit. Obviously.
|
|
[[https://magit.vc][magit website]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package magit
|
|
:config
|
|
;; (setq magit-completing-read-function 'ivy-completing-read)
|
|
:general
|
|
(:prefix my/leader
|
|
"g s" 'magit-status
|
|
"g x" 'magit-checkout
|
|
"g c" 'magit-commit
|
|
"g p" 'magit-push
|
|
"g u" 'magit-pull
|
|
"g e" 'magit-ediff-resolve
|
|
"g r" 'magit-rebase-interactive
|
|
"g i" 'magit-init))
|
|
#+end_src
|
|
|
|
transient can be used to create command dispatchers. Magit uses it to easily add options to git commands, and it displays a nice popup with the possible flags and commands.
|
|
[[https://magit.vc/manual/transient/][transient manual]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package transient)
|
|
#+end_src
|
|
|
|
Visualise git changes in the gutter, next to the line numbers
|
|
[[https://github.com/emacsorphanage/git-gutter][git-gutter GitHub page]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package git-gutter
|
|
:diminish t
|
|
:ghook
|
|
'prog-mode-hook
|
|
'org-mode-hook
|
|
:config
|
|
(setq git-gutter:update-interval 0.02))
|
|
|
|
(use-package git-gutter-fringe
|
|
:config
|
|
(define-fringe-bitmap 'git-gutter-fr:added [224] nil nil '(center repeated))
|
|
(define-fringe-bitmap 'git-gutter-fr:modified [224] nil nil '(center repeated))
|
|
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240] nil nil 'bottom))
|
|
#+end_src
|
|
|
|
** Syntax checking and highlighting
|
|
|
|
*** Flycheck
|
|
|
|
=Flycheck= is a general purpose syntax highlighting framework that provides hooks for other packages and an improvement of the builtin =flymake=.
|
|
[[https://www.flycheck.org][website]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package flycheck
|
|
:diminish t
|
|
:init
|
|
(global-flycheck-mode))
|
|
#+end_src
|
|
|
|
*** Tree-sitter
|
|
|
|
[[https://tree-sitter.github.io/][tree-sitter]] is a new development in parsing and syntax highlighting. It has been merged into Emacs 29, but until that's released we're using the [[https://emacs-tree-sitter.github.io/][emacs-tree-sitter]] package while on Emacs 28.
|
|
|
|
#+begin_src emacs-lisp
|
|
(when (< emacs-major-version 29)
|
|
(use-package tree-sitter
|
|
:config
|
|
(global-tree-sitter-mode)
|
|
:ghook
|
|
('tree-sitter-after-on-hook #'tree-sitter-hl-mode)))
|
|
#+end_src
|
|
|
|
[[https://github.com/emacs-tree-sitter/tree-sitter-langs][tree-sitter-langs]] provides =tree-sitter= support for a bunch of languages.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package tree-sitter-langs
|
|
:after tree-sitter)
|
|
#+end_src
|
|
|
|
*** LSP
|
|
|
|
[[https://emacs-lsp.github.io/lsp-mode][lsp-mode]] adds Language Server Protocol support to emacs.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package lsp-mode
|
|
:init
|
|
(setq lsp-keymap-prefix "C-c l"
|
|
lsp-use-plists nil)
|
|
(defun eb/lsp-mode-setup-completion ()
|
|
(setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
|
|
'(orderless)))
|
|
:hook ((conf-toml-mode
|
|
python-mode
|
|
sh-mode) . lsp-deferred)
|
|
(lsp-mode . lsp-enable-which-key-integration)
|
|
(lsp-completion-mode . eb/lsp-mode-setup-completion)
|
|
:commands
|
|
(lsp lsp-deferred)
|
|
:custom
|
|
(lsp-completion-provider :none) ;; I'm using corfu
|
|
:config
|
|
(setq lsp-typescript-surveys-enabled nil
|
|
lsp-completion-enable t
|
|
lsp-enable-suggest-server-download nil))
|
|
#+end_src
|
|
|
|
[[https://emacs-lsp.github.io/lsp-ui/][lsp-ui]] provides higher level UI elements for =lsp-mode=, like code lenses and flycheck support.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package lsp-ui
|
|
:ghook 'lsp-mode-hook
|
|
:config
|
|
(setq lsp-ui-doc-enable t
|
|
lsp-ui-peek-enable t
|
|
lsp-ui-sideline-enable t
|
|
lsp-ui-imenu-enable t)
|
|
:custom
|
|
(lsp-ui-doc-position 'bottom))
|
|
#+end_src
|
|
|
|
[[https://github.com/emacs-lsp/lsp-ivy][lsp-ivy]] integrates =ivy= into =lsp-mode=
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package lsp-ivy
|
|
:commands lsp-ivy-workspace-symbol)
|
|
#+end_src
|
|
|
|
[[https://github.com/gagbo/consult-lsp][consult-lsp]] integrates =consult= into =lsp-mode=
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package consult-lsp)
|
|
#+end_src
|
|
|
|
[[https://github.com/emacs-lsp/lsp-treemacs][lsp-treemacs]] provides an integration between =lsp-mode= and [[https://github.com/Alexander-Miller/treemacs][treemacs]].
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package lsp-treemacs
|
|
:commands lsp-treemacs-errors-list)
|
|
#+end_src
|
|
|
|
*** DAP
|
|
|
|
[[http://emacs-lsp.github.io/dap-mode][dap-mode]] provides debugging facilities using the [[https://microsoft.github.io/debug-adapter-protocol/][Debug Adapter Protocol]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package dap-mode
|
|
:defer t
|
|
:custom
|
|
(dap-auto-configure-mode t)
|
|
(dap-auto-configure-features '(sessions locals breakpoints expressions tooltip))
|
|
:config
|
|
(require 'dap-lldb)
|
|
(require 'dap-cpptools)
|
|
(setq dap-lldb-debugged-program-function (lambda () (read-file-name "Select program executable to debug")))
|
|
|
|
(dap-register-debug-template "C++ LLDB"
|
|
(list :type "lldb-vscode"
|
|
:dap-server-path (executable-find "lldb-vscode")
|
|
:cwd nil
|
|
:args nil
|
|
:request "launch"
|
|
:program nil))
|
|
(defun dap-debug-create-or-edit-json-template ()
|
|
"Edit C++ debugging configuration or create and edit if none exists"
|
|
(interactive)
|
|
(let ((filename (concat (lsp-workspace-root) "/launch.json"))
|
|
(default (concat user-emacs-directory "/default-launch.json")))
|
|
(unless (file-exists-p filename)
|
|
(copy-file default filename))
|
|
(find-file-existing filename))))
|
|
#+end_src
|
|
|
|
** Snippets
|
|
|
|
Snippets are predefined pieces of code that can be inserted and filled in. [[https://github.com/joaotavora/yasnippet][YASnippet]] uses syntax inspired by TextMate is the most popular, for good reason.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package yasnippet
|
|
:init
|
|
(load "yasnippet.el")
|
|
:diminish t
|
|
:general
|
|
(:keymaps 'yas-minor-mode-map
|
|
"<tab>" nil
|
|
"TAB" nil
|
|
"<C-tab>" 'yas-expand)
|
|
:config
|
|
(add-to-list 'yas-snippet-dirs my/snippets-dir)
|
|
(yas-global-mode))
|
|
|
|
(use-package yasnippet-snippets)
|
|
#+end_src
|
|
|
|
** Languages
|
|
|
|
*** JavaScript / TypeScript
|
|
|
|
Indent 2 spaces
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq-default js-indent-level 2
|
|
typescript-indent-level 2)
|
|
#+end_src
|
|
|
|
[[https://github.com/mooz/js2-mode/][js2-mode]] improves a lot on the builtin =js-mode=
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package js2-mode
|
|
:after lsp-mode
|
|
:mode
|
|
("\\.mjs\\'" . js2-mode)
|
|
("\\.jsx?\\'" . js2-jsx-mode)
|
|
:hook
|
|
(js2-mode . lsp-deferred)
|
|
(js2-jsx-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
Prettier has my preference for formatting JavaScript and TypeScript
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package prettier-js
|
|
:config
|
|
(setq prettier-js-args '("--single-quote" "true"))
|
|
:hook
|
|
(js2-mode . typescript-mode))
|
|
#+end_src
|
|
|
|
TypeScript stuff
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package typescript-mode
|
|
:after lsp-mode
|
|
:mode
|
|
("\\.tsx?\\'" . typescript-mode)
|
|
:hook (typescript-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
Prefer local packages from =node_modules= to global ones
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package add-node-modules-path)
|
|
#+end_src
|
|
|
|
*** Web mode
|
|
|
|
[[https://web-mode.org/][web-mode]] handles HTML/CSS and JavaScript
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package web-mode
|
|
:after lsp-mode
|
|
:config
|
|
(setq web-mode-markup-indent-offset 2
|
|
web-mode-css-indent-offset 2
|
|
web-mode-code-indent-offset 2
|
|
web-mode-enable-auto-pairing t
|
|
web-mode-enable-css-colorization t
|
|
web-mode-enable-current-element-highlight t
|
|
web-mode-enable-current-column-highlight t)
|
|
|
|
(add-to-list 'web-mode-engines-alist '(("elixir" . "\\.html.heex\\'")))
|
|
:hook
|
|
((html-mode css-mode web-mode) . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Markdown
|
|
|
|
[[https://jblevins.org/projects/markdown-mode/][markdown-mode]] adds support for Markdown editing. =gfm-mode= supports GitHub Flavoured Markdown.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package markdown-mode
|
|
:after lsp-mode
|
|
:mode
|
|
(("README\\.md\\'" . gfm-mode)
|
|
("\\.md\\'" . markdown-mode)
|
|
("\\.markdown\\'" . markdown-mode))
|
|
:init
|
|
(setq markdown-command "multimarkdown")
|
|
:hook
|
|
(markdown-mode . display-fill-column-indicator-mode)
|
|
(markdown-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Elixir
|
|
|
|
Add support for Elixir with [[https://github.com/elixir-editors/emacs-elixir][elixir-mode]]. The =elixir-format= hook sets up the correct formatter configuration when in a =projectile= project.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package elixir-mode
|
|
:after lsp-mode
|
|
:hook ((elixir-format . (lambda ()
|
|
(if (projectile-project-p)
|
|
(setq elixir-format-arguments
|
|
(list "--dot-formatter"
|
|
(concat (locate-dominating-file buffer-file-name ".formatter.exs") ".formatter.exs")))
|
|
(setq elixir-format-arguments nil))))
|
|
(elixir-mode . (lambda () (add-hook 'before-save-hook 'elixir-format nil t)))
|
|
(elixir-mode . lsp-deferred))
|
|
:config
|
|
(setq lsp-elixir-server-command '("elixir-ls"))
|
|
(add-to-list 'auto-mode-alist '("\\.[hl]eex\\'" . elixir-mode)))
|
|
#+end_src
|
|
|
|
Add a [[https://github.com/ayrat555/mix.el][mix]] minor mode to call =mix= tasks from emacs.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package mix
|
|
:hook
|
|
(elixir-mode . mix-minor-mode))
|
|
#+end_src
|
|
|
|
*** Erlang
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package erlang
|
|
:mode
|
|
("\\.P\\'" . erlang-mode)
|
|
("\\.E\\'" . erlang-mode)
|
|
("\\.S\\'" . erlang-mode)
|
|
:config
|
|
(require 'erlang-start))
|
|
#+end_src
|
|
|
|
*** Rust
|
|
|
|
Rust support with [[https://github.com/rust-lang/rust-mode][rust-mode]].
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package rust-mode
|
|
:after lsp-mode
|
|
:hook
|
|
(rust-mode . lsp-deferred)
|
|
(before-save . lsp-format-buffer)
|
|
(before-save . lsp-organize-imports)
|
|
:init
|
|
(setq lsp-rust-analyzer-cargo-watch-command "clippy"
|
|
lsp-rust-analyzer-server-display-inlay-hints t
|
|
lsp-rust-analyzer-binding-mode-hints t
|
|
lsp-rust-analyzer-display-lifetime-elision-hints-enable "always"))
|
|
#+end_src
|
|
|
|
Add [[https://github.com/kwrooijen/cargo.el][cargo]] support
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package cargo
|
|
:hook
|
|
(rust-mode . cargo-minor-mode))
|
|
#+end_src
|
|
|
|
Flycheck support for Rust with [[https://github.com/flycheck/flycheck-rust][flycheck-rust]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package flycheck-rust
|
|
:hook
|
|
(flycheck-mode . flycheck-rust-setup))
|
|
#+end_src
|
|
|
|
*** TOML
|
|
|
|
Support for TOML files with [[https://github.com/dryman/toml-mode.el][toml-mode]]
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package toml-mode
|
|
:mode ("\\.toml\\'" . conf-toml-mode))
|
|
#+end_src
|
|
|
|
*** Docker
|
|
|
|
Add docker support with [[https://github.com/spotify/dockerfile-mode][dockerfile-mode]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package dockerfile-mode
|
|
:after lsp-mode
|
|
:hook (dockerfile-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Bitbake / Yocto
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package bitbake-modes
|
|
:straight (:type git :repo "https://bitbucket.org/olanilsson/bitbake-modes.git"))
|
|
#+end_src
|
|
|
|
*** INI
|
|
|
|
=ini-mode= provides highlighting for ini files
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package ini-mode)
|
|
#+end_src
|
|
|
|
*** JSON
|
|
|
|
[[https://github.com/joshwnj/json-mode][json-mode]] extends the builtin =js-mode= with better syntax highlighting for JSON and adds some editing keybindings
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package json-mode
|
|
:after lsp-mode
|
|
:hook (json-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** CMake
|
|
|
|
Add [[https://melpa.org/#/cmake-mode][cmake-mode]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package cmake-mode
|
|
:after lsp-mode
|
|
:hook (cmake-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** YAML
|
|
|
|
Use [[https://github.com/yoshiki/yaml-mode][yaml-mode]] to handle YAML files
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package yaml-mode
|
|
:after lsp-mode
|
|
:hook (yaml-mode . lsp-deferred))
|
|
#+end_src
|
|
*** C/C++
|
|
|
|
Enable clangd LSP for C and C++
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package cc-mode
|
|
:ensure nil
|
|
:after lsp-mode
|
|
:hook
|
|
(c-mode . lsp-deferred)
|
|
(c++-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
Enable and configure =auto-insert-mode= for Horus projects
|
|
|
|
#+begin_src emacs-lisp
|
|
(defconst my/generate-cpp-file-executable
|
|
"~/workspace/horus/development/code-generation/generate-cpp-file.py"
|
|
"Python program to generate a C++ boilerplate")
|
|
|
|
(when (file-executable-p my/generate-cpp-file-executable)
|
|
(define-auto-insert
|
|
"\\.[ch]pp\\'"
|
|
(lambda nil (call-process my/generate-cpp-file-executable nil t nil buffer-file-name))))
|
|
|
|
|
|
(auto-insert-mode)
|
|
#+end_src
|
|
|
|
*** Meson
|
|
|
|
[[https://mesonbuild.com][meson]] is a build system designed to be as fast and as user-friendly as possible.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package meson-mode)
|
|
#+end_src
|
|
*** nix
|
|
|
|
Add [[https://github.com/NixOS/nix-mode][nix-mode]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package nix-mode
|
|
:after lsp-mode
|
|
:mode "\\.nix\\'"
|
|
:hook (nix-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Common Lisp
|
|
|
|
Common Lisp does not use =lsp-mode=, but has it's own environment: [[https://github.com/slime/slime][SLIME]] or Superior Lisp Interaction Mode for Emacs.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package slime
|
|
:init
|
|
(setq slime-lisp-implementations
|
|
'((sbcl ("sbcl" "--load ~/.quicklisp/setup.lisp") :coding-system utf-8-unix))
|
|
slime-default-lisp 'sbcl)
|
|
:config
|
|
(slime-setup '(slime-fancy slime-quicklisp slime-asdf))
|
|
:mode
|
|
(("\\.cl\\'" . lisp-mode))
|
|
:hook
|
|
(lisp-mode . (lambda () (slime-mode t)))
|
|
(inferior-lisp-mode . (lambda () (inferior-slime-mode t))))
|
|
#+end_src
|
|
*** Clojure
|
|
|
|
Similar to =lisp=, there is [[https://github.com/clojure-emacs/cider][CIDER]] (Clojure Interactive Development Environment that Rocks) for Clojure(Script)
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package cider)
|
|
#+end_src
|
|
*** Terraform
|
|
|
|
[[https://github.com/emacsorphanage/terraform-mode][terraform-mode]] is a major mode for Terraform files
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package terraform-mode
|
|
:after lsp-mode
|
|
:hook (terraform-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Fish
|
|
|
|
[[https://github.com/wwwjfy/emacs-fish][fish-mode]] provides a major mode for fish shell scripts
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package fish-mode
|
|
:init
|
|
(setq fish-enable-auto-indent t))
|
|
#+end_src
|
|
|
|
*** Zig
|
|
|
|
[[https://github.com/ziglang/zig-mode][zig-mode]] provides a major mode for the [[https://ziglang.org][zig programming language]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package zig-mode
|
|
:after lsp-mode
|
|
:hook (zig-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Yuck
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package yuck-mode)
|
|
#+end_src
|
|
|
|
*** Racket
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package racket-mode
|
|
:after lsp-mode
|
|
:hook (racket-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** Ruby
|
|
|
|
Let =ruby-mode= handle Ruby files
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package ruby-mode
|
|
:ensure nil
|
|
:after lsp-mode
|
|
:hook (ruby-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
*** MapServer
|
|
|
|
Add highlighting for MapServer .map files
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package mapserver-mode
|
|
:straight (:type git :host github :repo "AxxL/mapserver-emacs-mode")
|
|
:mode ("\\.map\\'" . mapserver-mode))
|
|
#+end_src
|
|
|
|
*** Go
|
|
|
|
It's better than nothing.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package go-mode
|
|
:after lsp-mode
|
|
:hook (go-mode . lsp-deferred))
|
|
#+end_src
|
|
|
|
* Org
|
|
|
|
** Main org setup
|
|
|
|
[[https://orgmode.org][org-mode]] configuration
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org
|
|
:general
|
|
<<org-binds>>
|
|
:custom
|
|
<<org-customisations>>
|
|
:hook
|
|
<<org-hooks>>
|
|
:config
|
|
<<org-config>>)
|
|
#+end_src
|
|
|
|
Some keybindings for often used functions
|
|
|
|
#+name: org-binds
|
|
#+begin_src emacs-lisp :tangle no
|
|
(:prefix my/leader
|
|
"r" 'org-capture
|
|
"a" 'org-agenda
|
|
"s" 'org-store-link
|
|
"L" 'org-store-link-global
|
|
"O" 'org-open-at-point-global)
|
|
#+end_src
|
|
|
|
Customisations
|
|
|
|
#+name: org-customisations
|
|
#+begin_src emacs-lisp :tangle no
|
|
(org-directory "~/org")
|
|
(org-log-done t)
|
|
(org-indent-indentation-per-level 2)
|
|
(org-startup-indented t)
|
|
(org-log-into-drawer t)
|
|
(org-default-notes-file (expand-file-name "notes.org" org-directory))
|
|
(org-return-follows-link t)
|
|
(org-pretty-entities t)
|
|
(org-hide-emphasis-markers t)
|
|
(org-startup-with-inline-images t)
|
|
(org-startup-with-latex-previews t)
|
|
(org-image-actual-width '(300))
|
|
#+end_src
|
|
|
|
Hooks
|
|
|
|
#+name: org-hooks
|
|
#+begin_src emacs-lisp :tangle no
|
|
((org-mode . org-indent-mode)
|
|
(org-mode . turn-on-visual-line-mode)
|
|
(org-mode . variable-pitch-mode)
|
|
(org-mode-indent . (lambda () (diminish 'org-indent-mode)))
|
|
(org-agenda-mode . (lambda () (hl-line-mode 1))))
|
|
#+end_src
|
|
|
|
Configuration
|
|
|
|
#+name: org-config
|
|
#+begin_src emacs-lisp :tangle no
|
|
(add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode))
|
|
(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.0)
|
|
(org-level-6 . 1.0)
|
|
(org-level-7 . 1.0)
|
|
(org-level-8 . 1.0)))
|
|
(set-face-attribute (car face) nil :family my/variable-width-font :weight 'medium :height (cdr face)))
|
|
(set-face-attribute 'org-document-title nil :family my/variable-width-font :weight 'bold :height 1.3)
|
|
(set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch)
|
|
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
|
|
(set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
|
|
(set-face-attribute 'org-code 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-checkbox nil :inherit 'fixed-pitch)
|
|
#+end_src
|
|
|
|
=org-capture= allows creating and saving quick notes, links and TODOs
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-capture
|
|
;; :straight org
|
|
:ensure org
|
|
:after org
|
|
:config
|
|
(setq org-capture-templates
|
|
'(("t" "Todo" entry (file+headline "gtd.org")
|
|
"* TODO %?\n %i\n %a")
|
|
("n" "Note" entry (file+olp+datetree "notes.org")
|
|
"* %?\nEntered on %U\n %i\n %a")
|
|
("N" "Note (work)" entry (file+olp+datetree "work/notes.org")
|
|
"* %?\nEntered on %U\n %i\n %a")
|
|
("c" "org-protocol-capture" entry (file+headline "inbox.org" "Links")
|
|
"* %^{Title}\n\n[[%:link][%:description]]\n\n %i"
|
|
:immediate-finish t))))
|
|
#+end_src
|
|
|
|
=org-datetree= allows you to organise captures by date. It is basically a set of headings representing the date, with the first level for the year, the second level for the month and the third for the day.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-datetree
|
|
;; :straight org
|
|
:ensure org
|
|
:after org)
|
|
#+end_src
|
|
|
|
=org-protocol= can be used to send data to emacs using =org-protocol://= URLs.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-protocol
|
|
;; :straight org
|
|
:ensure org
|
|
:after org
|
|
:config
|
|
(setq org-protocol-default-template-key "c"))
|
|
#+end_src
|
|
|
|
** org-roam
|
|
|
|
[[https://www.orgroam.com][org-roam]] helps with non-hierarchical note-taking. It uses the [[https://en.wikipedia.org/wiki/Zettelkasten][zettelkasten method]] to capture and organise notes and ideas.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-roam
|
|
;; :after org
|
|
:custom
|
|
(org-roam-directory "~/org-roam")
|
|
(org-roam-completion-everywhere t)
|
|
<<org-roam-templates>>
|
|
:config
|
|
(require 'org-roam-dailies)
|
|
(org-roam-db-autosync-mode)
|
|
:general
|
|
(:prefix my/leader
|
|
:keymaps 'global
|
|
"n f" 'org-roam-node-find
|
|
"n r" 'org-roam-node-random
|
|
"n i" 'org-roam-node-insert
|
|
"n l" 'org-roam-buffer-toggle
|
|
:keymaps 'org-mode-map
|
|
"n o" 'org-id-get-create
|
|
"n t" 'org-roam-tag-add
|
|
"n a" 'org-roam-alias-add
|
|
"n l" 'org-roam-buffer-toggle)
|
|
("C-M-i" 'completion-at-point
|
|
:keymaps 'org-roam-dailies-map
|
|
"Y" 'org-roam-dailies-capture-yesterday
|
|
"T" 'org-roam-dailies-capture-tomorrow)
|
|
|
|
(:prefix my/leader "n d" '(:keymap org-roam-dailies-map)))
|
|
#+end_src
|
|
|
|
Org roam capture templates
|
|
|
|
#+name: org-roam-templates
|
|
#+begin_src emacs-lisp :tangle no
|
|
(org-roam-capture-templates '(("d" "default" plain
|
|
"%?"
|
|
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+date: %U\n")
|
|
:unnarrowed t)
|
|
("w" "work note" plain
|
|
"%?"
|
|
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :work:\n")
|
|
:unnarrowed t)
|
|
("p" "project" plain
|
|
"* Goals\n\n%?\n\n* Tasks\n\n** TODO Add initial tasks\n\n* Dates\n\n"
|
|
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :project:\n")
|
|
:unnarrowed t)))
|
|
#+end_src
|
|
|
|
[[https://github.com/org-roam/org-roam-ui][org-roam-ui]] provides a frontend to explore and interact with =org-roam= notes. It can be started with =M-x org-roam-ui-mode RET=, and is then available on [[http://127.0.0.1:35901/]]. Updates are sent real-time through a WebSocket.
|
|
The settings provided here are also the defaults, set any to =nil= to disable.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-roam-ui
|
|
:after org-roam
|
|
: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))
|
|
#+end_src
|
|
|
|
* Misc
|
|
|
|
** direnv
|
|
|
|
[[https://github.com/purcell/envrc][envrc]] adds support for [[https://direnv.net][direnv]] to emacs. =envrc= works on a per-buffer basis, so when you open multiple projects the environments don't pollute eachother. NOTE: this should be loaded last.
|
|
|
|
#+name: envrc-init
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package envrc
|
|
:init
|
|
(envrc-global-mode)
|
|
:general
|
|
(:prefix my/leader "e" '(:keymap envrc-command-map)))
|
|
#+end_src
|
|
|
|
** Writing
|
|
|
|
Enable flyspell
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package flyspell
|
|
:ensure nil
|
|
:init
|
|
(setq ispell-list-command "--list")
|
|
:hook
|
|
(text-mode . flyspell-mode))
|
|
|
|
(use-package flyspell-correct
|
|
:after flyspell
|
|
:general
|
|
|
|
(:keymaps 'flyspell-mode-map
|
|
"C-;" 'flyspell-correct-wrapper))
|
|
#+end_src
|
|
|
|
Use ivy for flyspell suggestions. Use =M-o= to switch to the actions (e.g. saving a word to your dictionary).
|
|
|
|
#+begin_src emacs-lisp :tangle no
|
|
(use-package flyspell-correct-ivy
|
|
:after flyspell-correct)
|
|
#+end_src
|
|
|
|
** Load local init file
|
|
|
|
If =local-init.el= exists, load it.
|
|
|
|
#+begin_src emacs-lisp
|
|
(when (file-readable-p my/local-init-file)
|
|
(load my/local-init-file))
|
|
#+end_src
|
|
|
|
#+begin_comment
|
|
DO NOT ADD ANYTHING BELOW THIS
|
|
#+end_comment
|
|
|
|
#+begin_src emacs-lisp :exports none
|
|
<<envrc-init>>
|
|
#+end_src
|