From b67cd920757ba8e68140fe90c787d1a4690ee240 Mon Sep 17 00:00:00 2001 From: noa Date: Mon, 17 Feb 2025 13:06:57 +0800 Subject: First pass at rearranging init.el to make more sense --- emacs/init.el | 1117 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 578 insertions(+), 539 deletions(-) diff --git a/emacs/init.el b/emacs/init.el index fa1a872..1700883 100644 --- a/emacs/init.el +++ b/emacs/init.el @@ -4,14 +4,7 @@ ;; (profiler-start 'cpu+mem) -;; Things we have, or want to have, in this configuration: -;; - Make a nice interface -;; - Programming -;; - Offline web browsing -;; - Reading mail -;; - Sending mail -;; - Bibliography management -;; - Taking notes +;;; Getting started (add-to-list 'load-path (expand-file-name (concat user-emacs-directory "site-lisp"))) @@ -30,9 +23,7 @@ ;; keep the emacs directory clean (use-package no-littering) -;; It is often useful to be able to run a command while i am already in the process of running a command in the minibuffer. This is rarely two extended commands; usually it is completion. -(use-package mb-depth - :hook (after-init . minibuffer-depth-indicate-mode)) +;;; Make a nice interface (use-package tubthumping-theme :disabled t @@ -40,7 +31,6 @@ :config (load-theme 'tubthumping t)) -;;; Fonts ;; Using a proportional font is the right way to do things, but emacs is very old and comes from a time before the innovation of legibility. As a result, there are some things that require a monospaced font, so i set one here. (custom-set-faces '(default ((t (:family "Noto Sans Mono" :height 120)))) @@ -80,55 +70,24 @@ :bind (([remap scroll-up-command] . pixel-scroll-interpolate-down) ([remap scroll-down-command] . pixel-scroll-interpolate-up))) -;; Update the calendar. We want weeks to start on a monday, the first day of the week. Holidays should be highlighted, and the date format should put the year first. -(use-package calendar - :defer t - :custom - (calendar-week-start-day 1) - (calendar-date-style 'iso) +;; Nicer terminal emacs +(set-display-table-slot standard-display-table 'vertical-border (make-glyph-code ?│)) +(setq mode-line-end-spaces nil) - :config - ;; Ensure the calendar always displays at the bottom of the screen, rather than wrapping weirdly and looking bad when it shows up in a side window. - (add-to-list 'display-buffer-alist - '("\\*Calendar\\*" - (display-buffer-in-side-window) - (side . bottom)))) +(use-package xclip) +(unless (display-graphic-p) (xclip-mode 1)) -;; Squeeze text into a more legible sliver. -(use-package visual-fill-column - :custom - (visual-fill-column-enable-sensible-window-split t) - (visual-fill-column-fringes-outside-margins nil) ; Keep fringes on the inside so relevant icons are in the right place - (visual-fill-column-center-text t) - :hook - ((text-mode . visual-fill-column-mode) - (eww-after-render . visual-line-fill-column-mode)) - ) -(use-package simple - :hook ((text-mode . visual-line-mode) - (after-init . auto-save-mode)) - :bind ([remap kill-buffer] . kill-current-buffer) - :custom - (save-interprogram-paste-before-kill t) - (kill-ring-max 25) - ;; Hide commands in M-x which do not work in the current mode. - (read-extended-command-predicate 'command-completion-default-include-p) - ;; My brain is not ready for advanced emacs undo - (undo-no-redo t) - :bind (("C-z" . undo) - ("C-S-z" . undo-redo))) -;; (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust) +;; Don't advertise gnu on startup +(setq inhibit-startup-echo-area-message "noa") ;; #userfreedom -;; Doesn't indent nicely with proportional fonts -;; (use-package adaptive-wrap :ensure t) -;; (add-hook 'visual-fill-column-mode-hook #'visual-wrap-prefix-mode) ;; Make tooltip information appear consistently in the echo area (use-package tooltip :custom (tooltip-mode nil)) + ;; startup.el does not provide itself, cannot be used with use-package (setopt inhibit-startup-screen t) @@ -146,58 +105,130 @@ ;; Doesn't work great with a proportional font but could still be useful. (global-set-key (kbd "C-S-") #'mouse-drag-region-rectangle) -;; Markdown -(use-package markdown-mode - :mode ("\\.\\(?:md\\|markdown\\|mkd\\|mdown\\|mkdn\\|mdwn\\)\\'" . markdown-mode) +;;; Minibuffer + +;; It is often useful to be able to run a command while i am already in the process of running a command in the minibuffer. This is rarely two extended commands; usually it is completion. + +(use-package savehist :custom - (markdown-disable-tooltip-prompt t) ; When inserting a link, only prompt for url and link text - (markdown-enable-html nil) ; I don't believe markdown should have html - (markdown-hide-urls t) ; Make inline urls look a bit neater - (markdown-url-compose-char ?~) - (markdown-max-image-size '(640 . 480)) + (savehist-file "~/.config/emacs/savehist") + (savehist-additional-variables + '(kill-ring + command-history + set-variable-value-history + custom-variable-history + query-replace-history + read-expression-history + minibuffer-history + read-char-history + face-name-history + bookmark-history + file-name-history)) + :hook (after-init . savehist-mode)) - ;; :hook ((markdown-mode . noa/set-buffer-name-to-markdown-title)) +(use-package mb-depth + :hook (after-init . minibuffer-depth-indicate-mode)) + +(use-package vertico + :hook (after-init . vertico-mode) + :custom + (vertico-resize nil) ;; don't shrink when there are less candidates + ;; (vertico-group-format #("%s " 0 3 (face vertico-group-title))) ;; Don't put a vertical line across group titles ) -;; Use abbrev as a simple autocorrect mode. M-x list-abbrevs for stats. -;; Check ~/.config/emacs/abbrev_defs to update any mistakes -(use-package abbrev - :hook (text-mode . abbrev-mode)) +;; Interact with vertico with the mouse. +(use-package vertico-mouse + :after vertico + :custom (vertico-mouse-mode t)) -(use-package flyspell - :hook (text-mode . flyspell-mode) - :custom - (flyspell-abbrev-p t)) +;; More comfortable directory navigation +(use-package vertico-directory + :after vertico + :bind (:map vertico-map + ("RET" . vertico-directory-enter) + ("DEL" . vertico-directory-delete-char) + ("DEL" . vertico-directory-delete-word)) + ;; If i type ~/ etc in a find-file prompt, get rid of the preceding directory names for a cleaner look. + :hook (rfn-eshadow-update-overlay . vertico-directory-tidy)) -(use-package writegood-mode - :hook (text-mode . writegood-mode)) +;; Prefix the current candidate with “» ”. From +;; https://github.com/minad/vertico/wiki#prefix-current-candidate-with-arrow +(advice-add #'vertico--format-candidate :around + (lambda (orig cand prefix suffix index _start) + (setq cand (funcall orig cand prefix suffix index _start)) + (concat + (if (= vertico--index index) + (propertize "» " 'face 'vertico-current) + " ") + cand))) -;; A nicer package for spellchecking -(use-package jinx - :disabled t - :hook (text-mode . jinx-mode) - :commands (jinx-correct jinx-correct-all) - :config - (put 'jinx-overlay 'mouse-face '(jinx-misspelled highlight)) ;; Use standard mouse face for jinx overlays - (add-to-list 'jinx-exclude-regexps '(t "\\cc")) ;; Don't check chinese characters +;; Annotations for completing-read + +;; Taken from configuration for the vertico stack: +;; Add prompt indicator to `completing-read-multiple'. +;; We display [CRM], 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) + +(use-package marginalia + :defer t + :hook (after-init . marginalia-mode) + ;; :custom + ;; (marginalia-mode t) ) -;; Automatically creates an abbrev for words i correct, so i don't make the same mistake twice -(defun jinx--add-to-abbrev (overlay word) - "Add abbreviation to `global-abbrev-table'. -The misspelled word is taken from OVERLAY. WORD is the corrected word." - (let ((abbrev (buffer-substring-no-properties - (overlay-start overlay) - (overlay-end overlay)))) - (message "Abbrev: %s -> %s" abbrev word) - (define-abbrev global-abbrev-table abbrev word))) -(advice-add 'jinx--correct-replace :before #'jinx--add-to-abbrev) -(use-package help +;; Basic matches candidates with the same text before the point, and the text after the point as a substring. +;; Orderless takes any number of space separated components and displays candidates that much every component in any order. +;; I don't actually know if these make any difference when i've specified a different completion style. +(use-package minibuffer + :custom + (read-file-name-completion-ignore-case t)) + +(use-package orderless + :after minibuffer + :custom + (completion-styles '(orderless basic)) + (completion-category-overrides '((file (styles basic partial-completion))))) + + + +(use-package consult + :defer t + ;; :commands (consult-complete-in-region) + :bind + ( + ;; ([remap switch-to-buffer] . consult-buffer) + ([remap yank-pop] . consult-yank-pop) + ([remap goto-line] . consult-goto-line) + ;; ([remap imenu] . consult-imenu) + ;; ([remap info] . consult-info) + ([remap repeat-complex-command] . consult-complex-command) + ([remap bookmark-jump] . consult-bookmark) + ("C-x C-r" . consult-recent-file) + :map comint-mode-map + ([remap comint-history-isearch-backward-regexp] . consult-history)) + ;; :custom + ;; Use consult for completion at point + ;; (completion-in-region-function 'consult-completion-in-region) + ) + +;;; Dictionary +;; Emacs has built in support for interfacing with dictd. With dictd and some dictionaries installed on debian, this works fine out of the box. +;; Unfortunately, dictionaries in this format tend to be hard wrapped and there isn't a lot of coverage outside of english +(use-package dictionary :defer t :custom - ;; When opening source files from a help window, use the same window - (help-window-keep-selected t)) + (dictionary-search-interface nil)) + +;;; Offline web browsing + ;; Despite the name, eww is a delight to use for text-heavy websites. (use-package browse-url @@ -231,168 +262,56 @@ The misspelled word is taken from OVERLAY. WORD is the corrected word." (goto-address-url-face 'link) (goto-address-url-mouse-face 'highlight)) + +(defvar noa/record-url-file "~/Documents/Library/urls") +(defun noa/record-url (url &rest args) + "An alternative browser function that appends the url to a file. We do not pay attention to any arguments." + (write-region (concat url "\n") nil noa/record-url-file 'append)) + +;;; Programming + (use-package flymake :hook (prog-mode . flymake-mode)) -(use-package emacs - :custom - (window-combination-resize t) - (window-resize-pixelwise t) - (frame-resize-pixelwise t) - (shell-file-name "/bin/sh") - (completion-ignore-case t) - (read-buffer-completion-ignore-case t) - ;; yes-or-no-p uses y-or-no-p, and read-answer accepts single key press answers - (use-short-answers t) - (history-length 250) - ;; Use a bar cursor and blink it and don't stop blinking it. - (cursor-type 'bar) - ;; Support opening new minibuffers from inside existing minibuffers. - (enable-recursive-minibuffers t) - ;; Whether to drop into the debugger on any error. This seems cool, but in practice is a bit annoying. - (debug-on-error nil) - (create-lockfiles nil) - (auto-save-interval 6) ;; every six keystrokes - (auto-save-timeout 5) ;; every 5 seconds - (auto-save-no-message t) - ;; Always give me a line of text when i'm near the edges of the screen - (scroll-margin 2)) +;; If i write a script, i will always run chmod +x after saving it. This command means i don't have to do that. +(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) -(use-package dired +(use-package sly + :disabled t + :if (executable-find "sbcl") + :ensure t + :commands 'sly + :custom ((inferior-lisp-program (executable-find "sbcl")) + (common-lisp-hyperspec-root "file:///usr/share/doc/hyperspec/")) + :mode ((rx (or ".lisp" ".cl") eos) . common-lisp-mode)) + +;; Write url to text file +(use-package ediff :defer t :custom - (dired-recursive-deletes 'always) ;; Don't ask me things - (dired-recursive-copies 'always) ;; Don't ask me things - (dired-dwim-target t) ;; Synergy between two dired windows - ;; I have quite a bit of storage and also make bad decisions regularly - ;; People who have used computers in the last forty years or so will likely be familiar with this innovation. - (delete-by-moving-to-trash t) - + (ediff-window-setup-function 'ediff-setup-windows-plain) + (ediff-split-window-function 'split-window-horizontally)) +(use-package elastic-indent + :disabled t + :hook (prog-mode . elastic-indent-mode)) - ;; -l is required by dired - ;; -a to also show dotfiles - ;; -v to sort numbers properly - ;; -F to visually distinguish different types of file - ;; -h for human readable file sizes - ;; I won't explain the meaning of the long flag. - (dired-listing-switches "-alvFh --group-directories-first") - -;; By default, don't show dired details - :hook ((dired-mode . dired-hide-details-mode) - (dired-mode . hl-line-mode)) - ) - -;; Show the recursive size of directories -(use-package dired-du +;; Change the width of tab characters within lines to make subsequent lines form a table-like layout. +(use-package elastic-table :disabled t - :hook (dired-mode . dired-du-mode) - :after dired - :custom - (dired-du-size-format t)) - -;; Some tramp settings. -(use-package files - :custom - (view-read-only t) - (confirm-kill-emacs 'y-or-n-p) - ;; We are on a unix system, so it makes sense to end files in the unix system way. I'm surprised this isn't the default. - (require-final-newline t) - - ;; This behaviour changes how we visit symlinks. - (find-file-visit-truename t) - - (remote-file-name-inhibit-locks t) - (remote-file-name-inhibit-auto-save t) - (remote-file-name-inhibit-auto-save-visited t) - (backup-directory-alist '(("." . "~/.config/emacs/backups/"))) - (make-backup-files nil) - (backup-by-copying t) - (version-control t) - ;; this will auto save to the current file - (auto-save-visited-mode t) - (auto-save-visited-interval 0.1) - (save-silently t) ;; don't message when saving - ) -(use-package tramp - :defer t - :custom - (tramp-inline-compress-start-size 1000) - (tramp-verbose 3)) -;; (add-to-list 'tramp-remote-path 'tramp-own-remote-path) - -;; I only use git, and this apparently speeds up tramp. -(use-package vc-hooks - :after vc - :custom - (vc-handled-backends '(Git))) - -;; It seems that tramp can also be made faster with these .ssh/config settings. - -;; Host * -;; ControlMaster auto -;; ControlPath ~/.ssh/master-%h:%p -;; ControlPersist 10m -;; ForwardAgent yes -;; ServerAliveInterval 60 - -;; Don't override display actions when i manually initiate a buffer switch. -(use-package window - :custom - ;; My computer has a small screen, so i find that it's more beneficial for me to split the frame into columns, so i get more context. However, splitting in this way only gives me a (window-width) of 61, so emacs will always split into vertically stacked windows. By setting this to 80, the first split should always be vertical. - (split-width-threshold 80) - (switch-to-buffer-obey-display-actions t) - ;; C-l from top to bottom - (recenter-positions '(top middle bottom))) - -(use-package frame - :hook (after-init . window-divider-mode) - :custom - (window-divider-default-right-width 1) - (window-divider-default-bottom-width 1) - (window-divider-default-places t)) - -;; Taken from configuration for the vertico stack: -;; Add prompt indicator to `completing-read-multiple'. -;; We display [CRM], 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) - -(use-package recentf - :hook (after-init . recentf-mode) - :custom - (recentf-max-menu-items 50)) - -(use-package bookmark - :defer t - :custom - (bookmark-default-file "~/.config/emacs/bookmarks")) - -;; Unfill commands -(defun unfill-paragraph () - "Takes a multi-line paragraph and makes it into a single line of text." - (interactive) - (let ((fill-column (point-max))) - (fill-paragraph nil))) -(global-set-key (kbd "M-Q") #'unfill-paragraph) - -;; Remember my position in files -(use-package saveplace - :hook (after-init . save-place-mode)) - -;; Disable disabled commands -(setq disabled-command-function nil) + :hook (prog-mode-hook . elastic-table-mode)) -;; Don't save changes in the customize interface -(use-package cus-edit - :custom - (custom-file (make-temp-file "custom"))) +;; Indenting lisp with tabs is horrible. H/t acdw +(defvar space-indent-modes '(emacs-lisp-mode + lisp-interaction-mode + lisp-mode + scheme-mode + python-mode) + "Modes to indent with spaces, not tabs.") +(add-hook 'prog-mode-hook + (defun indent-tabs-mode-maybe () + (setq indent-tabs-mode + (if (apply #'derived-mode-p space-indent-modes) nil t)))) ;; Scroll along with text in compilation mode, and stop scrolling at the first error. (use-package compile @@ -400,167 +319,46 @@ The misspelled word is taken from OVERLAY. WORD is the corrected word." :custom (compilation-scroll-output 'first-error)) -;; Don't advertise gnu on startup -(setq inhibit-startup-echo-area-message "noa") ;; #userfreedom - -;; Better buffer naming -(use-package uniquify - :custom - (uniquify-after-kill-buffer-p t) - (uniquify-buffer-name-style 'forward) - (uniquify-ignore-buffers-re "^\\*") - (uniquify-separator "/")) -;; Emacs server -;; (unless (server-running-p) (server-start))) +;;; Writing prose -;; Better support for long lines. -(use-package so-long - :hook (after-init . global-so-long-mode)) - -;; Automatically revert buffers when they change on disk. This doesn't apply to tramp. -(use-package autorevert - :hook (after-init . global-auto-revert-mode) - :custom - (global-auto-revert-non-file-buffers t)) -(use-package vc-hooks - :custom - (vc-follow-symlinks 'ask)) - -;; Minibuffer candidate completion -;; Display completion candidates vertically -(use-package vertico - :hook (after-init . vertico-mode) - :custom - (vertico-resize nil) ;; don't shrink when there are less candidates - ;; (vertico-group-format #("%s " 0 3 (face vertico-group-title))) ;; Don't put a vertical line across group titles - ) - -;; Interact with vertico with the mouse. -(use-package vertico-mouse - :after vertico - :custom (vertico-mouse-mode t)) - -;; More comfortable directory navigation -(use-package vertico-directory - :after vertico - :bind (:map vertico-map - ("RET" . vertico-directory-enter) - ("DEL" . vertico-directory-delete-char) - ("DEL" . vertico-directory-delete-word)) - ;; If i type ~/ etc in a find-file prompt, get rid of the preceding directory names for a cleaner look. - :hook (rfn-eshadow-update-overlay . vertico-directory-tidy)) - -;; Prefix the current candidate with “» ”. From -;; https://github.com/minad/vertico/wiki#prefix-current-candidate-with-arrow -(advice-add #'vertico--format-candidate :around - (lambda (orig cand prefix suffix index _start) - (setq cand (funcall orig cand prefix suffix index _start)) - (concat - (if (= vertico--index index) - (propertize "» " 'face 'vertico-current) - " ") - cand))) - -;; Annotations for completing-read -(use-package marginalia - :defer t - :hook (after-init . marginalia-mode) - ;; :custom - ;; (marginalia-mode t) - ) - - -;; Basic matches candidates with the same text before the point, and the text after the point as a substring. -;; Orderless takes any number of space separated components and displays candidates that much every component in any order. -;; I don't actually know if these make any difference when i've specified a different completion style. -(use-package minibuffer - :custom - (read-file-name-completion-ignore-case t)) - -(use-package orderless - :after minibuffer - :custom - (completion-styles '(orderless basic)) - (completion-category-overrides '((file (styles basic partial-completion))))) - -;; History - -(use-package savehist - :custom - (savehist-file "~/.config/emacs/savehist") - (savehist-additional-variables - '(kill-ring - command-history - set-variable-value-history - custom-variable-history - query-replace-history - read-expression-history - minibuffer-history - read-char-history - face-name-history - bookmark-history - file-name-history)) - :hook (after-init . savehist-mode)) - -(use-package consult - :defer t - ;; :commands (consult-complete-in-region) - :bind - ( - ;; ([remap switch-to-buffer] . consult-buffer) - ([remap yank-pop] . consult-yank-pop) - ([remap goto-line] . consult-goto-line) - ;; ([remap imenu] . consult-imenu) - ;; ([remap info] . consult-info) - ([remap repeat-complex-command] . consult-complex-command) - ([remap bookmark-jump] . consult-bookmark) - ("C-x C-r" . consult-recent-file) - :map comint-mode-map - ([remap comint-history-isearch-backward-regexp] . consult-history)) - ;; :custom - ;; Use consult for completion at point - ;; (completion-in-region-function 'consult-completion-in-region) - ) +;; Use abbrev as a simple autocorrect mode. M-x list-abbrevs for stats. +;; Check ~/.config/emacs/abbrev_defs to update any mistakes +(use-package abbrev + :hook (text-mode . abbrev-mode)) -(use-package consult-recoll - :bind ("" . consult-recoll) +(use-package flyspell + :hook (text-mode . flyspell-mode) :custom - (consult-recoll-inline-snippets nil) - (consult-recoll-group-by-mime nil)) - -;; Some settings for nicer completion with the default emacs completion buffer. I don't use this, because i use vertico. -;; (setopt completion-auto-help 'lazy -;; completion-auto-select 'second-tab -;; completion-show-help nil -;; completions-sort nil -;; completions-header-format nil) - -;; Completion styles -;; When given a prompt to select from a list of candidates, there are quite a lot of things we can tweak to improve the experience. + (flyspell-abbrev-p t)) -;; Make leading whitespace a uniform width, so indentation still works with proportional fonts -(use-package elastic-indent - :disabled t - :hook (prog-mode . elastic-indent-mode)) +(use-package writegood-mode + :hook (text-mode . writegood-mode)) -;; Change the width of tab characters within lines to make subsequent lines form a table-like layout. -(use-package elastic-table +;; A nicer package for spellchecking +(use-package jinx :disabled t - :hook (prog-mode-hook . elastic-table-mode)) + :hook (text-mode . jinx-mode) + :commands (jinx-correct jinx-correct-all) + :config + (put 'jinx-overlay 'mouse-face '(jinx-misspelled highlight)) ;; Use standard mouse face for jinx overlays + (add-to-list 'jinx-exclude-regexps '(t "\\cc")) ;; Don't check chinese characters + ) + +;; Automatically creates an abbrev for words i correct, so i don't make the same mistake twice +(defun jinx--add-to-abbrev (overlay word) + "Add abbreviation to `global-abbrev-table'. +The misspelled word is taken from OVERLAY. WORD is the corrected word." + (let ((abbrev (buffer-substring-no-properties + (overlay-start overlay) + (overlay-end overlay)))) + (message "Abbrev: %s -> %s" abbrev word) + (define-abbrev global-abbrev-table abbrev word))) +(advice-add 'jinx--correct-replace :before #'jinx--add-to-abbrev) + + -;; Indenting lisp with tabs is horrible. H/t acdw -(defvar space-indent-modes '(emacs-lisp-mode - lisp-interaction-mode - lisp-mode - scheme-mode - python-mode) - "Modes to indent with spaces, not tabs.") -(add-hook 'prog-mode-hook - (defun indent-tabs-mode-maybe () - (setq indent-tabs-mode - (if (apply #'derived-mode-p space-indent-modes) nil t)))) ;; Make sentence navigation commands work for people who are wrong ;; NOTE: paragraphs does not provide itself @@ -569,67 +367,15 @@ The misspelled word is taken from OVERLAY. WORD is the corrected word." :custom (sentence-end-double-space nil)) -;; If i write a script, i will always run chmod +x after saving it. This command means i don't have to do that. -(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) - -;; Zap up to char -(global-set-key (kbd "M-z") 'zap-up-to-char) - -;; Insert date and time at point -;; Sometimes it's useful to be able to add a timestamp. I use this for notes. Use the same binding as notepad.exe. -(defun noa/insert-date (&optional time) - "Insert the current date into the buffer. -With prefix argument TIME, also add the current time." - (interactive "P") - (if time - (insert (format-time-string "[%Y-%m-%d %H:%M]")) - (insert (format-time-string "[%Y-%m-%d]")))) -(defun noa/insert-datetime () +;; Unfill commands +(defun unfill-paragraph () + "Takes a multi-line paragraph and makes it into a single line of text." (interactive) - (noa/insert-date t)) - -(global-set-key (kbd "") 'noa/insert-date-time) - -;; Improve incremental search -(use-package isearch - :bind (:map isearch-mode-map - ("" . noa/isearch-done-goto-start) ; always put point at the beginning of the match - ("C-g" . isearch-cancel) ; always quit on C-g - ("C-o" . isearch-occur)) - :init (defun noa/isearch-done-goto-start (&optional nopush edit) - "End isearch at the start of the match." - (interactive) - (funcall #'isearch-done nopush edit) - (when isearch-forward (goto-char isearch-other-end))) - :custom - (isearch-lax-whitespace t) - (isearch-lazy-count t) - (isearch-allow-motion t) - (isearch-repeat-on-direction-change t) - (isearch-wrap-pause 'no)) - -(use-package avy - :bind (("M-j" . avy-goto-char-timer) - :map isearch-mode-map - ("M-j" . avy-isearch)) - :custom - (avy-keys (number-sequence ?a ?z)) - (avy-timeout-seconds 0.2)) - -;; Make window management commands easier to press -(use-package ace-window - :bind ([remap other-window] . ace-window)) - -(defun snarf-song (url) - (interactive "sYoutube url:") - (async-shell-command - (concat "yt-dlp -x --audio-format=mp3 -o " - (shell-quote-argument "~/media/music/%(title)s [%(id)s].%(ext)s") - " " - (shell-quote-argument url)))) - + (let ((fill-column (point-max))) + (fill-paragraph nil))) +(global-set-key (kbd "M-Q") #'unfill-paragraph) -;;; Email +;;; Reading mail ;; I keep coming back to rmail, despite its many, many warts. ;; Currently i fetch mail into Spool.mbox with fdm, then rmail moves it into Inbox.mbox. @@ -656,6 +402,8 @@ With prefix argument TIME, also add the current time." ;; ((rmail-show-message . visual-line-fill-column-mode)) ) +;;; Sending mail + (use-package message :defer t :init @@ -680,20 +428,6 @@ With prefix argument TIME, also add the current time." (message-interactive t) (message-auto-save-directory "~/Documents/Library/Mail/drafts")) -;; Environment variables -(setenv "PAGER" "cat") -(setenv "TERM" "dumb") -(setenv "NO_COLOR") -(setenv "GPG_AGENT_INFO" nil) - -;; Dictionary -;; Emacs has built in support for interfacing with dictd. With dictd and some dictionaries installed on debian, this works fine out of the box. -;; Unfortunately, dictionaries in this format tend to be hard wrapped and there isn't a lot of coverage outside of english -(use-package dictionary - :defer t - :custom - (dictionary-search-interface nil)) - ;;; Bibliography management ;; TODO: update this to fit with the new single org file notes system. This way should be easier than the previous method i think. (use-package ebib @@ -767,11 +501,7 @@ With prefix argument TIME, also add the current time." (biblio-bibtex-use-autokey t) (biblio-download-directory "~/Documents/Library/Papers")) - -(defun noa/yank-buffer-file-name () - (interactive) - (when (buffer-file-name) - (kill-new (file-name-nondirectory (buffer-file-name))))) +;;; Taking notes (use-package org :defer t @@ -854,16 +584,192 @@ With prefix argument TIME, also add the current time." ("C-j C-a" . ctrlj/view-agenda) ("C-j C-o" . ctrlj/jump-to-other-related-note))) -;; Experimental website generator -(use-package ox-hugo - :disabled t - :ensure t - :after ox) +;; Experimental website generator +(use-package ox-hugo + :disabled t + :ensure t + :after ox) + +(defun noa/consult-rg-notes () + (interactive) + (consult-ripgrep "~/Documents/Notes")) +(global-set-key (kbd "C-j C-s") #'noa/consult-rg-notes) + + +(defvar note/directory "~/Documents/Notes" + "The directory in which notes are stored.") +(defvar note/file-ending "md" + "The file ending for new notes.") + +(defun note/new (&optional other-window) + (interactive "P") + (let* ((uid (format-time-string "%Y-%m-%d-%H%M%S")) + (note (concat note/directory "/" uid "." note/file-ending))) + (if other-window + (progn + (insert "[[./" uid ".org]]") + (find-file-other-window note)) + (find-file note)) + )) + + +;; Markdown +(use-package markdown-mode + :mode ("\\.\\(?:md\\|markdown\\|mkd\\|mdown\\|mkdn\\|mdwn\\)\\'" . markdown-mode) + :custom + (markdown-disable-tooltip-prompt t) ; When inserting a link, only prompt for url and link text + (markdown-enable-html nil) ; I don't believe markdown should have html + (markdown-hide-urls t) ; Make inline urls look a bit neater + (markdown-url-compose-char ?~) + (markdown-max-image-size '(640 . 480)) + + ;; :hook ((markdown-mode . noa/set-buffer-name-to-markdown-title)) + ) + +;;; System administration + +(use-package proced + :defer t + :custom + (proced-auto-update-flag t) + (proced-auto-update-interval 1) + (proced-enable-color-flag nil) + (proced-show-remote-processes t)) + + +;;; Completion + +;; Some settings for nicer completion with the default emacs completion buffer. I don't use this, because i use vertico. +;; (setopt completion-auto-help 'lazy +;; completion-auto-select 'second-tab +;; completion-show-help nil +;; completions-sort nil +;; completions-header-format nil) + +;; Completion styles +;; When given a prompt to select from a list of candidates, there are quite a lot of things we can tweak to improve the experience. + +;;; File management + +(use-package consult-recoll + :bind ("" . consult-recoll) + :custom + (consult-recoll-inline-snippets nil) + (consult-recoll-group-by-mime nil)) + +(use-package dired + :defer t + :custom + (dired-recursive-deletes 'always) ;; Don't ask me things + (dired-recursive-copies 'always) ;; Don't ask me things + (dired-dwim-target t) ;; Synergy between two dired windows + ;; I have quite a bit of storage and also make bad decisions regularly + ;; People who have used computers in the last forty years or so will likely be familiar with this innovation. + (delete-by-moving-to-trash t) + + + + ;; -l is required by dired + ;; -a to also show dotfiles + ;; -v to sort numbers properly + ;; -F to visually distinguish different types of file + ;; -h for human readable file sizes + ;; I won't explain the meaning of the long flag. + (dired-listing-switches "-alvFh --group-directories-first") + +;; By default, don't show dired details + :hook ((dired-mode . dired-hide-details-mode) + (dired-mode . hl-line-mode)) + ) + +;; Show the recursive size of directories +(use-package dired-du + :disabled t + :hook (dired-mode . dired-du-mode) + :after dired + :custom + (dired-du-size-format t)) + + +(use-package recentf + :hook (after-init . recentf-mode) + :custom + (recentf-max-menu-items 50)) + +(use-package bookmark + :defer t + :custom + (bookmark-default-file "~/.config/emacs/bookmarks")) + +;; Remember my position in files +(use-package saveplace + :hook (after-init . save-place-mode)) + + +;;; Window and buffer navigation + +(use-package isearch + :bind (:map isearch-mode-map + ("" . noa/isearch-done-goto-start) ; always put point at the beginning of the match + ("C-g" . isearch-cancel) ; always quit on C-g + ("C-o" . isearch-occur)) + :init (defun noa/isearch-done-goto-start (&optional nopush edit) + "End isearch at the start of the match." + (interactive) + (funcall #'isearch-done nopush edit) + (when isearch-forward (goto-char isearch-other-end))) + :custom + (isearch-lax-whitespace t) + (isearch-lazy-count t) + (isearch-allow-motion t) + (isearch-repeat-on-direction-change t) + (isearch-wrap-pause 'no)) + +(use-package avy + :bind (("M-j" . avy-goto-char-timer) + :map isearch-mode-map + ("M-j" . avy-isearch)) + :custom + (avy-keys (number-sequence ?a ?z)) + (avy-timeout-seconds 0.2)) + +;; Make window management commands easier to press +(use-package ace-window + :bind ([remap other-window] . ace-window)) + + +;; Better buffer naming +(use-package uniquify + :custom + (uniquify-after-kill-buffer-p t) + (uniquify-buffer-name-style 'forward) + (uniquify-ignore-buffers-re "^\\*") + (uniquify-separator "/")) + +;;; Embark + +(use-package embark + :bind + (("C-." . embark-act) + ([remap describe-bindings] . embark-bindings)) + + :init + (setq prefix-help-command #'embark-prefix-help-command)) + +(use-package embark-consult + :after (embark consult) + :hook + (embark-collect-mode . consult-preview-at-point-mode)) + +;;; Reading pdfs and epub files -(defun noa/consult-rg-notes () - (interactive) - (consult-ripgrep "~/Documents/Notes")) -(global-set-key (kbd "C-j C-s") #'noa/consult-rg-notes) +(use-package pdf-tools + :when (display-graphic-p) + :magic ("%PDF" . pdf-view-mode) + :config + (pdf-tools-install :no-query)) + +;;; Music (use-package emms :disabled t @@ -885,78 +791,211 @@ With prefix argument TIME, also add the current time." (global-set-key (kbd "C-c e r") 'emms-toggle-repeat-playlist) (global-set-key (kbd "C-c e s") 'emms-toggle-random-playlist)) -;; Experiment with embark -(use-package embark - :bind - (("C-." . embark-act) - ([remap describe-bindings] . embark-bindings)) +;;; Useful functions +(defun noa/yank-buffer-file-name () + (interactive) + (when (buffer-file-name) + (kill-new (file-name-nondirectory (buffer-file-name))))) - :init - (setq prefix-help-command #'embark-prefix-help-command)) +;; Insert date and time at point +;; Sometimes it's useful to be able to add a timestamp. I use this for notes. Use the same binding as notepad.exe. +(defun noa/insert-date (&optional time) + "Insert the current date into the buffer. +With prefix argument TIME, also add the current time." + (interactive "P") + (if time + (insert (format-time-string "[%Y-%m-%d %H:%M]")) + (insert (format-time-string "[%Y-%m-%d]")))) +(defun noa/insert-datetime () + (interactive) + (noa/insert-date t)) -(use-package embark-consult - :after (embark consult) - :hook - (embark-collect-mode . consult-preview-at-point-mode)) +(global-set-key (kbd "") 'noa/insert-date-time) -(use-package pdf-tools - :when (display-graphic-p) - :magic ("%PDF" . pdf-view-mode) - :config - (pdf-tools-install :no-query)) +(defun snarf-song (url) + (interactive "sYoutube url:") + (async-shell-command + (concat "yt-dlp -x --audio-format=mp3 -o " + (shell-quote-argument "~/media/music/%(title)s [%(id)s].%(ext)s") + " " + (shell-quote-argument url)))) -;; Common lisp development +;;; Tramp +(use-package tramp + :defer t + :custom + (tramp-inline-compress-start-size 1000) + (tramp-verbose 3)) +;; (add-to-list 'tramp-remote-path 'tramp-own-remote-path) -(use-package sly - :disabled t - :if (executable-find "sbcl") - :ensure t - :commands 'sly - :custom ((inferior-lisp-program (executable-find "sbcl")) - (common-lisp-hyperspec-root "file:///usr/share/doc/hyperspec/")) - :mode ((rx (or ".lisp" ".cl") eos) . common-lisp-mode)) +;; I only use git, and this apparently speeds up tramp. +(use-package vc-hooks + :after vc + :custom + (vc-handled-backends '(Git))) -;; Write url to text file -(defvar noa/record-url-file "~/Documents/Library/urls") -(defun noa/record-url (url &rest args) - "An alternative browser function that appends the url to a file. We do not pay attention to any arguments." - (write-region (concat url "\n") nil noa/record-url-file 'append)) +;; It seems that tramp can also be made faster with these .ssh/config settings. -(defvar note/directory "~/Documents/Notes" - "The directory in which notes are stored.") -(defvar note/file-ending "md" - "The file ending for new notes.") +;; Host * +;; ControlMaster auto +;; ControlPath ~/.ssh/master-%h:%p +;; ControlPersist 10m +;; ForwardAgent yes +;; ServerAliveInterval 60 +;;; Window management +;; Don't override display actions when i manually initiate a buffer switch. +(use-package window + :custom + ;; My computer has a small screen, so i find that it's more beneficial for me to split the frame into columns, so i get more context. However, splitting in this way only gives me a (window-width) of 61, so emacs will always split into vertically stacked windows. By setting this to 80, the first split should always be vertical. + (split-width-threshold 80) + (switch-to-buffer-obey-display-actions t) + ;; C-l from top to bottom + (recenter-positions '(top middle bottom))) -(defun note/new (&optional other-window) - (interactive "P") - (let* ((uid (format-time-string "%Y-%m-%d-%H%M%S")) - (note (concat note/directory "/" uid "." note/file-ending))) - (if other-window - (progn - (insert "[[./" uid ".org]]") - (find-file-other-window note)) - (find-file note)) - )) +(use-package frame + :hook (after-init . window-divider-mode) + :custom + (window-divider-default-right-width 1) + (window-divider-default-bottom-width 1) + (window-divider-default-places t)) -(use-package ediff +;;; Unsorted + +;; Update the calendar. We want weeks to start on a monday, the first day of the week. Holidays should be highlighted, and the date format should put the year first. +(use-package calendar :defer t :custom - (ediff-window-setup-function 'ediff-setup-windows-plain) - (ediff-split-window-function 'split-window-horizontally)) + (calendar-week-start-day 1) + (calendar-date-style 'iso) -(use-package proced + :config + ;; Ensure the calendar always displays at the bottom of the screen, rather than wrapping weirdly and looking bad when it shows up in a side window. + (add-to-list 'display-buffer-alist + '("\\*Calendar\\*" + (display-buffer-in-side-window) + (side . bottom)))) + +;; Squeeze text into a more legible sliver. +(use-package visual-fill-column + :custom + (visual-fill-column-enable-sensible-window-split t) + (visual-fill-column-fringes-outside-margins nil) ; Keep fringes on the inside so relevant icons are in the right place + (visual-fill-column-center-text t) + :hook + ((text-mode . visual-fill-column-mode) + (eww-after-render . visual-line-fill-column-mode)) + ) + +;; (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust) + +;; Doesn't indent nicely with proportional fonts +;; (use-package adaptive-wrap :ensure t) +;; (add-hook 'visual-fill-column-mode-hook #'visual-wrap-prefix-mode) + +(use-package simple + :hook ((text-mode . visual-line-mode) + (after-init . auto-save-mode)) + :bind ([remap kill-buffer] . kill-current-buffer) + :custom + (save-interprogram-paste-before-kill t) + (kill-ring-max 25) + ;; Hide commands in M-x which do not work in the current mode. + (read-extended-command-predicate 'command-completion-default-include-p) + ;; My brain is not ready for advanced emacs undo + (undo-no-redo t) + :bind (("C-z" . undo) + ("C-S-z" . undo-redo))) + +(use-package help :defer t :custom - (proced-auto-update-flag t) - (proced-auto-update-interval 1) - (proced-enable-color-flag nil) - (proced-show-remote-processes t)) + ;; When opening source files from a help window, use the same window + (help-window-keep-selected t)) -;; Nicer terminal emacs -(set-display-table-slot standard-display-table 'vertical-border (make-glyph-code ?│)) -(setq mode-line-end-spaces nil) +(use-package emacs + :custom + (window-combination-resize t) + (window-resize-pixelwise t) + (frame-resize-pixelwise t) + (shell-file-name "/bin/sh") + (completion-ignore-case t) + (read-buffer-completion-ignore-case t) + ;; yes-or-no-p uses y-or-no-p, and read-answer accepts single key press answers + (use-short-answers t) + (history-length 250) + ;; Use a bar cursor and blink it and don't stop blinking it. + (cursor-type 'bar) + ;; Support opening new minibuffers from inside existing minibuffers. + (enable-recursive-minibuffers t) + ;; Whether to drop into the debugger on any error. This seems cool, but in practice is a bit annoying. + (debug-on-error nil) + (create-lockfiles nil) + (auto-save-interval 6) ;; every six keystrokes + (auto-save-timeout 5) ;; every 5 seconds + (auto-save-no-message t) + ;; Always give me a line of text when i'm near the edges of the screen + (scroll-margin 2)) -(use-package xclip) -(unless (display-graphic-p) (xclip-mode 1)) +(use-package files + :custom + (view-read-only t) + (confirm-kill-emacs 'y-or-n-p) + ;; We are on a unix system, so it makes sense to end files in the unix system way. I'm surprised this isn't the default. + (require-final-newline t) + + ;; This behaviour changes how we visit symlinks. + (find-file-visit-truename t) + + (remote-file-name-inhibit-locks t) + (remote-file-name-inhibit-auto-save t) + (remote-file-name-inhibit-auto-save-visited t) + (backup-directory-alist '(("." . "~/.config/emacs/backups/"))) + (make-backup-files nil) + (backup-by-copying t) + (version-control t) + ;; this will auto save to the current file + (auto-save-visited-mode t) + (auto-save-visited-interval 0.1) + (save-silently t) ;; don't message when saving + ) + + +;; Disable disabled commands +(setq disabled-command-function nil) + +;; Don't save changes in the customize interface +(use-package cus-edit + :custom + (custom-file (make-temp-file "custom"))) + + +;; Emacs server +;; (unless (server-running-p) (server-start))) + +;; Better support for long lines. +(use-package so-long + :hook (after-init . global-so-long-mode)) + +;; Automatically revert buffers when they change on disk. This doesn't apply to tramp. +(use-package autorevert + :hook (after-init . global-auto-revert-mode) + :custom + (global-auto-revert-non-file-buffers t)) + +(use-package vc-hooks + :custom + (vc-follow-symlinks 'ask)) + + +;; Zap up to char +(global-set-key (kbd "M-z") 'zap-up-to-char) + +(setenv "PAGER" "cat") +(setenv "TERM" "dumb") +(setenv "NO_COLOR") +(setenv "GPG_AGENT_INFO" nil) + +;;; Cleanup ;; (profiler-stop) + -- cgit 1.4.1-2-gfad0