#+TITLE: luxicks Emacs Configuration #+PROPERTY: header-args :results silent This is my configuration for the emacs editor. - Personal information (name, email) are stored in a separate ~personal.el~ file. - Machine specific settings are stored in a separate ~custom.el~ file. - Both files are loaded automatically. * Set Up use-package Packages provided by =straight.el= https://github.com/radian-software/straight.el #+BEGIN_SRC emacs-lisp (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 6)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) (straight-use-package 'use-package) (setq straight-use-package-by-default t) (package-initialize) (straight-use-package 'bind-key) #+end_src * Theming #+begin_src emacs-lisp (use-package modus-themes :straight t :config ;; Add all your customizations prior to loading the themes (setq modus-themes-italic-constructs t modus-themes-bold-constructs nil) ;; Maybe define some palette overrides, such as by using our presets (setq modus-themes-common-palette-overrides modus-themes-preset-overrides-intense) ;; Load the theme of your choice. (load-theme 'modus-operandi t) (define-key global-map (kbd "") #'modus-themes-toggle)) #+end_src *Set up the default frame look* #+begin_src emacs-lisp (setq default-frame-alist (append (list '(width . 90) '(height . 50) '(vertical-scroll-bars . nil) '(internal-border-width . 5)))) #+end_src * Fix Defaults ** Hide UI elements Remove all those UI elements. They do not look good and waste space. #+BEGIN_SRC emacs-lisp (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1) (tooltip-mode -1) (fringe-mode -1) #+END_SRC ** Disable file backups Emacs sure loves to clutter directories with backup files. #+BEGIN_SRC emacs-lisp (setq make-backup-files nil) (setq auto-save-default nil) (setq create-lockfiles nil) #+END_SRC ** File management Configure dired to only use one buffer. #+BEGIN_SRC emacs-lisp (setf dired-kill-when-opening-new-dired-buffer t) (setq dired-listing-switches "-laGh1v --group-directories-first") (setq dired-omit-files (rx (or (seq bol (? ".") "#") ;; emacs autosave files (seq bol "." (not (any "."))) ;; dot-files (seq "~" eol) ;; backup-files (seq bol "CVS" eol) ;; CVS dirs ))) (defun my-dired-init () "to be run as hook for `dired-mode'." (interactive) (dired-hide-details-mode 1) (dired-omit-mode 1)) (add-hook 'dired-mode-hook 'my-dired-init) #+END_SRC Use ranger inside of emacs #+BEGIN_SRC emacs-lisp (use-package ranger :straight t) (ranger-override-dired-mode t) #+END_SRC ** Other Settings #+begin_src emacs-lisp ;; The default encoding should be utf-8 everywhere (prefer-coding-system 'utf-8) ;; All "Yes or No" questions can be shortend to "y or n". (defalias 'yes-or-no-p 'y-or-n-p) ;; No more startup messages and screens (setq inhibit-startup-screen t) (setq initial-buffer-choice nil) (defun display-startup-echo-area-message () (message "Welcome Back!")) ;; Highlight matching braces (show-paren-mode t) ;; cua-mode. Like any other editor (cua-mode t) ;; Configure the cursor (setq-default cursor-type 'bar indent-tabs-mode nil cursor-in-non-selected-windows nil) (blink-cursor-mode 0) ;; Default column with (set-fill-column 95) ;; Start up in the home directory (setq default-directory "~/") ;; Make C-k always kill the whole line (setq kill-whole-line t) ;; Do not ding. Ever. (setq ring-bell-function 'ignore) ;; Dialogues always go in the modeline. (setq use-dialog-box nil) ;; Show tooltips on hover and not in the echo area. ;; Those are often cut of. (tooltip-mode) ;; Better line wraping (global-visual-line-mode 1) #+end_src ** Keybindings #+BEGIN_SRC emacs-lisp (bind-key "C-x k" 'kill-buffer-with-prejudice) (bind-key "C-x C-k" 'kill-buffer-and-window) (bind-key "M-p" 'switch-to-previous-buffer) (bind-key "M-i" 'delete-indentation) (bind-key "C-+" 'text-scale-increase) (bind-key "C--" 'text-scale-decrease) ;; buffer-list is not a good default (bind-key "C-x C-b" 'ibuffer) (bind-key "C-c n" 'display-line-numbers-mode) (global-set-key (kbd "") 'menu-bar-mode) #+END_SRC Unbind useless keys. #+BEGIN_SRC emacs-lisp (unbind-key "C-") ;; prevent switching to tab mode randomly (unbind-key "C-h n") ;; I have never wanted to see emacs news ever (unbind-key "C-h C-n") ;; why on earth is it bound to two keybindings?? (unbind-key "C-x C-d") ;; list-directory is utterly useless given the existence of dired (unbind-key "C-x C-r") ;; as is find-file-read-only #+END_SRC * Useful Functions ** Edit This File A simple funtion to open this file for quick editing. #+BEGIN_SRC emacs-lisp (defun edit-config () (interactive) (find-file "~/.emacs.d/README.org")) #+END_SRC ** Reformating Reindet the whole buffer with ~F1~ #+BEGIN_SRC emacs-lisp (defun lux/indent-buffer () "Reindents the whole buffer" (interactive) (save-excursion (indent-region (point-min) (point-max) nil))) (global-set-key [f1] 'lux/indent-buffer) #+END_SRC ** Window Splitting These are functions for splitting windows and move the cursor over immediately. #+BEGIN_SRC emacs-lisp (defun lux/split-right-and-enter () "Split the window to the right and enter it." (interactive) (split-window-right) (other-window 1)) (bind-key "M-3" 'lux/split-right-and-enter) (defun lux/split-below-and-enter () "Split the window down and enter it." (interactive) (split-window-below) (other-window 1)) (bind-key "M-2" 'lux/split-below-and-enter) #+END_SRC Rebind the default window controls to use "M-*" keys for ease-of-use #+begin_src emacs-lisp (bind-key "M-1" 'delete-other-windows) (bind-key "C-M-1" 'delete-other-windows) (bind-key "M-0" 'delete-window) #+end_src ** Quick buffer switching #+BEGIN_SRC emacs-lisp (defun switch-to-previous-buffer () "Switch to previously open buffer.Repeated invocations toggle between the two most recently open buffers." (interactive) (switch-to-buffer (other-buffer (current-buffer) 1))) #+END_SRC * Fonts Set up the fonts to use. #+begin_src emacs-lisp (set-face-attribute 'default nil :font "Iosevka Term-12") (set-face-attribute 'fixed-pitch nil :font "Iosevka Term-12") (set-face-attribute 'variable-pitch nil :font "Iosevka Aile") (let* ((variable-tuple (cond ((x-list-fonts "Iosevka Aile") '(:font "Iosevka Aile")) ((x-family-fonts "Sans Serif") '(:family "Sans Serif")) (nil (warn "Cannot find a Sans Serif Font. Install Source Sans Pro.")))) (base-font-color (face-foreground 'default nil 'default)) (headline `(:inherit default :weight bold :foreground ,base-font-color))) (custom-theme-set-faces 'user `(org-level-8 ((t (,@headline ,@variable-tuple)))) `(org-level-7 ((t (,@headline ,@variable-tuple)))) `(org-level-6 ((t (,@headline ,@variable-tuple)))) `(org-level-5 ((t (,@headline ,@variable-tuple)))) `(org-level-4 ((t (,@headline ,@variable-tuple)))) `(org-level-3 ((t (,@headline ,@variable-tuple)))) `(org-level-2 ((t (,@headline ,@variable-tuple)))) `(org-level-1 ((t (,@headline ,@variable-tuple)))) `(org-document-title ((t (,@headline ,@variable-tuple :underline nil)))))) (custom-theme-set-faces 'user '(variable-pitch ((t (:family "Iosevka Aile" :height 120 :weight thin)))) '(fixed-pitch ((t ( :family "Iosevka Term" :height 120))))) #+end_src * Completion ** Ivy Use Ivy to make minibuf promts better. Adds the ability to sort and filter. #+BEGIN_SRC emacs-lisp (use-package ivy :straight t :diminish :init (ivy-mode 1) (unbind-key "S-SPC" ivy-minibuffer-map) (setq ivy-height 30 ivy-use-virtual-buffers t ivy-use-selectable-prompt t) :bind (("C-x b" . ivy-switch-buffer) ("C-c C-r" . ivy-resume) ("C-s" . swiper))) ;; ivy-rich makes Ivy look a little bit more like Helm. (use-package ivy-rich :straight t :after counsel :custom (ivy-virtual-abbreviate 'full ivy-rich-switch-buffer-align-virtual-buffer t ivy-rich-path-style 'abbrev) :init (ivy-rich-mode)) (use-package ivy-hydra :straight t) #+END_SRC ** Smex Sort commands by recency in ivy windows #+BEGIN_SRC emacs-lisp (use-package smex :straight t) #+END_SRC ** Counsel #+BEGIN_SRC emacs-lisp (use-package counsel :straight t :after ivy :init (counsel-mode 1) :bind (("C-c ;" . counsel-M-x) ("C-c U" . counsel-unicode-char) ("C-c i" . counsel-imenu) ("C-c y" . counsel-yank-pop) ("C-c r" . counsel-recentf) :map ivy-minibuffer-map ("C-r" . counsel-minibuffer-history)) :diminish) #+END_SRC ** Ido #+begin_src emacs-lisp (use-package ido :straight t :config (ido-mode 1) :bind (("C-x f" . ido-find-file))) #+end_src ** Autocompletion #+BEGIN_SRC emacs-lisp (use-package auto-complete :straight t :config (ac-config-default)) #+END_SRC * Magit Magit is THE go to package for using git in emacs. #+BEGIN_SRC emacs-lisp (use-package magit :straight t :bind (("C-c g" . magit-status)) :diminish magit-auto-revert-mode :diminish auto-revert-mode :custom (magit-remote-set-if-missing t) (magit-diff-refine-hunk t) :config (magit-auto-revert-mode t) (advice-add 'magit-refresh :before #'maybe-unset-buffer-modified) (advice-add 'magit-commit :before #'maybe-unset-buffer-modified) (setq magit-completing-read-function 'ivy-completing-read) (add-to-list 'magit-no-confirm 'stage-all-changes)) (use-package libgit :straight t :disabled :after magit) #+END_SRC The ~advice-add~ entries are thereto stop magit from bugging us to save buffers when commiting and refreshing. ** Helper Functions #+BEGIN_SRC emacs-lisp (autoload 'diff-no-select "diff") (defun current-buffer-matches-file-p () "Return t if the current buffer is identical to its associated file." (when (and buffer-file-name (buffer-modified-p)) (diff-no-select buffer-file-name (current-buffer) nil 'noasync) (with-current-buffer "*Diff*" (and (search-forward-regexp "^Diff finished \(no differences\)\." (point-max) 'noerror) t)))) #+END_SRC Clear modified bit on all unmodified buffers #+BEGIN_SRC emacs-lisp (defun maybe-unset-buffer-modified (&optional _) (interactive) (dolist (buf (buffer-list)) (with-current-buffer buf (when (and buffer-file-name (buffer-modified-p) (current-buffer-matches-file-p)) (set-buffer-modified-p nil))))) #+END_SRC Don't prompt to save unmodified buffers on exit. #+BEGIN_SRC emacs-lisp (advice-add 'save-buffers-kill-emacs :before #'maybe-unset-buffer-modified) #+END_SRC #+BEGIN_SRC emacs-lisp (defun kill-buffer-with-prejudice (&optional _) "Kill a buffer, eliding the save dialogue if there are no diffs." (interactive) (when (current-buffer-matches-file-p) (set-buffer-modified-p nil)) (kill-buffer)) #+END_SRC * Org Mode Configuration to make org-mode better as a word processor #+BEGIN_SRC emacs-lisp (use-package org-modern :straight t :hook (org-mode . org-modern-mode)) (setq ;; Edit settings org-auto-align-tags nil org-tags-column 0 org-catch-invisible-edits 'show-and-error org-special-ctrl-a/e t org-insert-heading-respect-content t ;; Org styling, hide markup etc. org-hide-emphasis-markers t org-pretty-entities t ) ;; Ellipsis styling (setq org-ellipsis "…") (set-face-attribute 'org-ellipsis nil :inherit 'default :box nil) ;; Always collapse org files (setq org-startup-folded t) #+END_SRC ** Archive Location When archiving items in org files, the default ist to crate a separate file named ~.org_archive~. This clutters up my notes folder quite a bit, as I use a lot of separate files with thier respective archives. All archives should be stored in a single ~.archive~ file per directory. #+BEGIN_SRC emacs-lisp (setq org-archive-location "./.archive::* From %s") #+END_SRC ** Templates *** Babel Here we set custom templates to be used for structure expansion. These are used when we type "<" folowed by the shortcut for a template and hit "TAB". e.g. "") 'copilot-accept-completion) (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion) (define-key copilot-completion-map (kbd "M--") 'copilot-complete) #+end_src ** Elisp Some customization for writing elisp #+BEGIN_SRC emacs-lisp (defun my-elisp-mode-hook () "My elisp customizations." (electric-pair-local-mode 1) (add-hook 'before-save-hook 'check-parens nil t) (auto-composition-mode nil)) (add-hook 'emacs-lisp-mode-hook 'my-elisp-mode-hook) #+END_SRC ** Common Lisp #+BEGIN_SRC emacs-lisp (setq inferior-lisp-program "sbcl") (use-package slime :straight t) (slime-setup '(slime-fancy slime-quicklisp slime-asdf)) (add-hook 'slime-repl-mode-hook (lambda () (paredit-mode +1))) #+END_SRC * Load additional files All information about the current user should reside in the ~personal.el~ file. This file contains personal information like name, email or other identifying information. This file should contain definitions, that are the same on every device, but sould not be commited to a repository. #+BEGIN_SRC emacs-lisp (setq personal-file "~/.emacs.d/personal.el") (load personal-file 'noerror) #+END_SRC Load a custom file from the emacs home dir. This file is specific to the machine emacs runs on. It conatins customizations and file locations that are machine dependend. #+BEGIN_SRC emacs-lisp (setq custom-file "~/.emacs.d/custom.el") (load custom-file 'noerror) #+END_SRC