Emacs configuration
(load-file "~/.config/sensitive.el")
Package Configuration
Add MELPA to the list of recognized archives
(require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize)
Installs use-package if I don't have it already and enables verbose messages
(unless (package-installed-p 'use-package) (package-install 'use-package)) (require 'use-package) (setq use-package-verbose t)
Use-package always installs packages
(setq use-package-always-ensure t)
GNU keys to enable downloading packages
(use-package gnu-elpa-keyring-update)
Appearance
Disable Splash Screen
(setq inhibit-splash-screen t)
Define font style and height
;All future frames (useful for the daemon) (setq default-frame-alist '((font . "Roboto Mono 22"))) (add-to-list 'default-frame-alist '(background-color . "#34293E")) ;The initial frame (useful for the gui) (setq initial-frame-alist '((font . "Roboto Mono 22"))) (add-to-list 'initial-frame-alist '(background-color . "#34293E"))
Set theme (currently Shades of Purple). My setup is a little weird: I
first set it to doom-shades-of-purple and then shades-of-purple. This
ends up with a color scheme that is pleasant for most modes.
(use-package doom-themes) (use-package shades-of-purple-theme) (setq custom-safe-themes t) (load-theme 'doom-shades-of-purple t) (load-theme 'shades-of-purple)
Disables a bunch of needless UI noise.
(cond ((> emacs-major-version 20) (tool-bar-mode -1) ; introduced in emacs 21 (menu-bar-mode -1) (scroll-bar-mode -1) (menu-bar-showhide-fringe-menu-customize-disable) (blink-cursor-mode -1) (windmove-default-keybindings 'meta)))
Use Emacs to display the battery level.
(setq battery-update-interval 10)
(display-battery-mode 1)
Pretty mode line
(use-package doom-modeline)
(doom-modeline-mode 1)
(doom-modeline-def-modeline 'main
'(bar matches buffer-info buffer-position)
'(time major-mode battery))
Display time in mode line
(display-time-mode 1)
Allows me to see the column number as well as the line number.
(column-number-mode)
Cute icon for notifications
(setq alert-default-icon "/home/tiago/.dot-files/doom-cute.png")
utf-8
(prefer-coding-system 'utf-8) (set-default-coding-systems 'utf-8) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) (setq default-buffer-file-coding-system 'utf-8) (set-language-environment 'utf-8) (set-selection-coding-system 'utf-8) (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
Conveniences
Don't use ui dialogs
(setq use-dialog-box nil)
Suppress annoying message any time you start a new frame
(setq server-client-instructions nil)
Enable recentf mode to remember recently opened files
(setq recentf-max-saved-items 10000) (recentf-mode 1) (add-to-list 'recentf-exclude (lambda (s) (cl-search "/test/" s))) (add-to-list 'recentf-exclude (lambda (s) (cl-search "/tmp/" s))) (add-to-list 'recentf-exclude (lambda (s) (cl-search "/sudo:" s)))
Every time a file is visited, update the list of recently visited files.
(add-hook 'find-file-hook 'recentf-save-list)
Undo and redo modifications to the window configuration. Use repeat mode to easily undo multiple modifications.
(winner-mode) (global-set-key "\C-xp" 'winner-undo) (global-set-key "\C-xn" 'winner-redo) (repeat-mode 1) (setq winner-repeat-map (let ((map (make-sparse-keymap))) (define-key map (kbd "p") 'winner-undo) (define-key map (kbd "n") 'winner-redo) map))
Disable repeat mode in Dired
(setq dired-jump-map nil)
Set scratch buffer major mode to org-mode
(setq initial-major-mode 'org-mode) (setq initial-scratch-message "")
Better keybinding to run a shell command
(global-set-key (kbd "M-s s") #'async-shell-command)
When running a shell command, do not display the command buffer until there is output.
(setq async-shell-command-display-buffer nil)
Minibuffer history persists across multiple sessions
(savehist-mode)
Ensures that backups and auto-saves go to a separate directory instead of stinking up the working directory.
(defvar backup-dir (expand-file-name "~/.emacs.d/backup/")) (defvar autosave-dir (expand-file-name "~/.emacs.d/autosave/")) (setq backup-directory-alist (list (cons ".*" backup-dir))) (setq auto-save-list-file-prefix autosave-dir) (setq auto-save-file-name-transforms `((".*" ,autosave-dir t)))
Package for using connecting and pairing Bluetooth devices
(use-package bluetooth)
Package for restoring and reading from the trash folder
(use-package trashed)
Package that displays when I am in Emacs on discord
(use-package elcord) (setq elcord-display-buffer-details nil) (setq elcord-editor-icon "doom_cute_icon") (elcord-mode)
Updates the PATH according to the environment in which Emacs is running
(use-package exec-path-from-shell) (when (daemonp) (exec-path-from-shell-initialize))
Buffer Navigation
Function for jumping to another part of the buffer quickly
(use-package flash) (bind-key "M-j" #'flash-jump)
Keybindings for navigating functions
(bind-key "C-M-p" #'beginning-of-defun) (bind-key "C-M-n" #'end-of-defun)
Opens files at the last visited location
(save-place-mode 1)
Key binding for returning to the beginning of the line ignores indentation
(global-set-key (kbd "C-a") #'back-to-indentation)
Shows an indexed view of the current buffer and allows for straightforward navigation
(use-package consult) (defun consult-org-maybe () (interactive) (if (eq major-mode 'org-mode) (consult-org-heading) (consult-imenu))) (global-set-key (kbd "M-g i") #'consult-org-maybe)
Faster scroll
(when (display-graphic-p) (setq mouse-wheel-scroll-amount '(2 ((shift) . 1)) mouse-wheel-progressive-speed nil))
Editing Buffers
Enable creation of pairs of brackets or quotes when one is inserted.
(setq skeleton-pair t) (bind-key "(" 'skeleton-pair-insert-maybe) (bind-key "{" 'skeleton-pair-insert-maybe) (bind-key "[" 'skeleton-pair-insert-maybe) (bind-key (char-to-string 34) 'skeleton-pair-insert-maybe) ;char 34 is the single quote, putting the character itself ;ruins prettify symbols mode
Enable Emacs to track changes made to files by different programs.
(setq auto-revert-interval 1)
(global-auto-revert-mode 1)
Delete trailing white spaces after saving a file.
(add-hook 'before-save-hook
'delete-trailing-whitespace)
Multiple cursors
(use-package multiple-cursors) (global-set-key (kbd "C->") 'mc/mark-next-like-this) (global-set-key (kbd "C-<") 'mc/mark-previous-like-this) (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this) (global-set-key (kbd "C-x x SPC") 'set-rectangular-region-anchor)
Yanking a string replaces the current selection
(delete-selection-mode 1)
Command to insert the current file name
(global-set-key (kbd "C-c w") (lambda () (interactive) (insert (buffer-file-name (window-buffer (minibuffer-selected-window))))))
Command to consult and insert from kill-ring
(global-set-key (kbd "C-c y") #'consult-yank-from-kill-ring) (global-set-key (kbd "C-x C-SPC") #'consult-mark)
Popup windows
This makes it so every pop up window appears in the current window. Special rule for "magit-diff" to prevent it from taking up the entire window when committing.
(add-to-list 'display-buffer-alist
'(""
(display-buffer-same-window)))
(add-to-list 'display-buffer-alist
'("magit-diff"
(display-buffer-no-window)))
(add-to-list 'display-buffer-alist
'((derived-mode
coq-response-mode coq-goals-mode mu4e-view-mode)
(display-buffer-no-window)))
GPG
;; let's get encryption established (use-package pinentry) (setenv "GPG_AGENT_INFO" nil) ;; use emacs pinentry (setq auth-source-debug t) (setq epg-gpg-program "gpg2") ;; not necessary (require 'epa-file) (epa-file-enable) (setq epa-pinentry-mode 'loopback) (setq epg-pinentry-mode 'loopback) (pinentry-start) (require 'org-crypt) (org-crypt-use-before-save-magic) (setq epa-file-encrypt-to email1) (setq epa-file-select-keys 1)
Coding Packages
Compilation
Jump to first error after compiling.
(setq compilation-auto-jump-to-first-error 'first-known)
Kill compilation buffer and window
(keymap-set compilation-mode-map "q" #'kill-buffer-and-window)
Flymake
Package used by Eglot for highlighting errors
(use-package flymake) (add-hook 'prog-mode-hook #'flymake-mode) (keymap-set flymake-mode-map "C-c C-x" #'flymake-goto-next-error)
Corfu
Package for completion suggestions
(use-package corfu) (setq corfu-auto t) (global-corfu-mode 1) (corfu-popupinfo-mode 1) (setq corfu-popupinfo-delay nil) (keymap-set corfu-popupinfo-map "C-M-i" #'corfu-popupinfo-toggle) (use-package nerd-icons-corfu) (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
OCaml packages
(use-package tuareg :vc (:url "https://github.com/mrjazzybread/tuareg" :rev :newest))
Compile at root of directory
(keymap-set tuareg-mode-map "C-c C-c" #'project-compile)
Use dune build to compile OCaml projects
(add-hook 'tuareg-mode-hook
(lambda ()
(if (eq (project-current) nil)
(setq-local compile-command
(concat "ocaml " (buffer-file-name)))
(setq-local compile-command "dune build && dune install"))))
(add-hook 'dune-mode-hook
(lambda () (setq-local compile-command "dune build && dune install")))
Format OCaml code after saving the buffer
(use-package ocamlformat) (setq ocamlformat-enable 'enable-outside-detected-project) (setq ocamlformat-show-errors nil) (add-hook 'before-save-hook #'ocamlformat-before-save)
Dune package
(use-package dune)
Rust packages
(use-package rustic) (setq rustic-lsp-client #'eglot)
Eglot
Prevent Eglot from being using when writing Rocq.
(defun lsp-no-coq () (interactive) (unless (eq major-mode 'coq-mode) (eglot-ensure))) (use-package eglot) (add-hook 'prog-mode-hook #'lsp-no-coq) (add-hook 'LaTeX-mode-hook #'eglot-ensure)
Eldoc popup. Useful for displaying documentation and errors. I have it set to a keybinding and not a timer since I prefer to control what pop ups appear.
(use-package eldoc-box) (setq eldoc-box-only-multi-line t) (bind-key "\C-hj" #'eldoc-box-help-at-point)
Git packages
Folks… It's Magit.
(use-package magit) (keymap-set magit-mode-map "C-c C-p" #'magit-section-up) (setq magit-display-buffer-function #'magit-display-buffer-traditional) (setq magit-bury-buffer-function 'magit-restore-window-configuration) (bind-key "C-x g" #'magit-status)
Automatically save files when entering Magit.
(setq magit-save-repository-buffers 'dontask)
Commit on every file save. I use this to sync my agenda files automatically.
(use-package git-auto-commit-mode) (setq gac-automatically-add-new-files-p t)
Miscellaneous Coding packages
(use-package yaml-mode) (use-package boogie-friends) (setq flycheck-dafny-executable "/usr/bin/dafny")
Dired
Deleted files are moved to the trash folder
(setq delete-by-moving-to-trash t)
Start Dired in omit mode
(add-hook 'dired-mode-hook #'dired-omit-mode)
Bind the "o" key to show hidden files
(add-hook 'dired-mode-hook
(lambda () (local-set-key
(kbd "o") #'dired-omit-mode)))
Bind the "b" key to move up in the directory
(add-hook 'dired-mode-hook
(lambda () (local-set-key
(kbd "b") #'dired-up-directory)))
Set files to omit
(setq dired-omit-files (rx (or (seq bol (? ".") "#") ;; emacs autosave files (seq bol ".") ;; dot-files (seq "~" eol) ;; backup-files (seq bol "CVS" eol) ;; CVS dirs (seq bol "CVS" eol) ;; CVS dirs )))
Make it so Dired buffers are just a list of file names.
(add-hook 'dired-mode-hook
(lambda () (dired-hide-details-mode 1)))
Icons for Dired mode.
;This package requires additional fonts (use-package all-the-icons-dired :hook (dired-mode . all-the-icons-dired-mode))
Kill Dired buffer when opening a new Dired buffer.
(setq dired-kill-when-opening-new-dired-buffer t)
Dired buffers update when there is a change in one of the files in the directory
(setq global-auto-revert-non-file-buffers t)
Keeps track of visited Dired buffers
(use-package dired-hist) (define-key dired-mode-map "l" #'dired-hist-go-back) (define-key dired-mode-map "r" #'dired-hist-go-forward) (dired-hist-mode 1)
More convenient way to search through sub-directories.
(use-package dired-subtree) (keymap-set dired-mode-map "i" #'dired-subtree-insert) (keymap-set dired-mode-map "DEL" #'dired-subtree-remove)
Disable "Omit N files" message
(setq dired-omit-verbose nil)
Quickly browse files in read only mode
(defun view-browse (f) (let ((b (current-buffer))) (dired-jump) (condition-case nil ((lambda () (funcall f) (dired-find-file) (kill-buffer b) (view-mode))) (error (progn (switch-to-buffer b) (message "No more files in current directory")))))) (defun view-next-file () (interactive) (view-browse (lambda () (dired-next-line 1)))) (defun view-previous-file () (interactive) (view-browse (lambda () (dired-previous-line 1))) ) (define-key view-mode-map (kbd "n") 'view-next-file) (define-key view-mode-map (kbd "p") 'view-previous-file)
Change ls switches to use human readable file sizes and to list
directories first.
(setq dired-listing-switches "-alh --group-directories-first")
When copying a file, have it so if there is another dired buffer open in another window in the same frame, it selects that buffer by default
(setq dired-dwim-target t)
Use mu4e to manage emails. Naturally, requires mu4e to already be installed.
(require 'mu4e)
Fancy dashboard for mu4e. Requires local file
(use-package async) (load "~/.mu4e-dashboard/mu4e-dashboard.el")
This is necessary so that mu4e won't print an annoying error message
(setq user-mail-address email1)
Function to use for sending emails.
(setq message-send-mail-function 'smtpmail-send-it)
Quitting mu4e returns to the dashboard
(keymap-set mu4e-headers-mode-map "q" #'mu4e-dashboard)
Avoids mail syncing issues
(setq mu4e-change-filenames-when-moving t) (setq mu4e-context-policy "pick-first")
Refreshes email every minute
(setq mu4e-update-interval 60) (setq mu4e-get-mail-command "mbsync -a")
Set mail directory
(setq mu4e-maildir "~/mail")
Creates two contexts for my two work emails.
(setq mu4e-contexts (list ;; Work account (make-mu4e-context :name "FCT" :match-func (lambda (msg) (when msg (string-prefix-p "/gmail" (mu4e-message-field msg :maildir)))) :vars `((user-mail-address . ,email1) (user-full-name . "Tiago Soares") (smtpmail-smtp-server . "smtp.gmail.com") (smtpmail-smtp-service . 465) (smtpmail-stream-type . ssl) (mu4e-drafts-folder . "/gmail/[Gmail]/Drafts") (mu4e-sent-folder . "/gmail/[Gmail]/Sent Mail") (mu4e-refile-folder . "/gmail/[Gmail]/All Mail") (mu4e-trash-folder . "/gmail/[Gmail]/Trash"))) (make-mu4e-context :name "Inria" :match-func (lambda (msg) (when msg (string-prefix-p "/inria" (mu4e-message-field msg :maildir)))) :vars `((user-mail-address . ,email2) (user-full-name . "Tiago Soares") (smtpmail-smtp-server . "smtp.inria.fr") (smtpmail-smtp-service . 587) (smtpmail-stream-type . nil) (mu4e-drafts-folder . "/inria/Drafts") (mu4e-sent-folder . "/inria/Sent") (mu4e-trash-folder . "/inria/Trash"))) ) )
Notifications for mu4e
(use-package mu4e-alert) (mu4e-alert-set-default-style 'libnotify) (mu4e-alert-enable-notifications) (setq mu4e-alert-icon "/home/tiago/.dot-files/email.png")
Human readable header fields
(setq mu4e-headers-fields '((:human-date . 12) (:from . 22) (:subject)))
Better reading and writing experience for emails
(add-hook 'mu4e-view-mode-hook #'writeroom-mode) (add-hook 'mu4e-headers-mode-hook #'writeroom-mode) (add-hook 'message-mode-hook #'auto-fill-mode)
Suppress annoying "Indexing… message"
(setq mu4e-hide-index-messages t)
Fold threads at startup
(add-hook 'mu4e-thread-mode-hook #'mu4e-thread-fold-all)
Start mu4e
(mu4e)
Org
(use-package org)
Some Basic Bookkeeping
Automatically commit changes to org files.
(defun epic () (setq gac-automatically-push-p t)) (add-hook 'git-auto-commit-mode-hook #'epic)
Some helpful variables
(defun org-directory (file) (concat "~/roam/daily/personal/" file)) (defvar todo-file (org-directory "todo.org.gpg")) (defvar agenda-file (org-directory "appoint.org.gpg")) (defvar log-file (org-directory "art.org.gpg"))
My agenda files:
(setq org-agenda-file-regexp "\\`[^.].*\\.org\\\(\\.gpg\\\)?\\'") (setq org-agenda-files (list todo-file agenda-file log-file))
Settings for exporting Org files with citations to TeX.
(setq org-cite-export-processors '((t biblatex "numeric" "numeric"))) (setq org-cite-global-bibliography '("~/.dot-files/latex/english.bib")) (setq org-export-with-sub-superscripts nil)
Restore the window configuration when quitting the agenda view
(setq org-agenda-restore-windows-after-quit t)
Enable notifications for Org agenda items
(use-package org-alert) (setq alert-default-style 'libnotify) (setq org-alert-interval 300) (setq org-alert-notify-cutoff 10) (setq org-alert-notify-after-event-cutoff 0) (org-alert-enable)
Add menu item to list only items with a TODO keyword.
(add-to-list 'org-agenda-custom-commands
'("t" "List all items with the TODO keyword" ((todo "TODO"))))
Add menu item to list albums I haven't listened and movies I haven't watched.
(add-to-list 'org-agenda-custom-commands
'("l" "List all unlistened albums" ((todo "TOLISTEN" nil))
((org-agenda-view-columns-initially t))))
(add-to-list 'org-agenda-custom-commands
'("m" "List all unwatched movies" ((todo "TOWATCH" nil))
((org-agenda-view-columns-initially t))))
This is very important
(defun what () (interactive) (insert "👁️👄👁️"))
Add Markdown as a an export backend
(require 'ox-md) (add-to-list 'org-export-backends 'md)
Update agenda on startup
(start-process-shell-command "update" nil "cd $HOME/roam/daily && git pull")
Appearance
Hide emphasis markers and macro braces
(setq org-hide-emphasis-markers t) (setq org-hide-macro-markers t)
Make it there is only one star visible in each heading.
(setq org-hide-leading-stars t)
Use LaTeX like syntax to insert special symbols
(setq org-pretty-entities t)
Start Org files with each heading folded.
(setq org-startup-folded 'content)
Enable Org indentation
(setq org-startup-indented t)
Center Org agenda
(add-hook 'org-agenda-mode-hook #'writeroom-mode)
Don't show items that are marked as done.
(setq org-agenda-skip-timestamp-if-done t
org-agenda-skip-deadline-if-done t
org-agenda-skip-scheduled-if-done t
org-agenda-skip-scheduled-if-deadline-is-shown t
org-agenda-skip-timestamp-if-deadline-is-shown t)
Automatic latex preview in Org mode
(setq org-startup-with-latex-preview t)
Package for editing latex snippets in Org-mode.
(use-package org-fragtog)
(add-hook 'org-mode-hook #'org-fragtog-mode)
Scale up latex preview in Org mode
(setq org-format-latex-options (plist-put org-format-latex-options :scale 3))
Org agenda takes up the full window
(setq org-agenda-window-setup 'only-window)
Org agenda does not display the files in which items are written in.
(setq org-agenda-prefix-format '((agenda . "%?-12t% s") (todo . "%-12:c") (tags . "%-12:c") (search . "%-12:c")))
Org agenda starts on the current day
(setq org-agenda-start-on-weekday nil)
Add Rocq and Gospel to the list of languages that Org is aware of
(add-to-list 'org-babel-tangle-lang-exts '("rocq" . "v")) (add-to-list 'org-babel-tangle-lang-exts '("gospel" . "mli")) (add-to-list 'org-src-lang-modes '("gospel" . tuareg)) (add-to-list 'org-src-lang-modes '("rocq" . coq))
Org Pretty Symbols
Function for adding pretty symbols for Org mode. Most of these are just so that Org mode environments aren't awful to look at.
;; Pretty Symbols for Org (defun add-symbols () (push '("#+end_example" . ? ) prettify-symbols-alist) (push '("#+end_src" . ? ) prettify-symbols-alist) (push '("#+begin_src ocaml" . ?🐫) prettify-symbols-alist) (push '("#+begin_src gospel" . ?🛐) prettify-symbols-alist) (push '("#+begin_src rocq" . ?🦅) prettify-symbols-alist) (push '("#+begin_example ocaml :why3" . ?❔) prettify-symbols-alist) (push '("#+begin_src emacs-lisp" . ?🗿) prettify-symbols-alist) (push '("->" . ?→) prettify-symbols-alist) (push '("<->" . ?↔) prettify-symbols-alist) (push '("|-" . ?⊢) prettify-symbols-alist) (push '("/\\" . ?∧) prettify-symbols-alist) (push '("\\/" . ?∨) prettify-symbols-alist) (push '("<-" . ?←) prettify-symbols-alist) (prettify-symbols-mode 1)) (add-hook 'org-mode-hook #'add-symbols)
Org capture templates
(setq org-capture-templates '( ("w" "Writing TODO" entry (file+headline todo-file "Writing") "* TODO %?\n " :empty-lines 0) ("p" "Phd TODO" entry (file+headline todo-file "PhD Tasks") "* TODO [[%L][%?]]\n " :empty-lines 0) ("a" "Appointment" entry (file+headline agenda-file "Appointments") "* APPOINTMENT %?\n " :empty-lines 0) ("?" "Question" entry (file+headline todo-file "Questions") "* 👁️👄👁️ [[%L][%?]]\n " :empty-lines 0) ("r" "Reading" checkitem (file+headline todo-file "Reading List") "[ ] %?\n") ("l" "Album" entry (file+headline log-file "Albums") "* TOLISTEN %?\n %^{Artist}p" :empty-lines 0) ("m" "Movie" entry (file+headline log-file "Movie") "* TOWATCH %?\n %^{Recommended}p")))
Search for albums
This function searches for albums in my personal list from a certain
artist (this can probably be simplified with org-ql).
(defun list-albums-by-artist () (interactive) (with-current-buffer "art.org.gpg" (let* ((value (completing-read "Value: " (mapcar #'list (org-property-values "ARTIST"))))) (unless (string-match "\\`{.*}\\'" value) (setq value (concat "\"" value "\""))) (switch-to-buffer "art.org.gpg") (org-match-sparse-tree nil (concat "ARTIST=" value)) )))
Org Keywords
(setq org-todo-keywords '((sequence "APPOINTMENT(p)" "SPEC(s)" "TODO(t)" "IN-PROGRESS(i@/!)" "VERIFYING(v!)" "BLOCKED(b@)" "👁️👄👁️(q)" "TOLISTEN(l)" "TOWATCH(e)" "|" "DONE(d!)" "OBE(o@!)" "WONT-DO(w@/!)" "LISTENED(m@)" "WATCHED(r@)"))) ;; TODO colors (setq org-todo-keyword-faces '( ("TODO" . (:foreground "GoldenRod" :weight bold)) ("TOLISTEN" . (:foreground "GoldenRod" :weight bold)) ("TOWATCH" . (:foreground "LightBlue" :weight bold)) ("APPOINTMENT" . (:foreground "DeepPink" :weight bold)) ("IN-PROGRESS" . (:foreground "Cyan" :weight bold)) ("VERIFYING" . (:foreground "DarkOrange" :weight bold)) ("BLOCKED" . (:foreground "Red" :weight bold)) ("DONE" . (:foreground "LimeGreen" :weight bold)) ("WONT-DO" . (:foreground "Firebrick" :weight bold)) ("SPEC" . (:foreground "LightCyan" :weight bold)) ("LISTENED" . (:foreground "LimeGreen" :weight bold)) ("WATCHED" . (:foreground "LimeGreen" :weight bold)) ))
Remove Spell Checking in Code Blocks
(add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_SRC" . "#\\+END_SRC")) (add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_EXAMPLE" . "#\\+END_EXAMPLE")) (add-to-list 'ispell-skip-region-alist '("^#\\+begin_src" . "#\\+end_src")) (add-to-list 'ispell-skip-region-alist '("^#\\+begin_example" . "#\\+end_example")) (add-to-list 'ispell-skip-region-alist '("^#\\+" . "\n")) (add-to-list 'ispell-skip-region-alist '("~" . "~")) (add-to-list 'ispell-skip-region-alist '("/" . "/")) (add-to-list 'ispell-skip-region-alist '("{{{" . "}}}")) (add-to-list 'ispell-skip-region-alist '("<<" . ">>"))
Org Key Bindings and Hooks
Global key bindings to access and update the agenda.
(global-set-key "\C-ca" 'org-agenda) (global-set-key "\C-cc" 'org-capture)
Keybindings to navigate agenda view
(keymap-set org-agenda-keymap "n" #'org-agenda-next-item) (keymap-set org-agenda-keymap "p" #'org-agenda-previous-item)
French Notes
Function for inserting a conjugation table for french verbs
(setq conjugation-table "|-----------+---| | Je | | |-----------+---| | Tu | | |-----------+---| | Il/Elle | | |-----------+---| | Nous | | |-----------+---| | Vous | | |-----------+---| | Ils/Elles | | |-----------+---|") (defun start-conjugation () (interactive) (insert conjugation-table) (org-backward-paragraph) (org-cycle) (org-cycle))
LaTeX export
Add common scientific paper classes.
(with-eval-after-load 'ox-latex (add-to-list 'org-latex-classes '("llncs" "\\documentclass{llncs}" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}")))) (with-eval-after-load 'ox-latex (add-to-list 'org-latex-classes '("IEEEtran" "\\documentclass{IEEEtran}" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}"))))
Disable exporting with table of contents.
(setq org-export-with-toc nil)
Automatically export to latex on save when the export-org-buffer
variable is non-nil. This should be buffer local.
(setq org-export-buffer nil) (defun org-export-auto () (when org-export-buffer (if (equal org-export-buffer 'beamer) (org-beamer-export-to-latex) (org-latex-export-to-latex)) (org-babel-tangle) (let ((gospel (car (directory-files "." t "\\.mli$" t 1))) (rocq (car (directory-files "." t "\\.v$" t 1)))) (shell-command (concat "gospel check " gospel) "Gospel Type Checking") (shell-command (concat "rocq c " rocq ">> /dev/null") "Rocq Compilation")))) (add-hook 'after-save-hook #'org-export-auto)
Use listings for source code blocks
(setq org-latex-src-block-backend 'listings)
Command to display the compilation windows for LaTeX, Gospel and Rocq
(defun latex-compilation-windows () (interactive) (delete-other-windows) (switch-to-buffer "LaTeX") (my-split-window-right) (windmove-right) (switch-to-buffer "Gospel Type Checking") (split-window-below) (windmove-down) (switch-to-buffer "Rocq Compilation"))
Use the \gosp macro for code snippets
(setq org-export-filter-code-functions '((lambda (s b info) (let ((s (replace-regexp-in-string "texttt" "gosp" s t t))) (replace-regexp-in-string "\\\\_" "_" s t t)))))
Replaces certain strings with latex
(setq org-export-filter-body-functions '((lambda (s b info) (when (or (eq b 'latex) (eq b 'beamer)) (let ((case-fold-search nil) (macros '(("GospelSL" . "gospelsl") ("Gospel" . "gospel") ("Rocq" . "rocq") ("OCaml" . "ocaml") ("Peter" . "peter") ("Ortac" . "ortac") ("Why3" . "whythree") ("Iris" . "iris") ("CFML" . "cfml") ("Viper" . "viper") ("Cameleer" . "cameleer")))) (dolist (v macros) (setq s (replace-regexp-in-string (car v) (concat "\\" (cdr v)) s t t))))) s)))
Org Roam
(use-package org-roam) (setq org-roam-directory (file-truename "~/roam")) (setq org-roam-file-exclude-regexp '("data/" "daily/")) (setq org-roam-completion-everywhere t) (keymap-global-set "C-c n l" #'org-roam-buffer-toggle) (keymap-global-set "C-c n f" #'org-roam-node-find) (keymap-global-set "C-c n g" #'org-roam-graph) (keymap-global-set "C-c n i" #'org-roam-node-insert) (keymap-global-set "C-c n c" #'org-roam-capture) (keymap-global-set "C-c n j" #'org-roam-dailies-capture-today) (org-roam-db-autosync-mode)
Capture templates for org roam.
(setq org-roam-capture-templates '(("t" "travel" plain "%?" :if-new (file+head "travel/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("r" "Reading note" plain (file "~/roam/templates/reading_template.org") :if-new (file+head "research/%<%Y%m%d%H%M%S>-${slug}.org.gpg" "#+title: ${title}\n") :unnarrowed t) ("p" "PhD Note" plain "%?" :if-new (file+head "research/%<%Y%m%d%H%M%S>-${slug}.org.gpg" "#+title: ${title}\n") :unnarrowed t :jump-to-captured t) ))
Capture template for org roam dailies
(setq org-roam-dailies-capture-templates '(("d" "default" plain "* %?" :target (file+head "%<%Y-%m-%d>.org.gpg" "#+title: %<%Y-%m-%d> ") :jump-to-captured t)))
PDFs
Opens the current file in zathura and kills the Doc View buffer.
(defun zathura () (when (equal (file-name-extension (buffer-file-name)) "pdf") (start-process "zathura" nil "zathura" (buffer-file-name)) (let ((b (current-buffer))) (add-to-list 'recentf-list (buffer-file-name)) (recentf-save-list) (previous-buffer) (kill-buffer b) )))
When we open a PDF in Emacs, open it in zathura instead.
(add-hook 'doc-view-mode-hook #'zathura)
Function to run a latex process in the background.
(defun run-latex () (interactive) (async-shell-command "latexmk -pdf -pdflatex='pdflatex -interaction=nonstopmode' -pvc --synctex=1 -use-make main.tex" "LaTeX"))
Proof General
Package for working with Rocq
(use-package proof-general)
Removes the EXTREMELY annoying proof general splash screen
(setq proof-splash-enable nil)
When starting a proof, splits windows so that the goals window is larger than the response window
(setq proof-three-window-mode-policy 'hybrid)
Weird arrow :/
(setq overlay-arrow-string "")
Function to generate a Rocq Makefile
(defun coq-makefile-gen () (interactive) (async-shell-command "coq_makefile -f _CoqProject -o Makefile"))
Why3 configuration
(setq opam-share (if (boundp 'opam-share) opam-share (ignore-errors (car (process-lines "opam" "var" "share"))))) (setq why3-share (if (boundp 'why3-share) why3-share (ignore-errors (car (process-lines "why3" "--print-datadir"))))) (setq why3el (let ((f (expand-file-name "emacs/why3.elc" why3-share))) (if (file-readable-p f) f (when (and opam-share (file-directory-p opam-share)) (let ((f (expand-file-name "emacs/site-lisp/why3.elc" opam-share))) (if (file-readable-p f) f nil)))))) (when why3el (require 'why3 why3el))
Unicode Symbols for Iris
;; Input of unicode symbols (use-package math-symbol-lists) ; Automatically use math input method for Coq files (add-hook 'coq-mode-hook (lambda () (set-input-method "math"))) (add-hook 'tuareg-mode-hook (lambda () (set-input-method "math"))) ; Input method for the minibuffer ;; (defun my-inherit-input-method () ;; "Inherit input method from `minibuffer-selected-window'." ;; (let* ((win (minibuffer-selected-window)) ;; (buf (and win (window-buffer win)))) ;; (when buf ;; (activate-input-method (buffer-local-value 'current-input-method buf))))) ;; (add-hook ' ;; minibuffer-setup-hook #'my-inherit-input-method) ; Define the actual input method (quail-define-package "math" "UTF-8" "Ω" t) (quail-define-rules ; add whatever extra rules you want to define here... ("\\fun" ?λ) ("\\mult" ?⋅) ("\\ent" ?⊢) ("\\valid" ?✓) ("\\diamond" ?◇) ("\\box" ?□) ("\\bbox" ?■) ("\\later" ?▷) ("\\pred" ?φ) ("\\and" ?∧) ("\\or" ?∨) ("\\comp" ?∘) ("\\ccomp" ?◎) ("\\all" ?∀) ("\\ex" ?∃) ("\\to" ?→) ("\\sep" ?∗) ("\\lc" ?⌜) ("\\rc" ?⌝) ("\\Lc" ?⎡) ("\\Rc" ?⎤) ("\\lam" ?λ) ("\\empty" ?∅) ("\\Lam" ?Λ) ("\\Sig" ?Σ) ("\\-" ?∖) ("\\aa" ?●) ("\\af" ?◯) ("\\auth" ?●) ("\\frag" ?◯) ("\\iff" ?↔) ("\\gname" ?γ) ("\\incl" ?≼) ("\\latert" ?▶) ("\\update" ?⇝) ("\\nin" ?∉) ("\\u" ?∪) ("\\points" ?↦) ;; accents (for iLöb) ("\\o" ?ö) ;; subscripts and superscripts ("^^+" ?⁺) ("__+" ?₊) ("^^-" ?⁻) ("__0" ?₀) ("__1" ?₁) ("__2" ?₂) ("__3" ?₃) ("__4" ?₄) ("__5" ?₅) ("__6" ?₆) ("__7" ?₇) ("__8" ?₈) ("__9" ?₉) ("__a" ?ₐ) ("__e" ?ₑ) ("__h" ?ₕ) ("__i" ?ᵢ) ("__k" ?ₖ) ("__l" ?ₗ) ("__m" ?ₘ) ("__n" ?ₙ) ("__o" ?ₒ) ("__p" ?ₚ) ("__r" ?ᵣ) ("__s" ?ₛ) ("__t" ?ₜ) ("__u" ?ᵤ) ("__v" ?ᵥ) ("__x" ?ₓ) ) (mapc (lambda (x) (if (cddr x) (quail-defrule (cadr x) (car (cddr x))))) ; need to reverse since different emacs packages disagree on whether ; the first or last entry should take priority... ; see <https://mattermost.mpi-sws.org/iris/pl/46onxnb3tb8ndg8b6h1z1f7tny> for discussion (reverse (append math-symbol-list-basic math-symbol-list-extended)))
Settings for Text Mode
Enable auto-fill.
(add-hook 'text-mode-hook #'auto-fill-mode)
(setq fill-column 80)
Enable Writeroom mode for a more comfortable writing experience.
(use-package writeroom-mode) (add-hook 'text-mode-hook #'writeroom-mode) (setq writeroom-mode-line t) (setq writeroom-maximize-window nil)
Use aspell as default spell checking program (should be default, but
something is changing it)
(setq ispell-program-name "/usr/bin/aspell")
Enable Flyspell for spell checking
(use-package flyspell) (add-hook 'text-mode-hook #'flyspell-mode) (add-hook 'prog-mode-hook #'flyspell-prog-mode) (use-package flyspell-correct) (keymap-set flyspell-mode-map "M-$" #'flyspell-correct-wrapper)
Removes completion at point from flyspell so that I can use it for
completing org roam nodes.
(require 'flyspell) (keymap-unset flyspell-mode-map "C-M-i")
Disable word completion in text-mode
(setq text-mode-ispell-word-completion nil)
Automatic insertion of right brace in Latex-mode
(setq LaTeX-electric-left-right-brace t)
Minibuffer completion w/Vertico
(use-package vertico)
(vertico-mode 1)
(vertico-multiform-mode 1)
Allows using minibuffer commands within the minibuffer.
(setq enable-recursive-minibuffers t)
TAB works the same way as in other completion systems.
(keymap-set vertico-map "TAB" #'minibuffer-complete)
Completion at point uses Vertico
(setq completion-in-region-function #'consult-completion-in-region)
Orderless allows for more flexible completion styles.
(use-package orderless) (setq completion-styles '(orderless basic)) (setq completion-category-overrides '((file (styles partial-completion)))) (setq completion-category-defaults nil) ;; Disable defaults, use orderless settings (setq completion-pcm-leading-wildcard t) ;; Emacs 31: partial-completion behaves like substring
More information in minibuffer
(use-package marginalia)
Icons in minibuffer
(use-package all-the-icons) (use-package all-the-icons-completion) (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup) (all-the-icons-completion-mode) (marginalia-mode)
Vertico completion in a posframe
(use-package vertico-posframe)
(vertico-posframe-mode 1)
Non-transparent popup
(setq vertico-posframe-parameters '((alpha . 100)))
Fixed size Vertico posframe
(defun my-vertico-posframe-get-size (buffer) "Set the vert-posframe size according to the current frame." (let ((height (or vertico-posframe-height 10)) (width (min (or vertico-posframe-width 200) (round (* .9 (frame-width)))))) (list :height height :width width :min-height height :min-width width))) (setq vertico-posframe-size-function #'my-vertico-posframe-get-size)
Do not use posframe for consult line and consult mark
(setq vertico-multiform-commands '((consult-line (:not posframe)) (consult-mark (:not posframe)) (consult-mark (:not posframe)) (consult-org-maybe (:not posframe)) (t posframe)))
Switch to buffer with recentf files.
(global-set-key (kbd "C-x b") #'consult-buffer)
No live preview when switching buffers
(setq consult-preview-excluded-buffers t)
Replace I-search with consult-line. Vertico cycle is set to t so that
we can go to candidates in previous lines.
(setq vertico-cycle t) (global-set-key (kbd "C-s") #'consult-line)
Eshell
(use-package eshell)
Fish like suggestions for eshell
(use-package capf-autosuggest)
(add-hook 'eshell-mode-hook #'capf-autosuggest-mode)
Increase the history size. This is helpful when using capf-autosuggest
since that package checks the history for completion candidates.
(setq eshell-history-size 50000)
Pretty eshell prompt
(load-file "/home/tiago/.config/prompt.el") (setq eshell-prompt-function #'epe-theme-dakrone)
Function for clearing the shell
(defun eshell-clear () (interactive) "Clear the eshell buffer." (let ((inhibit-read-only t)) (erase-buffer) (eshell-send-input) (beginning-of-buffer) (kill-line) (end-of-buffer) ))
Function for getting to the base of any project. Useful for spawning shells since having it at the root of the project is generally more convenient.
(defvar project-files '("dune-project" "package.json" "CoqProject" "Makefile" ) ) (defun is-base () (or (equal default-directory "/") (not (eq (seq-intersection (directory-files ".") project-files 'equal ) nil) )) ) (defun get-to-base () (let ((c default-directory)) (progn (while (not (is-base)) (find-file "..")) (when (equal default-directory "/") (find-file c) ) )))
Always spawns eshell on a new terminal
(defun multi-eshell () (interactive) (let ((b (current-buffer))) (when (seq-find (lambda (val) (equal "*eshell*" (buffer-name val))) (buffer-list)) (switch-to-buffer "*eshell*") (rename-uniquely)) (switch-to-buffer b) (eshell)))
Key binding for spawning a new instance of eshell at the root of a
project.
(defun eshell-spawn () (interactive) (get-to-base) (multi-eshell)) (bind-key "C-c C-SPC" 'eshell-spawn)
Delete duplicates in the eshell history
(setq eshell-hist-ignoredups t)
Augments eshell's completion framework so that it behaves more like
fish (e.g. "pacman -S …" completes the name of the package)
(use-package fish-completion)
(global-fish-completion-mode 1)
I never know man
(setq eshell-cmpl-dir-ignore "\\`\\(CVS\\)/\\'")
Add rust packages to path
(add-to-list 'exec-path "~/.cargo/bin")
Buffer name matches eshell directory
(defun sync-dir-in-buffer-name () (rename-buffer (concat "*eshell* " default-directory) t)) (add-hook 'eshell-mode-hook #'sync-dir-in-buffer-name) (add-hook 'eshell-directory-change-hook #'sync-dir-in-buffer-name)
No message when starting eshell
(setq eshell-banner-message "")
Keybinding to clear the shell
(keymap-set eshell-mode-map "C-l" #'eshell-clear)
We use eat to run any commands that require visuals
(use-package eat) (setq eat-kill-buffer-on-exit t) (add-hook 'eshell-mode-hook #'eat-eshell-mode)
Gospel Specific Things
Some macros to help writing Rocq proofs of Gospel signatures.
(defun gospel-abstract (var) (interactive "sName:") (insert (format "Global Instance _%s_inst : _%s_sig :=" var var)) (newline 1 t) (insert (format "{ %s := }." var)) (backward-char 3)) (defun gospel-lemma (var) (interactive "sName:") (insert (format "#[refine] Global Instance _%s_inst : _%s_sig := { }." var var var)) (newline 1 t) (insert "Proof.") (newline 1 t))
Function to insert Gospel header
(defun gospel-header () (interactive) (insert "(**************************************************************************) (* *) (* GOSPEL -- A Specification Language for OCaml *) (* *) (* Copyright (c) 2018- The VOCaL Project *) (* *) (* This software is free software, distributed under the MIT license *) (* (as described in file LICENSE enclosed). *) (**************************************************************************) "))
Add the preamble necessary to write math symbols in a latex Gospel code block.
(defun gospel-unicode () (interactive) (tag-word-or-region "*?$" "$?*")) (require 'latex) (keymap-set LaTeX-mode-map "C-c C-x C-m" #'gospel-unicode)
Remove escaped Latex code
(defun delete-until-end () (while (and (< (point) (- (point-max) 1)) (not (and (eq (char-after) ?\?) (eq (char-after (+ (point) 1)) ?*)))) (delete-char 1)) (delete-char 2)) (defun delete-gospel-escape () (beginning-of-buffer) (while (< (point) (- (point-max) 1)) (if (and (eq (char-after) ?*) (eq (char-after (+ (point) 1)) ?\?)) (delete-until-end) (forward-char))) (save-buffer)) (add-hook 'org-babel-post-tangle-hook #'delete-gospel-escape)
-e * EXWM
(use-package exwm)
Setting the initial workspace number
(setq exwm-workspace-number 5)
Make it so that EXWM buffers are named after the window they are managing
(add-hook 'exwm-update-class-hook
(lambda () (exwm-workspace-rename-buffer exwm-class-name)))
In an EXWM buffer, the bindings on the left are mapped to the bindings on the right. This way, we can use Emacs keybindings in X windows.
(setq exwm-input-simulation-keys
'(([?\C-b] . [left])
([?\C-f] . [right])
([?\M-f] . [C-right])
([?\M-b] . [C-left])
([?\C-p] . [up])
([?\C-n] . [down])
([?\C-a] . [home])
([?\C-e] . [end])
([?\M-v] . [prior])
([?\M-w] . [C-c])
([?\C-y] . [C-v])
([?\C-_] . [C-z])
([?\C-v] . [next])
([?\C-d] . [delete])
([?\C-s] . [C-f])
([?\C-k] . [S-end delete])
([?\C- ] . [C-a])
([?\C-g] . [escape])
([?\C-j] . [S-return])
([?\C-w] . [C-x])
))
Minor mode to rename Firefox EXWM buffers to the names of the respective tabs.
(use-package exwm-firefox-core) (load-file "~/exwm-firefox.el") (exwm-firefox-mode 1)
Better splitting of windows
(defun my-split-window-right (&optional arg) "Split the current window 70/30 rather than 50/50. A single-digit prefix argument gives the top window arg*10%. We use window-total-width to account for writeroom-mode." (interactive "P") (let ((proportion (* (or arg 6) .1))) (split-window-right (round (* proportion (window-total-width)))))) (global-set-key (kbd "C-x 3") 'my-split-window-right)
Sometimes when switching to an X window, EXWM does not focus on it. This piece of code prevents this.
(advice-add #'exwm-layout--hide
:after (lambda (id)
(with-current-buffer (exwm--id->buffer id)
(setq exwm--ewmh-state
(delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state))
(exwm-layout--set-ewmh-state id)
(xcb:flush exwm--connection))))
Functions to shutdown and reboot the system
(defun efs/shutdown () (interactive) (org-save-all-org-buffers) (async-shell-command "shutdown -h now")) (defun efs/reboot () (interactive) (org-save-all-org-buffers) (async-shell-command "shutdown -r now"))
Mouse follows focus
(use-package exwm-mff)
(add-hook 'exwm-init-hook #'exwm-mff-mode)
Inner "Gaps"
(window-divider-mode 1) (setq window-divider-default-bottom-width 6) (setq window-divider-default-right-width 6) (menu-bar-bottom-and-right-window-divider)
EXWM allows switching to X windows in a different workspace.
(setq exwm-workspace-show-all-buffers 1) (setq exwm-layout-show-all-buffers 1)
Transparent emacs frames.
(set-frame-parameter (selected-frame) 'alpha '(80 . 80)) (add-to-list 'default-frame-alist '(alpha . (70 . 70)))
Update dot files.
(start-process-shell-command "update" nil "cd $HOME/.dot-files && git pull")
Battery Notifications
Id for critical notifications.
(defvar notification-id nil)
This variable is t if the battery was previously charging.
(defvar was-charging t)
This variable is t if the battery was previously fully charged.
(defvar was-full nil)
Notifications for different battery states
(defun battery-critical-notification (charge) (setq notification-id (notifications-notify :timeout 0 :urgency 'high :title (format "Battery level critical %d%%!" charge) :app-icon "/home/tiago/.dot-files/low-battery.png" :replaces-id notification-id))) (defun battery-charging-notification () (setq notification-id (notifications-notify :urgency 'medium :title "Battery charging!" :app-icon "/home/tiago/.dot-files/battery-charging.png" :replaces-id notification-id))) (defun battery-discharging-notification () (setq notification-id (notifications-notify :urgency 'medium :title "Battery discharging!" :app-icon "/home/tiago/.dot-files/battery-charging.png" :replaces-id notification-id))) (defun battery-charged-notification () (setq notification-id (notifications-notify :urgency 'medium :title "Battery charged!" :app-icon "/home/tiago/.dot-files/battery-charged.png" :replaces-id notification-id))) (defun is-charging (data) (equal (alist-get ?L data) "on-line")) (defun is-connected (data) (or (equal (alist-get ?L data) "N/A") (is-charging data))) (defun dcharge (data) (string-to-number (alist-get ?p data))) (defun critical-battery (data) (when (and (not (is-connected data)) (< (dcharge data) 10)) (battery-critical-notification (dcharge data)))) (defun battery-charging (data) (when (and was-charging (not (is-connected data))) (battery-discharging-notification)) (when (and (not was-charging) (is-charging data)) (battery-charging-notification)) (setq was-charging (is-connected data))) (defun battery-full (data) (if (and (eq (dcharge data) 100) (is-charging data)) (unless was-full (setq was-full t) (battery-charged-notification)) (setq was-full nil))) (add-hook 'exwm-init-hook (lambda () (setq battery-update-functions '(critical-battery battery-charging battery-full))))
Keybindings for desktop utilities
We use the desktop-environment package to help us change the volume,
adjust brightness, etc…
(use-package desktop-environment)
(desktop-environment-mode 1)
Disable the keybinding for locking the screen as we use this binding for window navigation
(define-key desktop-environment-mode-map (kbd "s-l") nil t)
Command for muting the volume
(setq desktop-environment-volume-toggle-command "amixer -D pulse set Master 1+ toggle")
Command for setting the volume
(setq desktop-environment-volume-set-command "~/.config/vol_set.sh %s")
Command for getting the current value of the volume
(setq desktop-environment-volume-get-command "amixer -D pulse get Master")
Command for screenshots
(setq desktop-environment-screenshot-directory "~/pictures")
Locking the screen also pauses any media
(setq desktop-environment-screenlock-command "~/.config/lock.sh")
Background processes
Helper function to run a program in the background
(defun efs/run-in-background (command) (let ((command-parts (split-string command "[ ]+"))) (apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
Sound display
(use-package volume)
Run applications after EXWM has initialized.
(defun startup-apps () (interactive) (efs/run-in-background "discord --start-minimized") (efs/run-in-background "dunst") (efs/run-in-background "picom")) (add-hook 'exwm-init-hook #'startup-apps)
Update config files
(start-process-shell-command "config" nil "~/.update.sh")
Auto-pause media when headphones are disconnected
(start-process-shell-command "autopause" nil "~/.config/autopause.sh")
Multiple monitors
Set the initial workspace for each display
(setq exwm-randr-workspace-monitor-plist '(1 "eDP-1" 2 "HDMI-1-0"))
Mouse warping
(setq exwm-workspace-warp-cursor t)
Focus follows mouse
(setq mouse-atuoselect-window t
focus-follows-mouse t)
Have autorandr running in the background to ensure that extra monitors are correctly configured.
(defun efs/update-displays () (efs/run-in-background "autorandr --change --force") (message "Display config: %s" (string-trim (shell-command-to-string "autorandr --current"))) (start-process-shell-command "feh" nil "feh --bg-scale ~/.dot-files/.config/bg/lain-hands.jpeg --bg-scale ~/.dot-files/.config/bg/lain.jpeg")) (add-hook 'exwm-randr-screen-change-hook #'efs/update-displays) (exwm-randr-mode 1)
Keybindings
Keybindings to switch the current workspace
(setq exwm-input-global-keys `(([?\s-r] . exwm-reset) ;; s-r: Reset (to line-mode). ([?\s-w] . exwm-workspace-switch) ;; s-w: Switch workspace. ([?\s-&] . (lambda (cmd) ;; s-&: Launch application. (interactive (list (read-shell-command "$ "))) (start-process-shell-command cmd nil cmd))) ;; s-N: Switch to certain workspace. ,@(mapcar (lambda (i) `(,(kbd (format "s-%d" i)) . (lambda () (interactive) (exwm-workspace-switch-create ,i)))) (number-sequence 0 9)))) (add-hook #'exwm-init-hook (lambda () (interactive) (exwm-workspace-switch-create 1)))
Kills the current buffer.
(exwm-input-set-key (kbd "s-c") 'kill-current-buffer)
Window movement
(exwm-input-set-key (kbd "s-l") 'windmove-right) (exwm-input-set-key (kbd "s-j") 'windmove-left) (exwm-input-set-key (kbd "s-i") 'windmove-up) (exwm-input-set-key (kbd "s-k") 'windmove-down)
Window management
(exwm-input-set-key (kbd "s-L") 'windmove-swap-states-right) (exwm-input-set-key (kbd "s-J") 'windmove-swap-states-left) (exwm-input-set-key (kbd "s-I") 'windmove-swap-states-up) (exwm-input-set-key (kbd "s-K") 'windmove-swap-states-down)
Start a desktop application using switch to buffer
(use-package xdg-launcher :vc (:url "https://github.com/emacs-exwm/xdg-launcher")) (with-eval-after-load 'consult (push 'xdg-launcher-consult-source (cdr (memq 'consult-source-buffer consult-buffer-sources))))
Suspend the computer
(exwm-input-set-key (kbd "s-<escape>") 'desktop-environment-lock-screen)
Open web browser
(defun run-firefox () (interactive) (efs/run-in-background "firefox")) (exwm-input-set-key (kbd "s-<return>") 'run-firefox)
Lists all of my firefox tabs
(defun list-firefox () (interactive) (minibuffer-with-setup-hook (lambda () (insert "firefox ")) (call-interactively #'consult-buffer))) (exwm-input-set-key (kbd "s-f") #'list-firefox)
Enable EXWM
I call scratch-buffer first so that each new workspace opens in a
scratch buffer. I then call server-start to turn the Emacs instance
into a daemon. This is so that when a program tries to open a text
editor, it can connect to the Emacs instance without reloading the
config. The call to exwm-wm-mode is what actually starts EXWM.
(scratch-buffer) (server-start) (exwm-wm-mode)
For some reason autorandr doesn't work on one of my monitors so I have to put this in.
(start-process-shell-command "aaa" nil "xrandr --output eDP-1 --auto --output HDMI-1-0 --auto --primary --above eDP-1")