flocon/dot_emacs.d/README.org
2024-07-17 03:03:35 +02:00

14 KiB

Emacs literate configuration

Packages initialization

Here, we're initializing MELPA, as well as package.el and use-package.

  (require 'package)
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  ;; Comment/uncomment this line to enable MELPA Stable if desired.  See `package-archive-priorities`
  ;; and `package-pinned-packages`. Most users will not need or want to do this.
  ;;(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)

  (unless package-archive-contents
    (package-refresh-contents))

  (require 'use-package)
  (setq use-package-always-ensure t)

vc-use-package

vc-use-package integrates package-vc-install, which allows installing packages from git repositories, into use-package. It won't be needed from Emacs 30, as it will integrate natively.

  (if (< emacs-major-version 30)
      (unless (package-installed-p 'vc-use-package)
	(package-vc-install "https://github.com/slotThe/vc-use-package"))
    (require 'vc-use-package))

General config

Move temporary files to /tmp/{username}

  (defvar user-temporary-file-directory
    (concat temporary-file-directory user-login-name "/"))
  (make-directory user-temporary-file-directory t)
  (setq backup-by-copying t)
  (setq backup-directory-alist
	`(("." . ,user-temporary-file-directory)
	  (,tramp-file-name-regexp nil)))
  (setq auto-save-list-file-prefix
	(concat user-temporary-file-directory ".auto-saves-"))
  (setq auto-save-file-name-transforms
	`((".*" ,user-temporary-file-directory t)))

Minimal interface

We disable a lot of interface elements, to make the editor more minimal looking.

  (setq inhibit-startup-message t)
  (scroll-bar-mode -1)
  (tool-bar-mode -1)
  (tooltip-mode -1)
  (set-fringe-mode 10)
  (menu-bar-mode -1)

Mode line

  (use-package moody
    :config
    (moody-replace-mode-line-front-space)
    (moody-replace-mode-line-buffer-identification)
    (moody-replace-vc-mode))

Match fish shell's path

  (defun set-exec-path-from-shell-PATH ()
    "Set up Emacs' `exec-path' and PATH environment variable to match
  that used by the user's shell.

  This is particularly useful under Mac OS X and macOS, where GUI
  apps are not started from a shell."
    (interactive)
    (let ((path-from-shell (replace-regexp-in-string
			    "[ \t\n]*$" "" (shell-command-to-string
					    "/usr/bin/fish --login -c 'string join : $PATH'"
						      ))))
      (setenv "PATH" path-from-shell)
      (setq exec-path (split-string path-from-shell path-separator))))

  (set-exec-path-from-shell-PATH)

Bell

I don't like any visual or sound bell.

  (setq ring-bell-function 'ignore)

Font

I use two different fonts in Emacs : my sans serif font for anything where variable fonts wouldn't matter, and monospace for fixed width text (such as code, org blocks and org tables). I like to use the generic sans-serif and monospace fonts, as it allows me to define them system-wide, which I highly prefer.

Besides the font settings, I use the package fixed-pitch, which sets up hooks automatically for all the modes that require fixed width fonts. This allows me to have my sans serif everywhere else.

  (custom-theme-set-faces
   'user
   ;; global faces
   '(default ((t (:family "monospace" :height 125))))
   '(variable-pitch ((t (:family "DejaVu Sans" :height 125))))
   '(fixed-pitch ((t (:family "monospace" :height 125))))
   ;; org mode specific faces
   '(org-block ((t (:inherit fixed-pitch))))
   '(org-code ((t (:inherit (shadow fixed-pitch)))))
   '(org-table ((t (:inherit fixed-pitch :foreground "#83a598")))))


  (use-package fixed-pitch
    :vc ( :fetcher github :repo cstby/fixed-pitch-mode))

Ligatures

  (use-package ligature
    :config
    (ligature-set-ligatures 't '("www"))
    (ligature-set-ligatures '(prog-mode tsx-ts-mode) '("--" "---" "==" "===" "!=" "!==" "=!="
						       "=:=" "=/=" "<=" ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!"
						       "??" "???" "?:" "?." "?=" "<:" ":<" ":>" ">:" "<:<" "<>" "<<<" ">>>"
						       "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" "###" "####"
						       "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" "#!" "#=" "^=" "<$>" "<$"
						       "$>" "<+>" "<+" "+>" "<*>" "<*" "*>" "</" "</>" "/>" "<!--" "<#--"
						       "-->" "->" "->>" "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>"
						       "==>" "=>" "=>>" ">=>" ">>=" ">>-" ">-" "-<" "-<<" ">->" "<-<" "<-|"
						       "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" "~>" "~-" "-~"
						       "~@" "[||]" "|]" "[|" "|}" "{|" "[<" ">]" "|>" "<|" "||>" "<||"
						       "|||>" "<|||" "<|>" "..." ".." ".=" "..<" ".?" "::" ":::" ":=" "::="
						       ":?" ":?>" "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__" "???"
						       "<:<" ";;;"))
    (global-ligature-mode t))

Visual mode

We turn on visual mode, so that lines can wrap nicely and not go beyond my Emacs buffer size.

  (global-visual-line-mode t)

Theme

I use catppuccin as my theme, as I find it comfortable to work with (the Frappe flavor).

  (use-package catppuccin-theme
    :init
    (setq catppuccin-flavor 'frappe)
    :config
    (load-theme 'catppuccin :no-confirm))

Completion

I use vertico as my completion framework. It's minimal, fast and tells me all I need to know and even sorts by history.

  (use-package vertico
    :init
    (vertico-mode)

    ;; Different scroll margin
    ;; (setq vertico-scroll-margin 0)

    ;; Show more candidates
    ;; (setq vertico-count 20)

    ;; Grow and shrink the Vertico minibuffer
    (setq vertico-resize t)

    ;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
    (setq vertico-cycle t))

  ;; Persist history over Emacs restarts. Vertico sorts by history position.
  (use-package savehist
    :init
    (savehist-mode))

  ;; A few more useful configurations...
  (use-package emacs
    :init
    ;; Add prompt indicator to `completing-read-multiple'.
    ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
    (defun crm-indicator (args)
      (cons (format "[CRM%s] %s"
		    (replace-regexp-in-string
		     "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
		     crm-separator)
		    (car args))
	    (cdr args)))
    (advice-add #'completing-read-multiple :filter-args #'crm-indicator)

    ;; Do not allow the cursor in the minibuffer prompt
    (setq minibuffer-prompt-properties
	  '(read-only t cursor-intangible t face minibuffer-prompt))
    (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

    ;; Support opening new minibuffers from inside existing minibuffers.
    (setq enable-recursive-minibuffers t)

    ;; Emacs 28 and newer: Hide commands in M-x which do not work in the current
    ;; mode.  Vertico commands are hidden in normal buffers. This setting is
    ;; useful beyond Vertico.
    (setq read-extended-command-predicate #'command-completion-default-include-p))

  (use-package orderless
    :ensure t
    :custom
    (completion-styles '(orderless basic))
    (completion-category-overrides '((file (styles basic partial-completion)))))

which-key

which-key is a nice little package that allows to have a minibuffer showing which keybinds are available under prefixes.

  (use-package which-key
    :config
    (which-key-mode)
    (which-key-add-key-based-replacements ;; naming prefixes
      "C-c l" "lsp"))

Org mode

  (use-package org
    :hook
    (org-mode . variable-pitch-mode))

Pretty bullets and headlines

I use org-superstar-mode, as it makes headlines and bullets look really nice.

  (use-package org-superstar
    :defer t
    :hook (org-mode . org-superstar-mode))

toc-org

This allows generating the table of contents you can find at the beginning of this file.

  (use-package toc-org
    :hook (org-mode . toc-org-mode))

Programming

Eglot

Eglot is a built in LSP client for Emacs. I prefer it to LSP as it's more lightweight and more straightforward to setup correctly.

  (use-package eglot
    :defer t
    :config
    (setq eglot-events-buffer-size 0) ;; important performance fix (https://www.gnu.org/software/emacs/manual/html_node/eglot/Performance.html)
    :bind (:map eglot-mode-map
		("C-c l h" . eldoc)
		("C-c l r" . eglot-rename)
		("C-c l f" . eglot-format-buffer))
    :hook ((tsx-ts-mode . eglot-ensure)
	   (typescript-ts-mode . eglot-ensure)
	   (python-ts-mode . eglot-ensure)
	   (go-ts-mode . eglot-ensure)
	   (eglot--managed-mode . electric-pair-mode)
	   (eglot--managed-mode . (lambda ()
				    (add-hook 'after-save-hook #'eglot-format-buffer nil t)))
	   (eglot--managed-mode . display-line-numbers-mode)))


  (setq-default eglot-workspace-configuration '(:typescript (:format (:indentSize 2
										  :convertTabsToSpaces t
										  :semicolons "remove"))))
  ;; makes eglot faster using a rust wrapper, needs to be in PATH
  (use-package eglot-booster
    :defer t
    :vc (:fetcher github :repo jdtsmith/eglot-booster)
    :after eglot
    :config
    (eglot-booster-mode))

Autocompletion

  (use-package corfu
    :defer t
    :custom
    (corfu-auto t)
    :init
    (global-corfu-mode)
    (setq corfu-popupinfo-delay 0.2)
    (corfu-popupinfo-mode))

  (use-package nerd-icons-corfu
    :after corfu
    :config
    (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))

Snippets

  (use-package yasnippet
    :defer t
    :ensure t
    :diminish yas-minor-mode
    :hook (prog-mode . yas-minor-mode)
    :bind (:map yas-minor-mode-map
		("C-c C-e" . yas-expand)))

Magit

Magit is a git client in Emacs.

  (use-package magit
    :defer t)

Docker

  (use-package docker
    :defer t
    :ensure t
    :bind ("C-c d" . docker))

popper

Popper is a package that allows us to have popup buffers. This is really useful when working with REPL languages such as Javascript or Go.

  (use-package popper
    :ensure t ; or :straight t
    :bind (("C-c p t"   . popper-toggle)
	   ("C-c p c"   . popper-cycle)
	   ("C-c p w" . popper-toggle-type))
    :init
    (setq popper-reference-buffers
	  '("\\*Messages\\*"
	    "Output\\*$"
	    "\\*Async Shell Command\\*"
	    help-mode
	    compilation-mode
	    "^\\*eshell.*\\*$" eshell-mode 
	    "^\\*shell.*\\*$"  shell-mode  
	    "^\\*term.*\\*$"   term-mode
	    "^\\*vterm.*\\*$"  vterm-mode))
    (popper-mode)
    (popper-echo-mode))

Languages

tree-sitter

Tree-sitter is a built-in Emacs package that allows us to have extremely well integrated language grammar. Here, we're setting up the list of sources, most of them being on tree-sitter's official GitHub, as well as hooking up the languages to their different modes.

  (setq treesit-font-lock-level 4) ;; more coloring!
  (setq treesit-language-source-alist
	'((bash "https://github.com/tree-sitter/tree-sitter-bash")
	  (cmake "https://github.com/uyha/tree-sitter-cmake")
	  (css "https://github.com/tree-sitter/tree-sitter-css")
	  (elisp "https://github.com/Wilfred/tree-sitter-elisp")
	  (go "https://github.com/tree-sitter/tree-sitter-go")
	  (gomod "https://github.com/camdencheek/tree-sitter-go-mod")
	  (html "https://github.com/tree-sitter/tree-sitter-html")
	  (javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
	  (json "https://github.com/tree-sitter/tree-sitter-json")
	  (make "https://github.com/alemuller/tree-sitter-make")
	  (markdown "https://github.com/ikatyang/tree-sitter-markdown")
	  (python "https://github.com/tree-sitter/tree-sitter-python")
	  (toml "https://github.com/tree-sitter/tree-sitter-toml")
	  (templ "https://github.com/vrischmann/tree-sitter-templ")
	  (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
	  (typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
	  (yaml "https://github.com/ikatyang/tree-sitter-yaml")))

  ;; mode bindings to file extensions
  (setq auto-mode-alist
	(append '(("\\.ts\\'" . tsx-ts-mode)
		  ("\\.tsx\\'" . tsx-ts-mode)
		  ("\\.py\\'" . python-ts-mode)
		  ("\\.go\\'" . go-ts-mode))
		auto-mode-alist))

Mail

  (autoload 'notmuch "notmuch" "notmuch mail" t)
  (use-package notmuch
    :defer t)

;; Local Variables: ;; eval: (add-hook 'after-save-hook (lambda ()(if (y-or-n-p "Reload?")(load-file user-init-file))) nil t) ;; eval: (add-hook 'after-save-hook (lambda ()(if (y-or-n-p "Tangle?")(org-babel-tangle))) nil t) ;; End: