957 lines
32 KiB
Org Mode
957 lines
32 KiB
Org Mode
#+TITLE: My Ever Changing Literate Emacs Configuration
|
|
#+AUTHOR: xulfer <xulfer at cheapbsd.net>
|
|
#+PROPERTY: header-args :tangle init.el :noweb yes :exports code
|
|
|
|
# For PDF export allow line wrapping.
|
|
#+LATEX_HEADER: \usepackage{listings}
|
|
#+LATEX_HEADER: \lstset{breaklines=true, breakatwhitespace=true, basicstyle=\ttfamily\footnotesize, columns=fullflexible}
|
|
|
|
#+begin_src emacs-lisp :exports none :tangle no
|
|
;; This asks for a file which it uses to store the processed org
|
|
;; data with the includes into. It can be anything and can safely
|
|
;; be deleted afterwards. I think README.org is a good file to
|
|
;; pick if using a repository.
|
|
(defun tangle-literate-config ()
|
|
"Tangle config files with proper include handling."
|
|
(interactive)
|
|
(let ((org-confirm-babel-evaluate nil))
|
|
;; Create a temporary buffer with expanded includes
|
|
(with-temp-buffer
|
|
(insert-file-contents "config.org")
|
|
(org-mode)
|
|
;; This expands all #+INCLUDE directives
|
|
(org-export-expand-include-keyword)
|
|
;; Now tangle from this buffer which has everything in one place
|
|
(org-babel-tangle nil "init.el"))
|
|
(message "Configuration tangled!")))
|
|
#+end_src
|
|
|
|
#+BEGIN_SRC emacs-lisp :exports none
|
|
;;; init.el -*- lexical-binding: t; -*-
|
|
|
|
;;; Code:
|
|
#+END_SRC
|
|
#+begin_src emacs-lisp :tangle early-init.el :exports none
|
|
;;; early-init.el -*- lexical-binding: t; -*-
|
|
|
|
;;; Code:
|
|
#+end_src
|
|
|
|
* Quick Look
|
|
|
|
[[./img/preview.png]]
|
|
|
|
Just the usual flex of doing as little editing as possible in a screenshot.
|
|
|
|
* Motivation
|
|
|
|
Over a surprisingly short amount of time my emacs configuration has become quite a mess.
|
|
Almost every visit to it requiring some digging to get to the relevant configuration. So
|
|
as a result I've decided to make a literate configuration. Mostly for my own mental
|
|
house keeping. However, if some poor soul reads this and finds it useful, then that's a
|
|
bonus.
|
|
|
|
** Inspirations, and sometimes outright copy/paste sources
|
|
- [[https://github.com/progfolio/.emacs.d][Progfolio's Config]]
|
|
|
|
* Initial Bits and Bobs
|
|
|
|
Before anything else the appearance, and some performance settings need to be tweaked as
|
|
they can cause issues if done mid-start.
|
|
|
|
** Initial setup
|
|
|
|
The LSP packages perform better with plists so an environment variable needs to be
|
|
set to inform them that this is intended. I've also removed default package handling
|
|
as I intend to use another package manager. Lastly I suppress some compilation
|
|
warnings.
|
|
|
|
#+begin_src emacs-lisp :tangle early-init.el
|
|
(setq package-enable-at-startup nil)
|
|
(setq inhibit-default-init nil)
|
|
|
|
(setq native-comp-async-report-warnings-errors nil)
|
|
(setenv "LSP_USE_PLISTS" "true")
|
|
(setq lsp-use-plists t)
|
|
#+end_src
|
|
|
|
** Appearance
|
|
|
|
I like a minimal look, so I disable menu bars, tool bars, all the bars. I have Emacs
|
|
loading as a blank slate with only the scratch buffer open.
|
|
|
|
#+begin_src emacs-lisp :tangle early-init.el
|
|
(defvar default-file-name-handler-alist file-name-handler-alist)
|
|
(setq file-name-handler-alist nil)
|
|
|
|
(push '(menu-bar-lines . 0) default-frame-alist)
|
|
(push '(tool-bar-lines . 0) default-frame-alist)
|
|
(push '(vertical-scroll-bars) default-frame-alist)
|
|
|
|
(setq server-client-instructions nil)
|
|
|
|
(when (and (fboundp 'startup-redirect-eln-cache)
|
|
(fboundp 'native-comp-available-p)
|
|
(native-comp-available-p))
|
|
(startup-redirect-eln-cache
|
|
(convert-standard-filename
|
|
(expand-file-name "var/eln-cache/" user-emacs-directory))))
|
|
|
|
(setq frame-inhibit-implied-resize t)
|
|
(advice-add #'x-apply-session-resources :override #'ignore)
|
|
(setq desktop-restore-forces-onscreen nil)
|
|
(setq ring-bell-function #'ignore
|
|
inhibit-startup-screen t)
|
|
|
|
(push '(font . "Victor Mono-13") default-frame-alist)
|
|
(set-face-font 'default "Victor Mono-13")
|
|
(set-face-font 'variable-pitch "Victor Mono-13")
|
|
|
|
(copy-face 'default 'fixed-pitch)
|
|
|
|
(provide 'early-init)
|
|
;;; early-init.el ends here
|
|
|
|
;; Local Variables:
|
|
;; no-byte-compile: t
|
|
;; no-native-compile: t
|
|
;; no-update-autoloads: t
|
|
;; End:
|
|
#+end_src
|
|
|
|
* Package Management
|
|
|
|
I am using [[https://github.com/progfolio/elpaca][Elpaca]] as my package manager. I've found it to be quite quick, and easy to
|
|
use.
|
|
|
|
#+name: elpaca-boilerplate
|
|
#+begin_src emacs-lisp :exports none :tangle no
|
|
(defvar elpaca-installer-version 0.11)
|
|
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
|
|
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
|
|
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
|
|
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
|
|
:ref nil :depth 1 :inherit ignore
|
|
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
|
|
:build (:not elpaca--activate-package)))
|
|
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
|
|
(build (expand-file-name "elpaca/" elpaca-builds-directory))
|
|
(order (cdr elpaca-order))
|
|
(default-directory repo))
|
|
(add-to-list 'load-path (if (file-exists-p build) build repo))
|
|
(unless (file-exists-p repo)
|
|
(make-directory repo t)
|
|
(when (<= emacs-major-version 28) (require 'subr-x))
|
|
(condition-case-unless-debug err
|
|
(if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
|
|
((zerop (apply #'call-process `("git" nil ,buffer t "clone"
|
|
,@(when-let* ((depth (plist-get order :depth)))
|
|
(list (format "--depth=%d" depth) "--no-single-branch"))
|
|
,(plist-get order :repo) ,repo))))
|
|
((zerop (call-process "git" nil buffer t "checkout"
|
|
(or (plist-get order :ref) "--"))))
|
|
(emacs (concat invocation-directory invocation-name))
|
|
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
|
|
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
|
|
((require 'elpaca))
|
|
((elpaca-generate-autoloads "elpaca" repo)))
|
|
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
|
|
(error "%s" (with-current-buffer buffer (buffer-string))))
|
|
((error) (warn "%s" err) (delete-directory repo 'recursive))))
|
|
(unless (require 'elpaca-autoloads nil t)
|
|
(require 'elpaca)
|
|
(elpaca-generate-autoloads "elpaca" repo)
|
|
(let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
|
|
(add-hook 'after-init-hook #'elpaca-process-queues)
|
|
(elpaca `(,@elpaca-order))
|
|
|
|
(if debug-on-error
|
|
(setq use-package-verbose t
|
|
use-package-expand-minimally nil
|
|
use-package-compute-statistics t)
|
|
(setq use-package-verbose nil
|
|
use-package-expand-minimally t))
|
|
#+end_src
|
|
|
|
Elpaca supports =use-package= so hook that up, and add a =use-feature= macro
|
|
that adds a similar construct for configuring already loaded emacs packages and
|
|
features.
|
|
|
|
#+begin_src emacs-lisp
|
|
<<elpaca-boilerplate>>
|
|
|
|
(defmacro use-feature (name &rest args)
|
|
"Like `use-package' but accounting for asynchronous installation.
|
|
NAME and ARGS are in `use-package'."
|
|
(declare (indent defun))
|
|
`(use-package ,name
|
|
:ensure nil
|
|
,@args))
|
|
|
|
(elpaca elpaca-use-package
|
|
(require 'elpaca-use-package)
|
|
(elpaca-use-package-mode)
|
|
(setq use-package-always-ensure t))
|
|
#+end_src
|
|
|
|
#+INCLUDE: "config/editing.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/gc.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/tidy.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/auth.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/profiling.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/general.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/formatting.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/documentation.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/social.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/modal.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/qol.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/bufferlo.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/error.org" :minlevel 1
|
|
|
|
#+INCLUDE: "config/error.org" :minlevel 1
|
|
|
|
* Modern Completion Stack
|
|
|
|
I'm using modern to mean current, and as the colloquial usage given by the
|
|
community at large. At least based on my observations anyway. Most of these
|
|
serve to bolster the existing facilities of emacs rather than replace them.
|
|
|
|
** Prescient
|
|
|
|
[[https://github.com/radian-software/prescient.el][Prescient]] provides sorting for completion candidates; So recently used, and
|
|
frequent selections come first.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package prescient
|
|
:defer t
|
|
:config
|
|
(prescient-persist-mode))
|
|
|
|
(use-package corfu-prescient
|
|
:after (corfu prescient)
|
|
:config (corfu-prescient-mode))
|
|
|
|
(use-package vertico-prescient
|
|
:after (prescient vertico))
|
|
#+end_src
|
|
|
|
** Corfu
|
|
|
|
[[https://github.com/minad/corfu][Corfu]] provides completion within buffers from various sources. Though it
|
|
doesn't provide much in the way of sources itself. It works in conjunction
|
|
with the other packages in this section to provide it with candidates.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package corfu
|
|
:custom
|
|
(corfu-auto t) ;; Enable auto completion
|
|
(corfu-preselect 'directory) ;; Select the first candidate, except for directories
|
|
|
|
:init
|
|
(global-corfu-mode)
|
|
(corfu-popupinfo-mode) ;; Show docs next to candidates.
|
|
|
|
:config
|
|
;; Free the RET key for less intrusive behavior.
|
|
;; Option 1: Unbind RET completely
|
|
;; (keymap-unset corfu-map "RET")
|
|
;; Option 2: Use RET only in shell modes
|
|
(keymap-set corfu-map "RET" `( menu-item "" nil :filter
|
|
,(lambda (&optional _)
|
|
(and (derived-mode-p 'eshell-mode 'comint-mode)
|
|
#'corfu-send)))))
|
|
#+end_src
|
|
|
|
** Cape
|
|
|
|
The [[https://github.com/minad/cape][Cape]] package (Completion At Point Extensions) provides access to [[https://github.com/minad/corfu][Corfu]]
|
|
to various backends. Things like file completions and simple buffer
|
|
completion are examples of good backends to add here. Other backends
|
|
are listed [[https://github.com/minad/cape#available-capfs][here]].
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package cape
|
|
:bind ("M-<tab>" . cape-prefix-map)
|
|
:init
|
|
(add-hook 'completion-at-point-functions #'cape-dabbrev)
|
|
(add-hook 'completion-at-point-functions #'cape-file)
|
|
(add-hook 'completion-at-point-functions #'cape-elisp-block))
|
|
#+end_src
|
|
|
|
** Orderless
|
|
|
|
This provides numerous flexible methods for matching completion candidates.
|
|
Rather than just matching strings exactly it can also match portions, or
|
|
a custom regular expression, and more.
|
|
|
|
[[https://stable.melpa.org/#/orderless][Link]]
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package orderless
|
|
:ensure t
|
|
:custom
|
|
(completion-styles '(orderless basic))
|
|
(completion-category-defaults nil)
|
|
(completion-category-overrides '((file (styles partial-completion)))))
|
|
#+end_src
|
|
|
|
** Vertico
|
|
|
|
[[https://github.com/minad/vertico][Vertico]] is one of the *best* minibuffer improvement packages out there. Combined
|
|
with the other packages in this section it makes minibuffer completions concise,
|
|
and descriptive.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package vertico
|
|
:demand t
|
|
:custom (vertico-cycle t)
|
|
:config
|
|
(setf (car vertico-multiline) "\n") ;; don't replace newlines
|
|
(vertico-mode)
|
|
(vertico-prescient-mode)
|
|
(define-key vertico-map (kbd "C-h") #'+minibuffer-up-dir))
|
|
#+end_src
|
|
|
|
** Marginalia
|
|
|
|
[[https://github.com/minad/marginalia][Marginalia]] adds completion annotations on the right side of the minibuffer.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package marginalia
|
|
:defer 2
|
|
:config (marginalia-mode)
|
|
(setf (alist-get 'elpaca-info marginalia-command-categories) 'elpaca))
|
|
#+end_src
|
|
|
|
** Consult
|
|
|
|
#+begin_quote
|
|
[[https://github.com/minad/consult][Consult]] provides search and navigation commands based on the emacs completion
|
|
function completing-read.
|
|
#+end_quote
|
|
|
|
Think about this as a tightly integrate search that can tie into many aspects
|
|
of a project, and convey the results to various completion facilities.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package consult
|
|
:ensure t
|
|
:bind (;; C-c bindings in `mode-specific-map'
|
|
("C-c M-x" . consult-mode-command)
|
|
("C-c h" . consult-history)
|
|
("C-c k" . consult-kmacro)
|
|
("C-c m" . consult-man)
|
|
("C-c i" . consult-info)
|
|
([remap Info-search] . consult-info)
|
|
;; C-x bindings in `ctl-x-map'
|
|
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
|
|
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
|
|
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
|
|
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
|
|
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
|
|
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
|
|
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
|
|
;; Custom M-# bindings for fast register access
|
|
("M-#" . consult-register-load)
|
|
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
|
|
("C-M-#" . consult-register)
|
|
;; Other custom bindings
|
|
("M-y" . consult-yank-pop) ;; orig. yank-pop
|
|
;; M-g bindings in `goto-map'
|
|
("M-g e" . consult-compile-error)
|
|
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
|
|
("M-g g" . consult-goto-line) ;; orig. goto-line
|
|
("M-g M-g" . consult-goto-line) ;; orig. goto-line
|
|
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
|
|
("M-g m" . consult-mark)
|
|
("M-g k" . consult-global-mark)
|
|
("M-g i" . consult-imenu)
|
|
("M-g I" . consult-imenu-multi)
|
|
;; M-s bindings in `search-map'
|
|
("M-s d" . consult-find) ;; Alternative: consult-fd
|
|
("M-s c" . consult-locate)
|
|
("M-s g" . consult-grep)
|
|
("M-s G" . consult-git-grep)
|
|
("M-s r" . consult-ripgrep)
|
|
("M-s l" . consult-line)
|
|
("M-s L" . consult-line-multi)
|
|
("M-s k" . consult-keep-lines)
|
|
("M-s u" . consult-focus-lines)
|
|
;; Isearch integration
|
|
("M-s e" . consult-isearch-history)
|
|
:map isearch-mode-map
|
|
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
|
|
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
|
|
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
|
|
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
|
|
;; Minibuffer history
|
|
:map minibuffer-local-map
|
|
("M-s" . consult-history) ;; orig. next-matching-history-element
|
|
("M-r" . consult-history)) ;; orig. previous-matching-history-element
|
|
|
|
;; Enable automatic preview at point in the *Completions* buffer. This is
|
|
;; relevant when you use the default completion UI.
|
|
:hook (completion-list-mode . consult-preview-at-point-mode)
|
|
|
|
;; The :init configuration is always executed (Not lazy)
|
|
:init
|
|
|
|
;; Tweak the register preview for `consult-register-load',
|
|
;; `consult-register-store' and the built-in commands. This improves the
|
|
;; register formatting, adds thin separator lines, register sorting and hides
|
|
;; the window mode line.
|
|
(advice-add #'register-preview :override #'consult-register-window) (setq register-preview-delay 0.5)
|
|
|
|
;; Use Consult to select xref locations with preview
|
|
(setq xref-show-xrefs-function #'consult-xref
|
|
xref-show-definitions-function #'consult-xref)
|
|
|
|
;; Configure other variables and modes in the :config section,
|
|
;; after lazily loading the package.
|
|
:config
|
|
|
|
;; Optionally configure preview. The default value
|
|
;; is 'any, such that any key triggers the preview.
|
|
;; (setq consult-preview-key 'any)
|
|
;; (setq consult-preview-key "M-.")
|
|
;; (setq consult-preview-key '("S-<down>" "S-<up>"))
|
|
;; For some commands and buffer sources it is useful to configure the
|
|
;; :preview-key on a per-command basis using the `consult-customize' macro.
|
|
(consult-customize
|
|
consult-theme :preview-key '(:debounce 0.2 any)
|
|
consult-ripgrep consult-git-grep consult-grep consult-man
|
|
consult-bookmark consult-recent-file consult-xref
|
|
consult--source-bookmark consult--source-file-register
|
|
consult--source-recent-file consult--source-project-recent-file
|
|
;; :preview-key "M-."
|
|
:preview-key '(:debounce 0.4 any))
|
|
|
|
;; Optionally configure the narrowing key.
|
|
;; Both < and C-+ work reasonably well.
|
|
(setq consult-narrow-key "<") ;; "C-+"
|
|
|
|
;; Optionally make narrowing help available in the minibuffer.
|
|
;; You may want to use `embark-prefix-help-command' or which-key instead.
|
|
;; (keymap-set consult-narrow-map (concat consult-narrow-key " ?") #'consult-narrow-help)
|
|
)
|
|
#+end_src
|
|
=======
|
|
#+INCLUDE: "config/completion.org" :minlevel 1
|
|
>>>>>>> caf7087 (Moved completion section into its own file.)
|
|
|
|
* Files
|
|
|
|
I've been increasingly using [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][dired]], and [[https://github.com/alexluigit/dirvish][dirvish]] to handle files for a while now.
|
|
At times it can be a bit cumbersome, but with time it could easily be all I need.
|
|
|
|
** Dired
|
|
|
|
I mostly just modify the dired list command switches, and have [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][dired]] open new
|
|
directories in the same buffer. This comes with some benefits, and drawbacks but
|
|
for now it seems to work best this way.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-feature dired
|
|
:commands (dired)
|
|
:custom
|
|
(dired-listing-switches
|
|
"-l --almost-all --human-readable --group-directories-first --no-group")
|
|
:config
|
|
(put 'dired-find-alternate-file 'disabled nil))
|
|
#+end_src
|
|
|
|
** Dirvish
|
|
|
|
[[https://github.com/alexluigit/dirvish][Dirvish]] is a very exceptional [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][dired]] enhancement. With this package one can
|
|
have similar functionality to vifm, yazi, and so on all within the comfort
|
|
of emacs. I have most of the comforts enabled here; however they come with
|
|
certain dependencies. It will function without them however.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package dirvish
|
|
:ensure t
|
|
:init
|
|
(dirvish-override-dired-mode)
|
|
:custom
|
|
(dirvish-quick-access-entries ; It's a custom option, `setq' won't work
|
|
'(("h" "~/" "Home")
|
|
("d" "~/Downloads/" "Downloads")
|
|
("s" "/ssh:192.168.88.1" "SSH server")))
|
|
:config
|
|
(dirvish-peek-mode) ; Preview files in minibuffer
|
|
(dirvish-side-follow-mode) ; similar to `treemacs-follow-mode'
|
|
(setq dirvish-mode-line-format
|
|
'(:left (sort symlink) :right (omit yank index)))
|
|
(setq dirvish-attributes ; The order *MATTERS* for some attributes
|
|
'(vc-state subtree-state nerd-icons collapse git-msg file-time file-size)
|
|
dirvish-side-attributes
|
|
'(vc-state nerd-icons collapse file-size))
|
|
;; open large directory (over 20000 files) asynchronously with `fd' command
|
|
(setq dirvish-large-directory-threshold 20000)
|
|
|
|
(setq insert-directory-program
|
|
(if (eq system-type 'gnu/linux)
|
|
"ls"
|
|
"gls"))
|
|
|
|
:bind ; Bind `dirvish-fd|dirvish-side|dirvish-dwim' as you see fit
|
|
(("C-c f" . dirvish)
|
|
:map dirvish-mode-map ; Dirvish inherits `dired-mode-map'
|
|
(";" . dired-up-directory) ; So you can adjust `dired' bindings here
|
|
("?" . dirvish-dispatch) ; [?] a helpful cheatsheet
|
|
("a" . dirvish-setup-menu) ; [a]ttributes settings:`t' toggles mtime, `f' toggles fullframe, etc.
|
|
("f" . dirvish-file-info-menu) ; [f]ile info
|
|
("o" . dirvish-quick-access) ; [o]pen `dirvish-quick-access-entries'
|
|
("s" . dirvish-quicksort) ; [s]ort flie list
|
|
("r" . dirvish-history-jump) ; [r]ecent visited
|
|
("l" . dirvish-ls-switches-menu) ; [l]s command flags
|
|
("v" . dirvish-vc-menu) ; [v]ersion control commands
|
|
("*" . dirvish-mark-menu)
|
|
("y" . dirvish-yank-menu)
|
|
("N" . dirvish-narrow)
|
|
("^" . dirvish-history-last)
|
|
("TAB" . dirvish-subtree-toggle)
|
|
("M-f" . dirvish-history-go-forward)
|
|
("M-b" . dirvish-history-go-backward)
|
|
("M-e" . dirvish-emerge-menu)))
|
|
#+end_src
|
|
|
|
** Diredfl
|
|
|
|
This package just adds a bit of color to dired output. Looks good, but nothing
|
|
too fancy.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package diredfl
|
|
:after (dired dirvish)
|
|
:ensure t
|
|
:hook
|
|
(dired-mode-hook . diredfl-mode)
|
|
(dirvish-directory-view-mode . diredfl-mode)
|
|
:config
|
|
(set-face-attribute 'diredfl-dir-name nil :bold t))
|
|
#+end_src
|
|
|
|
** Projects
|
|
|
|
I use [[https://github.com/bbatsov/projectile][Projectile]] for project management. It provides everything I need in a fairly
|
|
small, logical key map.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package projectile
|
|
:ensure t
|
|
:init
|
|
(setq projectile-project-search-path '(("~/Project" . 3)))
|
|
:config
|
|
(define-key projectile-mode-map (kbd "C-c C-p") 'projectile-command-map)
|
|
(global-set-key (kbd "C-c p") 'projectile-command-map)
|
|
(projectile-mode +1))
|
|
#+end_src
|
|
|
|
** Helpful Settings
|
|
|
|
I have some settings for tidying up files on save, and keeping backup files
|
|
together.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-feature files
|
|
;;:hook
|
|
;;(before-save . delete-trailing-whitespace)
|
|
:config
|
|
;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
|
|
(defun rename-file-and-buffer (new-name)
|
|
"Renames both current buffer and file it's visiting to NEW-NAME."
|
|
(interactive "sNew name: ")
|
|
(let ((name (buffer-name))
|
|
(filename (buffer-file-name)))
|
|
(if (not filename)
|
|
(message "Buffer '%s' is not visiting a file." name)
|
|
(if (get-buffer new-name)
|
|
(message "A buffer named '%s' already exists." new-name)
|
|
(progn
|
|
(rename-file filename new-name 1)
|
|
(rename-buffer new-name)
|
|
(set-visited-file-name new-name)
|
|
(set-buffer-modified-p nil))))))
|
|
:custom
|
|
(require-final-newline t "Automatically add newline at end of file")
|
|
(backup-by-copying t)
|
|
(delete-old-versions t)
|
|
(kept-new-versions 10)
|
|
(kept-old-versions 5)
|
|
(version-control t)
|
|
(safe-local-variable-values
|
|
'((eval load-file "./init-dev.el")
|
|
(org-clean-refile-inherit-tags))
|
|
"Store safe local variables here instead of in emacs-custom.el"))
|
|
#+end_src
|
|
|
|
* Terminal
|
|
|
|
I've been using [[https://codeberg.org/akib/emacs-eat][eat]] (Emulate A Terminal) in place of vterm lately as it has
|
|
better emacs integration without too big of a performance hit. It doesn't
|
|
handle fancy terminal applications quite as well, but so far has performed
|
|
well.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package eat
|
|
:ensure (:type git
|
|
:host codeberg
|
|
:repo "akib/emacs-eat"
|
|
:files ("*.el" ("term" "term/*.el") "*.texi"
|
|
"*.ti" ("terminfo/e" "terminfo/e/*")
|
|
("terminfo/65" "terminfo/65/*")
|
|
("integration" "integration/*")
|
|
(:exclude ".dir-locals.el" "*-tests.el")))
|
|
:hook
|
|
(eat-mode-hook . eat-char-mode)
|
|
(eshell-load-hook . eat-eshell-mode)
|
|
(eshell-load-hook . eat-eshell-visual-command-mode)
|
|
:custom
|
|
(eat-kill-buffer-on-exit t)
|
|
:config
|
|
(setopt eat-shell-prompt-annotation-delay 0)
|
|
(setopt eat-very-visible-cursor-type '(t nil nil))
|
|
(setopt eat-default-cursor-type '(t nil nil))
|
|
(setq process-adaptive-read-buffering nil)
|
|
(setq read-process-output-max (* 4 1024 1024))
|
|
;; Compile terminfo if needed
|
|
(eat-compile-terminfo))
|
|
#+end_src
|
|
|
|
Many of these settings are there to reduce flickering. They may not be needed
|
|
long term.
|
|
|
|
* Look and Feel
|
|
|
|
I've already touched on some appearance settings so far, but I feel themes and
|
|
such deserve their own space.
|
|
|
|
** Themes
|
|
|
|
I'm currently only using solarized light as it seems to be the most readable
|
|
theme. Perhaps I might toggle light/dark mode based on time, or lighting in
|
|
the future.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package color-theme-solarized
|
|
:ensure (:host github
|
|
:repo "sellout/emacs-color-theme-solarized"
|
|
:files ("*.el"))
|
|
:no-require t
|
|
:init
|
|
(customize-set-variable 'frame-background-mode 'dark)
|
|
(load-theme 'solarized t))
|
|
#+end_src
|
|
|
|
I like using catppuccin from time to time as well.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package catppuccin-theme :ensure t)
|
|
#+end_src
|
|
|
|
** Modeline
|
|
|
|
Doom emacs has a great modeline in my opinion so I'm using theirs almost
|
|
as is. It comes with some pretty nice customization features should it be
|
|
necessary.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package doom-modeline
|
|
:defer 2
|
|
:config
|
|
(doom-modeline-mode)
|
|
:custom
|
|
(doom-modeline-time-analogue-clock nil)
|
|
(doom-modeline-time-icon nil)
|
|
(doom-modeline-unicode-fallback nil)
|
|
(doom-modeline-buffer-encoding 'nondefault)
|
|
(display-time-load-average nil)
|
|
(doom-modeline-icon t "Show icons in the modeline"))
|
|
#+end_src
|
|
|
|
* VCS
|
|
|
|
When it comes to git, (which is all that's configured for now), the easy
|
|
choice is [[https://magit.vc/][Magit]]. I've kept the configuration pretty minimal. Only adding
|
|
forge support really.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package magit
|
|
:defer t
|
|
:custom
|
|
(magit-repository-directories (list (cons elpaca-repos-directory 1)))
|
|
(magit-diff-refine-hunk 'all)
|
|
:config
|
|
(transient-bind-q-to-quit))
|
|
|
|
(use-package forge
|
|
:after (magit))
|
|
#+end_src
|
|
|
|
* Language Server Protocol
|
|
|
|
LSP can be quite helpful for completions that are non-trivial. There are many
|
|
flavors of LSP for Emacs, but I'm only familiar with eglot, and [[https://emacs-lsp.github.io/lsp-mode/#language-server-protocol-support-for-emacs][lsp-mode]]. Eglot
|
|
is built into emacs core now, and uses other built in component well. However
|
|
lsp-mode has some extra features that I think are worth having while also
|
|
performing pretty well. Plus it uses packages that I already add even without
|
|
the package.
|
|
|
|
#+begin_src emacs-lisp
|
|
;; LSP
|
|
(use-package lsp-mode
|
|
:init
|
|
;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
|
|
(setq lsp-keymap-prefix "C-c l")
|
|
:hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode)
|
|
(c-ts-mode . lsp-deferred)
|
|
(clojure-ts-mode . lsp-deferred)
|
|
(elixir-ts-mode . lsp-deferred)
|
|
(gleam-ts-mode . lsp-deferred)
|
|
(python-ts-mode . lsp-deferred)
|
|
(rust-ts-mode . lsp-deferred)
|
|
(slint-mode . lsp-deferred)
|
|
(zig-mode . lsp-deferred)
|
|
;; if you want which-key integration
|
|
(lsp-mode . lsp-enable-which-key-integration))
|
|
:commands lsp-deferred
|
|
:config
|
|
(setq lsp-elixir-server-command '("elixir-ls")))
|
|
|
|
;; optionally
|
|
(use-package lsp-ui :commands lsp-ui-mode)
|
|
#+end_src
|
|
|
|
* Tree Sitter
|
|
|
|
Tree sitter is included with emacs, but there are a couple of packages that
|
|
make managing tree sitter easier. Mainly with automatically updating, and
|
|
using tree sitter versions of major modes, and installing the parsers if
|
|
needed.
|
|
|
|
#+begin_src emacs-lisp
|
|
;; Treesit
|
|
(setq treesit-language-source-alist
|
|
'((rust "https://github.com/tree-sitter/tree-sitter-rust")))
|
|
|
|
(use-package treesit-auto
|
|
:custom
|
|
(treesit-auto-install 'prompt)
|
|
:config
|
|
(treesit-auto-add-to-auto-mode-alist 'all)
|
|
(global-treesit-auto-mode))
|
|
|
|
(use-package treesit-fold
|
|
:ensure t
|
|
:defer t)
|
|
#+end_src
|
|
|
|
* Major Modes
|
|
|
|
I use quite a few major modes. Mostly those using tree-sitter; Which should
|
|
be selected automatically. As most of these are pretty straight forward I won't
|
|
bother with an explanation on each.
|
|
|
|
#+begin_src emacs-lisp
|
|
;; Markdown
|
|
(use-package markdown-mode
|
|
:ensure t
|
|
:mode ("\\.md\\'" . gfm-mode)
|
|
:init (setq markdown-command "multimarkdown")
|
|
:bind (:map markdown-mode-map
|
|
("C-c C-e" . markdown-do)))
|
|
|
|
(use-package slint-mode
|
|
:defer t
|
|
:config
|
|
(add-to-list 'auto-mode-alist '("\\.slint\\'" . slint-mode)))
|
|
|
|
(use-package zig-mode
|
|
:defer t
|
|
:config
|
|
(add-to-list 'auto-mode-alist '("\\.\\(zig\\|zon\\)\\'" . zig-mode)))
|
|
|
|
(use-package rainbow-mode
|
|
:commands (rainbow-mode))
|
|
|
|
;; Clojure
|
|
(use-package clojure-ts-mode
|
|
:ensure t
|
|
:hook
|
|
((clojure-ts-mode . cider-mode)
|
|
(clojure-ts-mode . rainbow-delimiters-mode)
|
|
(clojure-ts-mode . clj-refactor-mode)))
|
|
|
|
;; Gleam
|
|
(use-package gleam-ts-mode
|
|
:mode (rx ".gleam" eos))
|
|
|
|
(use-package cider
|
|
:ensure t
|
|
:defer t)
|
|
|
|
(use-package inf-elixir
|
|
:defer t)
|
|
|
|
;; Go
|
|
(use-package go-mode
|
|
:demand t
|
|
:mode "\\.go\\'")
|
|
|
|
;; Meson
|
|
(use-package meson-mode
|
|
:demand t
|
|
:mode "\\.build\\'")
|
|
|
|
;; rust-mode
|
|
(use-package rust-mode
|
|
:ensure t
|
|
:init
|
|
(setq rust-mode-treesitter-derive t))
|
|
|
|
(use-package rustic
|
|
:ensure (:host github :repo "emacs-rustic/rustic")
|
|
:after (rust-ts-mode)
|
|
:config
|
|
(setq rustic-cargo-clippy-trigger-fix 'on-compile
|
|
rustic-rustfmt-args "+nightly"))
|
|
|
|
;; Scheme
|
|
(use-package geiser-chez :ensure t)
|
|
|
|
#+end_src
|
|
|
|
* Org Mode
|
|
|
|
Org mode is a handy note taking, todo list managing, journal writing, and literate
|
|
programming tool among other things. I use it for writing some of my configurations,
|
|
and managing my notes.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-feature org
|
|
:defer t
|
|
:config
|
|
(setq org-confirm-babel-evaluate nil)
|
|
:custom
|
|
(org-ellipsis (nth 5 '("↴" "˅" "…" " ⬙" " ▽" "▿")))
|
|
(org-priority-lowest ?D)
|
|
(org-fontify-done-headline t)
|
|
(global-set-key (kbd "C-c l") #'org-store-link)
|
|
(global-set-key (kbd "C-c a") #'org-agenda)
|
|
(global-set-key (kbd "C-c c") #'org-capture))
|
|
#+end_src
|
|
|
|
** Htmlize
|
|
|
|
The [[https://github.com/emacsorphanage/htmlize/blob/master/htmlize.el#start-of-content][htmlize]] package enables exporting org documents, and other buffers into HTML
|
|
format.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package htmlize
|
|
:after (org)
|
|
:defer t)
|
|
#+end_src
|
|
|
|
** Org Modern
|
|
|
|
[[https://github.com/minad/org-modern][org-modern]] provides a cleaner representation of org documents while being
|
|
edited. It displays the intended formatting without all the markup.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-modern
|
|
:after (org)
|
|
:config
|
|
(global-org-modern-mode)
|
|
(remove-hook 'org-agenda-finalize-hook 'org-modern-agenda))
|
|
#+end_src
|
|
|
|
** Literate Tools
|
|
|
|
These are packages useful for literate programming, and its presentation. Though
|
|
not necessarily exlusive to literate programming as they can improve the look of
|
|
most any org document.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-feature ob-tangle
|
|
:after (org)
|
|
:custom
|
|
(org-src-window-setup 'current-window)
|
|
(org-src-preserve-indentation t))
|
|
|
|
;; Maybe unnecessary... I'll see.
|
|
(use-package org-contrib)
|
|
|
|
(use-package org-make-toc
|
|
:commands (org-make-toc))
|
|
#+end_src
|
|
|
|
** Note Taking
|
|
Org-roam is my go to for note taking. While out of the box it isn't quite as snazzy
|
|
as something like Obsidian it does offer a lot of flexibility that no other note
|
|
taking tool has.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package org-roam
|
|
:after (org)
|
|
:ensure t
|
|
:bind (("C-c n l" . org-roam-buffer-toggle)
|
|
("C-c n f" . org-roam-node-find)
|
|
("C-c n i" . org-roam-node-insert))
|
|
:config
|
|
(setq org-roam-directory "~/Documents/org-roam"
|
|
org-roam-dailies-directory "daily/")
|
|
|
|
(setq org-roam-capture-templates
|
|
'(("d" "default plain" plain
|
|
"%?"
|
|
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
|
|
"#+title: ${title}\n"))
|
|
("D" "default encrypted" plain
|
|
"%?"
|
|
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org.gpg"
|
|
"#+title: ${title}\n"))))
|
|
|
|
(setq org-roam-dailies-capture-templates
|
|
'(("d" "default" plain
|
|
"%?"
|
|
:target (file+head "%<%Y-%m-%d>.org"
|
|
"#+title: %<%Y-%m-%d>\n\n* Tasks\n\n* Notes"))))
|
|
|
|
(org-roam-db-autosync-mode))
|
|
|
|
(use-package orgmdb
|
|
:ensure t)
|
|
|
|
(use-package org-roam-ui
|
|
:after (org-roam)
|
|
:ensure t
|
|
: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
|
|
|
|
#+INCLUDE: "config/custom.org" :minlevel 1
|
|
|
|
#+begin_src emacs-lisp :exports none
|
|
(maybe-load-rel "custom.el")
|
|
|
|
(provide 'init)
|
|
;;; init.el ends here
|
|
|
|
#+end_src
|