emacs-config/init.el

2460 lines
90 KiB
EmacsLisp
Raw Permalink Normal View History

2023-09-18 13:05:09 -07:00
;;; init.el --- Configuration entry point -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:
2023-09-23 16:48:22 -07:00
;; Some other config files
2023-09-27 04:07:01 -07:00
(add-to-list 'load-path "~/.emacs.d/elisp")
2023-09-23 16:48:22 -07:00
2023-09-18 13:05:09 -07:00
;; Set package dir to follow no-littering conventions
(setq package-user-dir "~/.emacs.d/var/elpa")
;; Use melpa
(require 'package)
2023-09-20 00:50:34 -07:00
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
2023-09-18 13:05:09 -07:00
(package-initialize)
;; Ensure use-package is installed
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
;; use-package
(eval-when-compile
2024-10-16 01:52:45 -07:00
(require 'use-package)
2023-09-20 16:13:29 -07:00
(setq use-package-always-ensure t
2024-10-16 01:52:45 -07:00
package-user-dir "~/.emacs.d/var/elpa"))
2023-09-18 13:05:09 -07:00
;; no-littering
(use-package no-littering
2023-09-29 12:53:49 -07:00
:autoload (no-littering-theme-backups
no-littering-expand-etc-file-name)
:init
2023-09-18 13:05:09 -07:00
(no-littering-theme-backups)
(setq custom-file (no-littering-expand-etc-file-name "custom.el")))
;; diminish
(use-package diminish
:config
2023-09-21 03:20:43 -07:00
(diminish 'visual-line-mode)
2023-09-18 13:05:09 -07:00
(diminish 'abbrev-mode))
2024-08-07 15:40:44 -07:00
;; Private config loading
(require 'private nil t)
(defun my/get-private (key)
"Get the private config variable KEY from the private configuration file."
(alist-get key my/private-config))
2023-09-18 13:05:09 -07:00
;; basic stuff
(use-package emacs
2024-09-13 01:20:27 -07:00
:hook (;;(emacs-lisp-mode . my/-emacs-lisp-mode-setup-evil-lookup)
;;(prog-mode . electric-pair-local-mode)
2024-10-16 01:52:45 -07:00
((text-mode tex-mode prog-mode) . auto-fill-mode)
((text-mode tex-mode prog-mode) . my/-enable-show-trailing-whitespace))
2023-09-18 13:05:09 -07:00
:init
(defun my/-enable-show-trailing-whitespace ()
(setq-local show-trailing-whitespace t))
;; (defun my/-emacs-lisp-mode-setup-evil-lookup ()
;; (setq-local evil-lookup-func
;; #'my/describe-symbol-at-point))
2023-09-18 13:05:09 -07:00
(defun my/describe-symbol-at-point ()
2024-09-13 01:36:02 -07:00
"Calls `describe-symbol' on the return value of `symbol-at-point'."
2023-09-18 13:05:09 -07:00
(interactive)
2024-09-13 01:36:02 -07:00
(let ((form (symbol-at-point)))
2023-09-20 00:50:34 -07:00
(if (consp form)
(describe-symbol (cadr form))
(describe-symbol form))))
2023-09-18 13:05:09 -07:00
2024-07-16 03:23:03 -07:00
;; Increase responsiveness
(setq gc-cons-threshold 80000000
read-process-output-max (* 1024 1024)) ;; 1mb
2024-10-08 16:35:45 -07:00
(global-so-long-mode 1)
2024-07-16 03:23:03 -07:00
2023-09-20 03:57:16 -07:00
;; Terminal mouse support
(xterm-mouse-mode 1)
2023-12-27 12:19:44 -08:00
;; Make cursor more visible
(global-hl-line-mode 1)
(blink-cursor-mode -1)
2023-12-27 12:19:44 -08:00
2023-10-16 05:02:57 -07:00
;; Enable all disabled stuff
(setq disabled-command-function nil)
2023-10-10 02:50:48 -07:00
2024-01-10 03:58:02 -08:00
;; Stop some annoying stuff
(setq extended-command-suggest-shorter nil
suggest-key-bindings nil)
2023-09-27 04:07:01 -07:00
;; Better scrolling
(setq mouse-scroll-delay 0
scroll-conservatively 10
scroll-margin 2
scroll-preserve-screen-position t)
2023-09-22 02:50:19 -07:00
2023-09-18 13:05:09 -07:00
;; Make show paren instant
(setq show-paren-delay 0)
(show-paren-mode 1)
;; Display line numbers
(global-display-line-numbers-mode 1)
;; Allow the frame to be any size
(setq frame-resize-pixelwise t)
2023-10-23 15:49:47 -07:00
;; Don't use a gtk file picker
(setq use-file-dialog nil)
2024-04-30 02:38:47 -07:00
;; Make yes-or-no-p less verbose (and not use windows)
(setq use-dialog-box nil
use-short-answers t)
2023-09-18 13:05:09 -07:00
;; Disable startup screen
2023-12-26 04:48:49 -08:00
(setq inhibit-startup-screen t
server-client-instructions nil)
2023-09-18 13:05:09 -07:00
2023-09-20 00:50:34 -07:00
;; show column numbers
(column-number-mode 1)
2023-09-18 13:05:09 -07:00
;; Disable the menu and tool bars
(menu-bar-mode -1)
(tool-bar-mode -1)
;; No scroll bars
(scroll-bar-mode -1)
2023-09-20 14:55:12 -07:00
;; Visual line mode
(global-visual-line-mode 1)
2024-07-16 03:23:03 -07:00
;; Make some commands easier to enter multiple times
(repeat-mode 1)
2024-10-20 00:44:30 -07:00
;; Easier buffer navigation
(keymap-global-set "C-c <" #'previous-buffer)
(keymap-global-set "C-c >" #'next-buffer)
(keymap-global-set "C-c k" #'previous-buffer)
(keymap-global-set "C-c j" #'next-buffer)
2023-09-18 13:05:09 -07:00
;; Set fonts
(add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono-12"))
2024-05-24 21:37:23 -07:00
(add-hook 'server-after-make-frame-hook
(lambda ()
(set-fontset-font t 'japanese-jisx0208 "IPAGothic")))
2023-09-18 13:05:09 -07:00
2024-05-02 17:06:27 -07:00
;; Enable color in compilation buffers
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
2023-09-20 00:50:34 -07:00
;; Some settings for programming
(setq-default indent-tabs-mode nil
2024-09-12 18:01:06 -07:00
tab-width 4
2024-03-04 21:16:21 -08:00
fill-column 80
2024-09-13 01:20:27 -07:00
comment-multi-line t
comment-empty-lines 'eol)
2024-10-12 04:38:43 -07:00
(add-to-list 'auto-mode-alist '("\\.[cC][nN][fF]\\'" . conf-mode))
2024-10-20 00:44:30 -07:00
(keymap-set emacs-lisp-mode-map "C-c C-r" #'eval-region)
(defun my/-fix-emacs-lisp-mode-system-files ()
(when (string-prefix-p lisp-directory buffer-file-name)
;; system Emacs files use tab characters and look weird without this.
(setq-local tab-width 8)))
(add-hook 'emacs-lisp-mode-hook #'my/-fix-emacs-lisp-mode-system-files)
2023-09-20 00:50:34 -07:00
2023-09-18 13:05:09 -07:00
;; Tree sitter download locations
(setq treesit-language-source-alist
2023-09-20 00:50:34 -07:00
'((c "https://github.com/tree-sitter/tree-sitter-c")
(cpp "https://github.com/tree-sitter/tree-sitter-cpp")
(java "https://github.com/tree-sitter/tree-sitter-java")
(python "https://github.com/tree-sitter/tree-sitter-python")
2023-09-21 16:02:36 -07:00
(rust "https://github.com/tree-sitter/tree-sitter-rust")
(json "https://github.com/tree-sitter/tree-sitter-json")
2024-01-09 04:50:59 -08:00
(yaml "https://github.com/ikatyang/tree-sitter-yaml")
(css "https://github.com/tree-sitter/tree-sitter-css")
(go "https://github.com/tree-sitter/tree-sitter-go")
2024-03-08 19:54:16 -08:00
(gomod "https://github.com/camdencheek/tree-sitter-go-mod")
2024-04-20 13:48:30 -07:00
(javascript "https://github.com/tree-sitter/tree-sitter-javascript")
(bash "https://github.com/tree-sitter/tree-sitter-bash")
2023-10-20 02:23:52 -07:00
(cmake "https://github.com/uyha/tree-sitter-cmake")
2024-04-24 21:01:50 -07:00
(blueprint "https://github.com/huanie/tree-sitter-blueprint")
(kdl "https://github.com/tree-sitter-grammars/tree-sitter-kdl")))
2023-09-20 00:50:34 -07:00
;; Tree sitter major mode conversions
(setq major-mode-remap-alist
'((c-mode . c-ts-mode)
2023-09-21 03:20:43 -07:00
(c++-mode . c++-ts-mode)
(c-or-c++-mode . c-or-c++-ts-mode)
2023-10-15 18:44:41 -07:00
(python-mode . python-ts-mode)
2023-09-20 00:50:34 -07:00
(java-mode . java-ts-mode)
2023-09-21 16:02:36 -07:00
(rust-mode . rust-ts-mode)
(json-mode . json-ts-mode)
2024-01-09 04:50:59 -08:00
(yaml-mode . yaml-ts-mode)
(css-mode . css-ts-mode)
(js-mode . js-ts-mode)
2024-04-20 13:48:30 -07:00
(cmake-mode . cmake-ts-mode)))
(defun my/treesit-compile-all (force)
"Compile all the modules defined in `treesit-language-source-alist'.
If FORCE, recompile all modules, even ones that are already compiled.
Interactively, force the recompile if called with a prefix."
(interactive "P")
(let ((did-build nil))
(dolist (lang treesit-language-source-alist)
(when (or force (not (treesit-language-available-p (car lang))))
(treesit-install-language-grammar (car lang))
(setq did-build t)))
(unless did-build
(message "All defined parsers installed!")))))
2023-09-18 13:05:09 -07:00
2024-08-03 03:29:09 -07:00
(use-package midnight
:ensure nil
:config
(add-to-list 'clean-buffer-list-kill-never-buffer-names
"*mu4e-main*")
(add-to-list 'clean-buffer-list-kill-never-buffer-names
"*Async-native-compile-log*")
(add-to-list 'clean-buffer-list-kill-never-buffer-names
"*dashboard*")
(add-to-list 'clean-buffer-list-kill-never-buffer-names
"*elfeed-search*")
(midnight-mode 1))
2024-10-08 21:45:10 -07:00
(defvar my/kill-some-buffers-exclude-names
'("*mu4e-main*" "*Async-native-compile-log*" "*dashboard*" "*elfeed-search*"
"*Messages*" "*scratch*")
"List of literal buffer names that `my/kill-some-buffers' should not kill.")
(defun my/kill-some-buffers-excluded-buffer-p (buffer)
"Return non-nil if BUFFER should be excluded from `my/kill-some-buffers'."
(cl-find (buffer-name buffer) my/kill-some-buffers-exclude-names
:test 'equal))
(defun my/buffer-visible-p (buffer)
"Return non-nil if BUFFER is visible.
BUFFER can be a string or a buffer."
(cond
((stringp buffer)
(not (string-prefix-p " " buffer)))
((bufferp buffer)
2024-10-09 07:32:06 -07:00
(and (stringp (buffer-name buffer))
(my/buffer-visible-p (buffer-name buffer))))
2024-10-08 21:45:10 -07:00
(t
(signal 'wrong-type-argument `((or bufferp stringp) ,buffer)))))
(defvar my/kill-some-buffers-default-pred 'my/buffer-visible-p
"Default predicate for `my/kill-some-buffers'.")
(defun my/kill-some-buffers-prompt-for (buffer)
"Generate a prompt for BUFFER."
(let* ((process (get-buffer-process buffer))
(process-p (and (process-live-p process)
(not (process-query-on-exit-flag process))))
(modified-p (and (buffer-file-name buffer)
(buffer-modified-p buffer))))
(format "Buffer \"%s\" %s. Kill? "
(buffer-name buffer)
(cond
((and process-p modified-p)
"HAS BEEN EDITED AND HAS A LIVE PROCESS")
(modified-p
"HAS BEEN EDITED")
(process-p
"HAS A LIVE PROCESS")
(t "is unmodified")))))
(cl-defun my/kill-some-buffers (&optional auto-unmod pred)
"Improved version of `kill-some-buffers'.
Ask the user weather to kill each visible buffer whose name is not in
`my/kill-some-buffers-exclude-names'.
When AUTO-UNMOD is non-nil, as it is with a prefix argument, automatically kill
unmodified buffers, and then ask about the rest.
When PRED is non-nil, it is a function that will be run in each buffer (not just
visible ones). If it returns t, that buffer will be considered for killing. If
PRED is nil, the value of `my/kill-some-buffers-default-pred' is used."
(interactive "P")
;; we already ask, no need to do it again
(let ((kill-buffer-query-functions nil)
(all-action (when auto-unmod 'unmod))
2024-11-07 22:06:44 -08:00
(had-valid-buffer)
(ask-again-buffers)
(to-kill))
2024-10-08 21:45:10 -07:00
(cl-flet ((ask-about (buffer allow-unmod)
(unless all-action
(read-answer
(my/kill-some-buffers-prompt-for buffer)
`(("yes" ?y "save and kill this buffer")
("no" ?n "skip this buffer")
("all" ?! "save and kill all remaining buffers")
("nosave" ?l "kill this buffer without saving")
,@(when allow-unmod
'(("unmod" ?a
"kill unmodified buffers, ask about the rest")))
("quit" ?q "exit")))))
(act-on (ans buffer allow-unmod)
(when (equal ans "all")
(setq all-action 'all))
(when (and allow-unmod
(equal ans "unmod"))
(setq all-action 'unmod))
(cond
((and (eq all-action 'unmod)
(buffer-file-name buffer)
(buffer-modified-p buffer))
(push buffer ask-again-buffers))
((or (eq all-action 'all)
(eq all-action 'unmod)
(equal ans "yes"))
(when (buffer-file-name buffer)
(with-current-buffer buffer
(save-buffer)))
(push buffer to-kill))
2024-10-08 21:45:10 -07:00
((equal ans "nosave")
(with-current-buffer buffer
(set-buffer-modified-p nil))
(push buffer to-kill))
2024-10-08 21:45:10 -07:00
;; Skip buffer
;; ((equal ans "no"))
((equal ans "quit")
(cl-return-from my/kill-some-buffers)))))
(dolist (buffer (buffer-list))
(when (and (not (my/kill-some-buffers-excluded-buffer-p buffer))
(funcall (or pred my/kill-some-buffers-default-pred) buffer))
2024-11-07 22:06:44 -08:00
(setq had-valid-buffer t)
2024-10-08 21:45:10 -07:00
(act-on (ask-about buffer t) buffer t)))
2024-11-07 22:06:44 -08:00
(unless had-valid-buffer
(message "Nothing to do..."))
2024-10-08 21:45:10 -07:00
(setq all-action nil)
(dolist (buffer ask-again-buffers)
(act-on (ask-about buffer nil) buffer nil))
;; Do this last so that tty frames don't auto-close half way through
(dolist (buffer to-kill)
(kill-buffer buffer)))))
2024-10-31 18:19:54 -07:00
(keymap-global-set "C-x K" 'my/kill-some-buffers)
2024-10-08 21:45:10 -07:00
2023-11-23 15:55:25 -08:00
(use-package tab-bar
:ensure nil
:init
(setq tab-bar-show 1
tab-bar-tab-hints t
icon-preference '(symbol text image emoji))
(tab-bar-mode 1))
2024-10-02 16:45:46 -07:00
;; jinx (better flyspell)
(use-package jinx
:hook (emacs-startup . global-jinx-mode)
2024-01-07 21:46:38 -08:00
:config
2024-10-02 16:45:46 -07:00
(evil-define-key 'normal 'global
"z=" #'jinx-correct))
2024-01-07 21:46:38 -08:00
2023-09-21 03:20:43 -07:00
;; recentf
2023-09-18 13:05:09 -07:00
(use-package recentf
2023-09-27 04:07:01 -07:00
:init
2023-12-27 22:43:15 -08:00
(setq recentf-exclude `("^/tmp/.*"
2023-10-30 01:34:55 -07:00
"^~/.mail/[^/]/Drafts/.*"
2023-12-27 22:43:15 -08:00
,(format "^%svar/elpa/.*" user-emacs-directory)
2024-04-17 02:59:08 -07:00
,(format "^%svar/elfeed/.*" user-emacs-directory)
2023-12-27 22:43:15 -08:00
,(format "^%svar/gnus/.*" user-emacs-directory)
2024-03-05 11:21:06 -08:00
,(format "^%svar/ellama-sessions/.*" user-emacs-directory)
,(format "^%setc/gnus/.*" user-emacs-directory)
,(format "^%svar/bookmark-default.el" user-emacs-directory)))
2023-10-24 01:08:15 -07:00
:bind ("C-c r" . recentf)
2023-09-18 13:05:09 -07:00
:config
(recentf-mode 1))
2024-09-13 05:17:00 -07:00
;; bookmarks
(use-package bookmark
:ensure nil
:bind ("C-c b" . my/bookmark-find-file)
:config
(defun my/bookmark-find-file (&optional name)
"Run `find-file' in or on bookmark NAME.
If NAME points to a directory, run `find-file' with `default-directory' in that
directory. Otherwise, run `find-file' on that file."
(interactive (list (bookmark-completing-read
"Find file in" bookmark-current-bookmark)))
(unless name
(error "No bookmark specified"))
(bookmark-maybe-historicize-string name)
(when-let ((file (bookmark-get-filename name)))
(if (file-directory-p file)
(let ((default-directory (file-name-as-directory file)))
(call-interactively 'find-file))
(find-file file)))))
2023-10-05 00:44:19 -07:00
;; kitty keyboard protocol
(use-package kkp
2024-11-19 18:13:37 -08:00
:defer nil
2023-10-05 00:44:19 -07:00
:config
2024-05-04 03:08:25 -07:00
(global-kkp-mode 1)
2024-11-19 18:13:37 -08:00
(defun my/-kkp-after-terminal-setup ()
;; Make tab and backtab work properly
(define-key input-decode-map [(control ?i)] [tab])
2024-11-19 18:13:37 -08:00
(define-key input-decode-map [(control ?I)] [backtab])
(define-key input-decode-map [(control ?m)] [return]))
(defun my/-kkp-after-terminal-teardown (term)
(with-selected-frame (car (frames-on-display-list term))
(define-key input-decode-map [(control ?i)] nil t)
(define-key input-decode-map [(control ?I)] nil t)
(define-key input-decode-map [(control ?m)] nil t)))
(advice-add 'kkp--terminal-setup :after 'my/-kkp-after-terminal-setup)
(advice-add 'kkp--terminal-teardown :after 'my/-kkp-after-terminal-teardown)
2024-10-20 00:44:30 -07:00
(defun my/quoted-insert (arg)
"Insert the next character using read-key, not read-char."
(interactive "*p")
;; Source: https://github.com/benjaminor/kkp/issues/11
(let ((char (read-key)))
;; Ensure char is treated as a character code for insertion
(unless (characterp char)
(user-error "%s is not a valid character"
(key-description (vector char))))
(when (numberp char)
(while (> arg 0)
(insert-and-inherit char)
(setq arg (1- arg))))))
(keymap-global-set "C-q" #'my/quoted-insert)
2024-11-05 10:06:00 -08:00
(defun my/-kkp-fix-map-y-or-n-p (oldfun &rest args)
"Fix `map-y-or-n-p' when used in a terminal with kkp enabled."
2024-05-04 03:08:25 -07:00
(let ((status (kkp--terminal-has-active-kkp-p)))
2024-11-19 19:25:21 -08:00
(condition-case err
2024-05-04 03:08:25 -07:00
(progn
2024-11-19 18:13:37 -08:00
(when status (kkp-disable-in-terminal))
2024-11-05 10:06:00 -08:00
(apply oldfun args))
2024-11-19 19:25:21 -08:00
(quit
;; We won't die in this case, so just re-enable kkp
(when (and status (not (kkp--terminal-has-active-kkp-p)))
(kkp-enable-in-terminal))
(signal 'quit nil))
(t
(when (and status (not (kkp--terminal-has-active-kkp-p)))
;; this does async stuff that will make kitty send characters after
;; Emacs exits. We prevent that by not re-enabling if this frame (or
;; Emacs) is about to die
(let ((will-die))
(mapbacktrace
(lambda (_evald func _args _flags)
(when (or (eq func 'save-buffers-kill-emacs)
(eq func 'server-save-buffers-kill-terminal))
(setq will-die t))))
(unless will-die
(kkp-enable-in-terminal))))
(when err
(signal (car err) (cdr err)))))))
2024-11-05 10:06:00 -08:00
(advice-add #'map-y-or-n-p :around
#'my/-kkp-fix-map-y-or-n-p))
2023-10-05 00:44:19 -07:00
2024-01-09 23:00:07 -08:00
;; mozc
(require 'mozc nil t)
(setq default-input-method "japanese-mozc")
2024-03-20 02:44:57 -07:00
;; undo-tree
(use-package undo-tree
:defer nil
2024-03-23 04:56:00 -07:00
:hook (undo-tree-visualizer-mode . my/-undo-tree-visualizer-mode-setup)
2024-03-20 02:44:57 -07:00
:config
2024-03-23 04:56:00 -07:00
(defun my/-undo-tree-visualizer-mode-setup ()
2024-10-09 07:32:06 -07:00
(visual-line-mode -1)
(setq truncate-lines t))
2024-03-20 02:44:57 -07:00
(global-undo-tree-mode))
2023-09-18 13:05:09 -07:00
;; evil
(use-package evil
:init
(setq evil-want-integration t
2024-01-08 16:26:25 -08:00
evil-want-C-d-scroll nil
2023-09-18 13:05:09 -07:00
evil-want-keybinding nil
2024-03-20 02:44:57 -07:00
evil-undo-system 'undo-tree
2023-10-31 00:39:11 -07:00
evil-search-module 'isearch
evil-respect-visual-line-mode t)
2023-09-18 13:05:09 -07:00
:config
(evil-mode 1)
(evil-define-key '(normal visual motion) proced-mode-map
2023-09-21 03:20:43 -07:00
"u" #'proced-unmark)
2023-09-18 13:05:09 -07:00
(evil-define-key '(normal visual motion) dired-mode-map
2024-10-17 21:13:42 -07:00
"u" #'dired-unmark)
(evil-define-key '(normal visual motion) profiler-report-mode-map
2024-10-20 00:44:30 -07:00
(kbd "TAB") #'profiler-report-toggle-entry)
(eldoc-add-command 'evil-insert
'evil-append
'evil-insert-line
'evil-append-line))
2023-09-18 13:05:09 -07:00
(use-package evil-collection
2023-09-22 02:50:19 -07:00
:after evil
2023-09-18 13:05:09 -07:00
:diminish evil-collection-unimpaired-mode
:config
(evil-collection-init))
(use-package evil-surround
2023-09-22 02:50:19 -07:00
:after evil
2023-09-18 13:05:09 -07:00
:config
2023-09-21 03:20:43 -07:00
(evil-define-key 'operator evil-surround-mode-map
2024-09-12 20:32:05 -07:00
"z" #'evil-surround-edit
"Z" #'evil-Surround-edit)
2023-09-21 03:20:43 -07:00
(evil-define-key 'visual evil-surround-mode-map
2024-09-12 20:32:05 -07:00
"gz" #'evil-surround-region
"gZ" #'evil-Surround-region)
2023-09-18 13:05:09 -07:00
(global-evil-surround-mode 1))
2023-09-21 03:20:43 -07:00
(use-package evil-terminal-cursor-changer
2023-09-22 02:50:19 -07:00
:after evil
2023-09-20 03:57:16 -07:00
:config
(evil-terminal-cursor-changer-activate))
2024-03-12 04:25:24 -07:00
(use-package evil-numbers
:after evil
:bind (("C-c =" . evil-numbers/inc-at-pt)
("C-c +" . evil-numbers/inc-at-pt)
("C-c -" . evil-numbers/dec-at-pt)
("C-c C-=" . evil-numbers/inc-at-pt-incremental)
("C-c C-+" . evil-numbers/inc-at-pt-incremental)
("C-c C--" . evil-numbers/dec-at-pt-incremental)))
2024-09-12 20:32:05 -07:00
(use-package evil-cleverparens
:hook ((prog-mode . my/-enable-evil-cleverparens)
2024-09-13 01:20:27 -07:00
(evil-cleverparens-mode . paredit-mode))
:bind (:map paredit-mode-map
("C-<return>" . paredit-RET)
2024-09-16 00:44:50 -07:00
("C-RET" . paredit-RET)
:map evil-cleverparens-mode-map
("C-c o" . evil-cp-open-below-form))
2024-09-12 20:32:05 -07:00
:custom
2024-10-16 01:52:45 -07:00
(evil-cleverparens-use-s-and-S nil)
:config
2024-09-16 00:44:50 -07:00
(eldoc-add-command 'paredit-RET
'paredit-open-round
'paredit-open-angled
'paredit-open-bracket
'paredit-open-angled
2024-10-20 00:44:30 -07:00
'paredit-open-parenthesis
'delete-indentation
'evil-cp-insert
'evil-cp-append
'evil-cp-insert-at-beginning-of-form
'evil-cp-insert-at-end-of-form)
2024-10-31 18:19:54 -07:00
(keymap-unset evil-cleverparens-mode-map "<normal-state> M-o" t)
(defun my/-enable-evil-cleverparens ()
2024-10-12 04:38:43 -07:00
(if (member major-mode '(lisp-mode emacs-lisp-mode
lisp-interaction-mode))
(evil-cleverparens-mode 1)
2024-10-16 16:56:08 -07:00
(electric-pair-local-mode 1)))
(cl-defun my/range-inside-thing-p (thing beg end &optional no-edge)
"Return non-nil if BEG and END fall inside the bounds of THING.
With NO-EDGE, return nil if beg or end fall on the edge of the range."
(save-excursion
;; this fixes that fact that `thing-at-point-bounds-of-string-at-point'
;; errors if called at the end of the buffer
2024-11-19 19:25:21 -08:00
(condition-case nil
(let ((sb (progn (goto-char beg) (bounds-of-thing-at-point thing)))
(eb (progn (goto-char end) (bounds-of-thing-at-point thing))))
(and sb eb (equal sb eb)
(or (not no-edge)
(and (/= beg (car sb))
(< beg (cdr sb))
(/= end (car sb))
(< end (cdr sb))))))
2024-10-17 20:28:16 -07:00
;; if the error happens, we aren't in a string
(wrong-type-argument nil))))
(defun my/-evil-cp-region-ok-p-no-string (oldfun beg end)
2024-10-17 20:28:16 -07:00
(or
2024-10-17 21:13:42 -07:00
(and (sp-point-in-comment beg)
(sp-point-in-comment end))
(and (sp-point-in-string beg)
(sp-point-in-string end)
(my/range-inside-thing-p 'string beg end t))
2024-10-17 20:28:16 -07:00
(funcall oldfun beg end)))
(defun my/column-num-at-pos (pos)
"Return the column number at POS."
(save-excursion
(goto-char pos)
(current-column)))
(defun my/-evil-cp-block-ok-p-no-string (oldfun beg end)
(when (> beg end) (cl-rotatef beg end))
(or
(save-excursion
(goto-char beg)
(let ((start-off (current-column))
(end-off (my/column-num-at-pos end)))
(cl-block nil
(dotimes (_ (count-lines beg end) t)
(let ((bol (pos-bol)))
(unless (sp-region-ok-p (+ bol start-off)
(+ bol end-off))
(cl-return))
2024-10-17 21:13:42 -07:00
(forward-line))))))
(funcall oldfun beg end)))
(advice-add 'sp-region-ok-p :around 'my/-evil-cp-region-ok-p-no-string)
2024-10-17 20:28:16 -07:00
(advice-add 'evil-cp--balanced-block-p :around 'my/-evil-cp-block-ok-p-no-string))
2023-10-24 01:08:15 -07:00
2024-11-07 10:18:48 -08:00
;; better lisp editing
2024-09-12 18:01:06 -07:00
(use-package adjust-parens
:hook (prog-mode . adjust-parens-mode)
:config
2024-10-16 23:10:20 -07:00
(defun my/lisp-indent-adjust-parens ()
"Like `lisp-indent-adjust-parens', but got to first char on line first.
Also, this works even if the region is active (it indents every line in the
region)."
(interactive)
2024-10-16 23:10:20 -07:00
(save-mark-and-excursion
(let ((end (mark t))
(line-count 1)
(indent-cols))
(when (and (region-active-p) end)
(setq mark-active nil
line-count (count-lines (point) end))
(when (> (point) end)
(let ((start (point)))
(goto-char end)
(setq end start))))
;; find the indentation column of each line
(save-excursion
(dotimes (_ line-count)
(back-to-indentation)
(push (- (point) (pos-bol)) indent-cols)
(forward-line))
(cl-callf nreverse indent-cols))
(cl-loop repeat line-count
for indent-col in indent-cols
for bol = (pos-bol)
do (back-to-indentation)
;; skip this line if the indentation has changed
when (= (- (point) bol) indent-col) do
(lisp-indent-adjust-parens)
;; if the indent failed, stop
(when (= (- (point) bol) indent-col)
(cl-return))
do (forward-line)))))
(defun my/lisp-dedent-adjust-parens ()
"Like `lisp-dedent-adjust-parens', but got to first char on line first.
Also, this works even if the region is active (it just jumps to the first line
in the region and indents once)."
(interactive)
2024-10-16 23:10:20 -07:00
(save-mark-and-excursion
(let ((end (mark t)))
(when (and (region-active-p) end)
(setq mark-active nil)
(when (> (point) end)
(goto-char end))))
(back-to-indentation)
(lisp-dedent-adjust-parens)))
2024-10-20 00:44:30 -07:00
(eldoc-add-command 'my/lisp-indent-adjust-parens
'my/lisp-dedent-adjust-parens
'lisp-indent-adjust-parens
'lisp-dedent-adjust-parens)
2024-10-16 23:10:20 -07:00
(evil-define-key '(normal visual) adjust-parens-mode-map
(kbd "<tab>") #'my/lisp-indent-adjust-parens
(kbd "<backtab>") #'my/lisp-dedent-adjust-parens))
2024-09-12 18:01:06 -07:00
2024-03-10 05:51:50 -07:00
;; for when the files are just too large
(use-package vlf
:demand t
:config
(require 'vlf-setup))
2024-10-20 00:44:30 -07:00
;; allow copy from terminal
2023-10-24 01:08:15 -07:00
(use-package xclip
:config
2024-11-06 18:04:13 -08:00
(setq xclip-method 'wl-copy
xclip-program (symbol-name xclip-method))
(xclip-mode 1)
(defun my/-xclip-detect-wl-paste-error (oldfun type)
(if (eq xclip-method 'wl-copy)
;; Direct from `xclip-get-selection'
(when (and (getenv "WAYLAND_DISPLAY")
(memq type '(clipboard CLIPBOARD primary PRIMARY)))
(let* ((exit-code 0)
(output
(with-output-to-string
(setq exit-code
(apply #'call-process (replace-regexp-in-string
"\\(.*\\)copy" "\\1paste"
xclip-program 'fixedcase)
nil standard-output nil
"-n" (if (memq type '(primary PRIMARY))
'("-p")))))))
(if (zerop exit-code)
output
"")))
(funcall oldfun type)))
(advice-add 'xclip-get-selection :around 'my/-xclip-detect-wl-paste-error))
2023-09-18 13:05:09 -07:00
;; which-key
(use-package which-key
:diminish which-key-mode
:config
(which-key-mode 1))
;; avy
(use-package avy
2023-09-20 00:50:34 -07:00
:bind (("C-c C-j" . avy-resume)
("M-s s" . evil-avy-goto-char-2)
("M-s S" . evil-avy-goto-line))
2023-09-18 13:05:09 -07:00
:init
(define-minor-mode my/evil-avy-mode
2023-09-20 00:50:34 -07:00
"A minor mode for binding avy commands to s and S in evil's normal and
visual states."
2023-09-18 13:05:09 -07:00
:keymap (make-sparse-keymap))
(evil-define-key '(normal visual operator motion) my/evil-avy-mode-map
2023-09-21 03:20:43 -07:00
"s" #'evil-avy-goto-char-2
"S" #'evil-avy-goto-line)
2023-09-20 00:50:34 -07:00
(define-globalized-minor-mode my/evil-avy-global-mode my/evil-avy-mode
(lambda () (my/evil-avy-mode 1))
2023-10-03 13:04:37 -07:00
:predicate '((not magit-mode dired-mode
proced-mode mu4e-main-mode
2023-10-20 02:50:07 -07:00
mu4e-view-mode mu4e-headers-mode
2023-12-27 22:43:15 -08:00
ibuffer-mode calc-mode calc-trail-mode
gnus-group-mode) t))
2023-09-20 00:50:34 -07:00
(my/evil-avy-global-mode 1)
2023-09-18 13:05:09 -07:00
:config
(avy-setup-default))
;; ace-window
(use-package ace-window
:diminish ace-window-mode
:bind ("M-o" . ace-window)
:init
(setq aw-scope 'frame
aw-minibuffer-flag t))
;; savehist
(use-package savehist
:config
(savehist-mode 1))
;; vertico
2024-01-07 21:46:38 -08:00
(use-package vertico
:bind (:map vertico-map
2024-10-20 00:44:30 -07:00
("C-RET" . vertico-exit-input)
("C-<return>" . vertico-exit-input)
2024-09-13 01:20:27 -07:00
("C-S-k" . kill-line)
("C-k" . vertico-previous)
("C-j" . vertico-next)
("RET" . vertico-directory-enter)
("DEL" . vertico-directory-delete-char)
("M-DEL" . vertico-directory-delete-word))
2024-01-07 21:46:38 -08:00
:hook (minibuffer-setup . cursor-intangible-mode)
2023-09-18 13:05:09 -07:00
:init
2023-12-27 22:43:15 -08:00
(defun my/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 #'my/crm-indicator)
2024-01-07 21:46:38 -08:00
(setq vertico-cycle t
enable-recursive-minibuffers t
2024-10-20 02:03:00 -07:00
;; read-extended-command-predicate #'command-completion-default-include-p
read-extended-command-predicate nil
2024-10-20 00:44:30 -07:00
minibuffer-prompt-properties '(read-only t ;; noindent 3
cursor-intangible t
face minibuffer-prompt))
2024-10-02 16:45:46 -07:00
(vertico-mode 1)
;; for jinx
(require 'vertico-multiform)
(add-to-list 'vertico-multiform-categories
'(jinx grid (vertico-grid-annotate . 20)))
(vertico-multiform-mode 1))
2023-09-18 13:05:09 -07:00
;; orderless
(use-package orderless
:autoload orderless-define-completion-style
2023-09-20 00:50:34 -07:00
:hook (text-mode . my/-setup-text-mode-completion-styles)
2023-09-18 13:05:09 -07:00
:init
2023-09-20 00:50:34 -07:00
(defun my/-setup-text-mode-completion-styles ()
(setq-local completion-styles '(basic)))
2023-09-18 13:05:09 -07:00
(orderless-define-completion-style my/orderless-with-initialism
(orderless-matching-styles '(orderless-initialism
orderless-regexp)))
2024-01-07 21:46:38 -08:00
(setq orderless-matching-styles '(orderless-regexp)
completion-styles '(orderless basic)
2023-09-18 13:05:09 -07:00
completion-category-defaults nil
completion-category-overrides '((file
2023-09-20 00:50:34 -07:00
(styles basic partial-completion))
2023-09-18 13:05:09 -07:00
(command
2024-01-07 21:46:38 -08:00
(styles my/orderless-with-initialism basic)))))
2023-09-18 13:05:09 -07:00
2024-09-13 01:20:27 -07:00
;; marginalia
2023-09-18 13:05:09 -07:00
(use-package marginalia
:bind (:map minibuffer-local-map
2024-09-13 01:20:27 -07:00
("M-a" . marginalia-cycle))
2023-09-18 13:05:09 -07:00
:init
(marginalia-mode 1))
;; embark
(use-package embark
2024-01-07 21:46:38 -08:00
:bind (("C-," . embark-act)
("C-;" . embark-dwim)
:map help-map
("B" . embark-bindings)
:map embark-symbol-map
2024-10-31 16:53:02 -07:00
("h" . helpful-symbol)
:map embark-become-file+buffer-map
("b" . consult-buffer)
("B" . switch-to-buffer))
2023-09-20 00:50:34 -07:00
:init
2024-11-01 09:40:43 -07:00
(setq embark-quit-after-action nil
embark-indicators '(embark-minimal-indicator
embark-isearch-highlight-indicator
embark-highlight-indicator))
2024-11-01 09:48:16 -07:00
:config
2024-11-01 09:40:43 -07:00
(defvar-keymap my/embark-string-map
:doc "Keymap for Embark string actions."
:parent embark-expression-map
"R" 'repunctuate-sentences)
(defun my/embark-target-string ()
"Target the string at point."
(if-let (((not (eobp))) ; prevent next line from causing errors
(bounds (bounds-of-thing-at-point 'string)))
(append (list 'string (buffer-substring-no-properties (car bounds)
(cdr bounds)))
bounds)))
(add-to-list 'embark-around-action-hooks
'(repunctuate-sentences embark--mark-target))
(add-to-list 'embark-keymap-alist
'(string my/embark-string-map))
(add-to-list 'embark-target-finders 'my/embark-target-string)
2023-09-20 00:50:34 -07:00
(add-to-list 'display-buffer-alist
2023-09-21 03:20:43 -07:00
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
2024-04-30 01:49:25 -07:00
(window-parameters (mode-line-format . none))))
(evil-define-key '(normal motion) org-mode-map
(kbd "C-,") #'embark-act))
2023-09-18 13:05:09 -07:00
;; consult
(use-package consult
:bind (("C-s" . consult-line)
("C-x b" . consult-buffer)
("C-S-s" . consult-ripgrep)
("C-x C-S-f" . consult-fd)
("C-x c k" . consult-keep-lines)
("C-x c f" . consult-focus-lines)
("C-x c r" . consult-recent-file)
("C-x c b" . consult-bookmark)
2023-09-22 02:50:19 -07:00
("C-x c d" . consult-fd)
("C-x c g" . consult-ripgrep)
2024-01-30 16:17:23 -08:00
("C-x c y" . consult-yank-from-kill-ring)
2023-09-20 00:50:34 -07:00
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
2023-10-12 20:24:53 -07:00
("M-g r" . consult-imenu-multi)
:map help-map
("TAB". consult-info)
("C-m" . consult-man))
2023-09-21 03:20:43 -07:00
:hook (minibuffer-setup . my/consult-setup-minibuffer-completion)
2023-09-18 13:05:09 -07:00
:init
2023-09-21 03:20:43 -07:00
(defun my/consult-setup-minibuffer-completion ()
2024-09-12 20:32:05 -07:00
(setq-local completion-in-region-function #'consult-completion-in-region))
2023-09-18 13:05:09 -07:00
(evil-declare-motion #'consult-line))
2023-11-27 15:53:58 -08:00
(use-package consult-eglot
:commands consult-eglot-symbols)
2023-09-18 13:05:09 -07:00
2024-09-13 05:46:16 -07:00
;; wgrep
(use-package wgrep)
2023-09-18 13:05:09 -07:00
;; integration for embark and consult
(use-package embark-consult
:hook (embark-collect-mode . consult-preview-at-point-mode))
;; corfu (autocomplete)
(use-package corfu
:bind (("M-<tab>" . completion-at-point)
:map corfu-map
2024-10-14 16:12:36 -07:00
("C-j" . corfu-next)
("C-k" . corfu-previous)
("M-SPC" . corfu-insert-separator)
("M-m" . my/corfu-move-to-minibuffer))
:init
(defun my/corfu-move-to-minibuffer ()
(interactive)
(when completion-in-region--data
(let ((completion-extra-properties corfu--extra)
(completion-cycle-threshold completion-cycling))
(apply #'consult-completion-in-region completion-in-region--data))))
(setq corfu-cycle t
corfu-auto t
corfu-on-exact-match nil
2024-10-15 16:43:52 -07:00
corfu-popupinfo-delay '(1.0 . 0.5)
completion-cycle-threshold nil
global-corfu-minibuffer
;; only enable corfu in the minibuffer in graphical frames
(lambda ()
(and (display-graphic-p)
(not (eq (current-local-map)
read-passwd-map)))))
(global-corfu-mode 1)
(corfu-popupinfo-mode 1)
2024-07-15 17:50:25 -07:00
:config
2024-10-15 16:43:52 -07:00
(add-to-list 'corfu-continue-commands #'my/corfu-move-to-minibuffer)
(defun my/help-buffer-exists-p ()
"Return if the buffer that `help-buffer' would, or nil if it doesn't exist."
(or (and help-xref-following (derived-mode-p 'help-mode))
(get-buffer "*Help*")))
(defun my/-corfu-popupinfo-close-help-buffer (oldfun &rest args)
(if (derived-mode-p 'emacs-lisp-mode)
(let ((help-buf (my/help-buffer-exists-p)))
(prog1
(apply oldfun args)
(when-let (((not help-buf))
(buf (help-buffer)))
;; Ensure that, even if `help-buffer' returns nil in the future, we
;; don't kill the current buffer
(kill-buffer buf))))
(apply oldfun args)))
(advice-add 'corfu-popupinfo--get-documentation :around
'my/-corfu-popupinfo-close-help-buffer))
(use-package corfu-terminal
:init
2024-10-15 16:43:52 -07:00
(corfu-terminal-mode 1)
:config
(require 'corfu-terminal-popupinfo)
(corfu-terminal-popupinfo-mode 1))
(use-package dabbrev
:ensure nil
:config
(add-to-list 'dabbrev-ignored-buffer-regexps "\\` ")
(add-to-list 'dabbrev-ignored-buffer-modes 'doc-view-mode)
(add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode)
(add-to-list 'dabbrev-ignored-buffer-modes 'tags-table-mode))
;; cape (a bunch of capfs!)
(use-package cape
:bind (("C-c p" . cape-dabbrev)
([remap dabbrev-expand] . cape-dabbrev)
("C-c P" . cape-line)
("C-c f" . cape-file))
:hook (text-mode . my/-cape-setup-text-mode)
:init
(defun my/-cape-setup-text-mode ()
2024-10-04 12:49:16 -07:00
;; Only run this if we are not in `TeX-mode'
(unless (bound-and-true-p TeX-mode-p)
(setq-local completion-at-point-functions
(append completion-at-point-functions (list 'cape-dict
'cape-dabbrev))
2024-10-04 12:49:16 -07:00
corfu-auto nil))))
2023-09-18 13:05:09 -07:00
;; xref
(use-package xref
:init
(evil-define-key '(normal motion) 'global
2023-09-21 03:20:43 -07:00
"gr" #'xref-find-references)
2023-09-18 13:05:09 -07:00
(setq xref-show-xrefs-function #'consult-xref
2023-09-21 03:20:43 -07:00
xref-show-definitions-function #'consult-xref))
2023-09-18 13:05:09 -07:00
2023-09-20 03:57:16 -07:00
;; popup.el
(use-package popup)
2023-11-03 23:04:36 -07:00
;; posframe
(use-package posframe
:init
(defun my/posframe-tip (name msg)
"Like `popup-tip', but with a posframe.
NAME should be the buffer name to pass to `posframe-show'. MSG is the message to
display."
(unwind-protect
(progn
(posframe-show name
:string msg
:position (point)
:max-width 80
:border-width 2
:border-color "white")
(clear-this-command-keys)
(push (read-event) unread-command-events)
(posframe-hide name))
(posframe-hide name))))
(defun my/floating-tooltip (name msg)
"If `display-graphic-p', call `my/posframe-tip', otherwise `popup-tip'.
MSG is the message to show in the popup. NAME is the name of the buffer to pass
to `posframe-show' if the display is graphical."
(if (display-graphic-p)
(my/posframe-tip name msg)
(popup-tip msg)))
2023-09-18 13:05:09 -07:00
;; flymake
2023-11-27 15:53:58 -08:00
(use-package flymake
2024-10-17 20:28:16 -07:00
:config
(require 'consult-flymake))
;; flycheck
(use-package flycheck
2024-10-27 14:15:03 -07:00
:hook ((sh-mode emacs-lisp-mode) . flycheck-mode)
2024-04-30 02:38:47 -07:00
:custom
(flycheck-indication-mode 'left-margin)
:init
2024-10-17 20:28:16 -07:00
(setq flycheck-display-errors-function nil))
(use-package consult-flycheck)
(defun my/sly-notes-at-point (&optional pos buffer)
"Return the sly notes at POS in BUFFER.
If BUFFER is nil, the current buffer is used."
(with-current-buffer (or buffer (current-buffer))
(unless pos
(setq pos (point)))
(cl-loop for overlay in (overlays-at pos)
for note = (overlay-get overlay 'sly-note)
when note
collect note)))
2024-10-17 20:28:16 -07:00
(defun my/diagnostic-at-point ()
"Show the diagnostics under point."
(interactive)
(let ((message))
(when-let (((bound-and-true-p flymake-mode))
2024-10-17 20:28:16 -07:00
(diag (get-char-property (point) 'flymake-diagnostic)))
(cl-callf nconc message (string-split (flymake--diag-text diag) "\n" t)))
(when (bound-and-true-p flycheck-mode)
2024-10-17 20:28:16 -07:00
(cl-callf nconc message
(mapcar 'flycheck-error-message (flycheck-overlay-errors-at (point)))))
;; sly (lazy-loaded)
(when (featurep 'sly)
(cl-callf nconc message (mapcar (lambda (note)
(plist-get note :message))
(my/sly-notes-at-point))))
2024-10-17 20:28:16 -07:00
;; jinx
(when-let (((bound-and-true-p jinx-mode))
(jinx-msg (jinx--get-overlays (point) (1+ (point)))))
2024-10-17 20:28:16 -07:00
(push "misspelled word" message))
(when message
(my/floating-tooltip " *my-diagnostic-posframe*"
(mapconcat (lambda (msg)
(concat "" msg))
message "\n")))))
(defconst my/consult-flymake-flycheck-narrow
'((?e . "Error")
(?w . "Warning")
(?i . "Info")
(?n . "Info")))
(defun my/-consult-replace-flymake-error-level (candidates)
"Return CANDIDATES with the flymake error level note replaced with info."
(cl-loop for cand in candidates
collect
(cl-loop
with start = nil
for i below (length cand)
for props = (text-properties-at i cand)
for face = (plist-get props 'face)
when (eq face 'compilation-info) do
(setq start (or start i))
else when start do
(setf (substring cand start i)
(propertize (string-pad "info" (- i start))
'face (flycheck-error-level-error-list-face
'info)))
(cl-return cand)
finally return cand)))
(defun my/consult-flymake-flycheck-candidates (&optional project)
"Return combined candidate list for flymake and flycheck.
With PROJECT, return the candiadeets for that project."
(let ((had-errors))
(prog1
(seq-uniq
(append
(when-let (((bound-and-true-p flymake-mode))
(diags (if project (flymake--project-diagnostics
project)
(flymake-diagnostics))))
(setq had-errors t)
(my/-consult-replace-flymake-error-level
(consult-flymake--candidates diags)))
(when (boundp 'flycheck-mode)
(if project
(cl-loop for buf in (project-buffers project)
append
(with-current-buffer buf
(when (and flycheck-mode flycheck-current-errors)
(setq had-errors t)
(consult-flycheck--candidates))))
(when (and flycheck-mode flycheck-current-errors)
(setq had-errors t)
(consult-flycheck--candidates))))))
(unless had-errors
(user-error "No errors (Flymake: %s | Flycheck: %s)"
(cond
((not (bound-and-true-p flymake-mode))
"not running")
((seq-difference (flymake-running-backends)
(flymake-reporting-backends))
"running")
(t "finished"))
(if (boundp 'flycheck-last-status-change)
flycheck-last-status-change
"not running"))))))
(defun my/consult-flymake-flycheck (&optional project)
"Jump to flymake or flycheck error.
With PROJECT, give diagnostics for all buffers in the current project."
(interactive "P")
(consult--read
(consult--with-increased-gc
(my/consult-flymake-flycheck-candidates
(and project (project-current))))
:prompt "Error: "
:category 'flymake-flycheck-error
:history t
:require-match t
:sort nil
:narrow (consult--type-narrow my/consult-flymake-flycheck-narrow)
:group (consult--type-group my/consult-flymake-flycheck-narrow)
:lookup #'consult--lookup-candidate
:state (consult--jump-state)))
(with-eval-after-load 'flymake
2024-10-31 18:19:54 -07:00
(keymap-set flymake-mode-map "C-c e" 'my/diagnostic-at-point)
(keymap-set flymake-mode-map "C-c E" 'my/consult-flymake-flycheck))
2024-10-17 20:28:16 -07:00
(with-eval-after-load 'flycheck
2024-10-31 18:19:54 -07:00
(keymap-set flycheck-mode-map "C-c e" 'my/diagnostic-at-point)
(keymap-set flycheck-mode-map "C-c E" 'my/consult-flymake-flycheck))
2024-10-17 20:28:16 -07:00
(with-eval-after-load 'jinx
2024-10-31 18:19:54 -07:00
(keymap-set jinx-mode-map "C-c e" 'my/diagnostic-at-point))
2023-09-18 13:05:09 -07:00
;; eldoc
(use-package eldoc
:diminish eldoc-mode
:init
2024-01-04 00:14:49 -08:00
(setq-default eldoc-echo-area-use-multiline-p nil))
2023-09-18 13:05:09 -07:00
2023-09-20 00:50:34 -07:00
;; eglot
2023-11-27 15:53:58 -08:00
(use-package eglot
:demand t
2024-09-14 15:40:11 -07:00
:pin gnu ;; try to force Elpa version to fix warnings
2024-10-21 17:12:25 -07:00
:hook ((eglot-managed-mode . my/-eglot-setup))
2023-09-20 00:50:34 -07:00
:init
2024-10-21 17:12:25 -07:00
;; (defun my/eglot-in-text-mode-only ()
;; (when (eq major-mode 'text-mode)
;; (eglot-ensure)))
2023-11-27 15:53:58 -08:00
(defvar my/-eglot-documentation-buffer nil
"Buffer for showing documentation for `my/eglot-documentation-at-point'.")
(defun my/eglot-documentation-at-point ()
"Show documentation for a symbol at point."
2023-10-05 21:43:36 -07:00
(interactive)
2023-11-27 15:53:58 -08:00
(if-let (server (eglot-current-server))
(progn
(if-let* (((not (buffer-live-p my/-eglot-documentation-buffer)))
(name (generate-new-buffer-name "*eglot documentation*")))
(setq my/-eglot-documentation-buffer (generate-new-buffer name)))
(eglot-hover-eldoc-function
(lambda (info _ _)
(if-let (((not (seq-empty-p info)))
(buff (current-buffer)))
(with-current-buffer my/-eglot-documentation-buffer
(read-only-mode -1)
(erase-buffer)
(insert info)
(goto-char (point-min))
2023-11-27 15:53:58 -08:00
(special-mode)
(read-only-mode 1)
(when (not (get-buffer-window my/-eglot-documentation-buffer nil))
(switch-to-buffer-other-window my/-eglot-documentation-buffer t)
(switch-to-buffer-other-window buff t)))))))))
(defun my/-eglot-cleanup-doc-buffer (_server &optional _interactive _timeout
preserve-buffers)
(when (and (not preserve-buffers)
(buffer-live-p my/-eglot-documentation-buffer)
(cl-every (lambda (buffer)
(with-current-buffer buffer
(let ((server (eglot-current-server)))
(or (not (eglot-lsp-server-p server))
(eglot--shutdown-requested server)))))
(buffer-list)))
(kill-buffer my/-eglot-documentation-buffer)))
(advice-add 'eglot-shutdown :after 'my/-eglot-cleanup-doc-buffer)
2023-11-27 15:53:58 -08:00
(defun my/-eglot-setup ()
"Setup eldoc variables for `eglot-managed-mode-hook'."
2024-01-04 00:14:49 -08:00
(setq-local evil-lookup-func #'my/eglot-documentation-at-point)
2023-11-27 15:53:58 -08:00
(evil-define-key '(normal motion) 'local
"K" #'evil-lookup
"gR" #'eglot-rename
"gA" #'eglot-code-actions
"gs" #'consult-eglot-symbols)
(eglot-inlay-hints-mode -1))
(setq eglot-autoshutdown t)
:config
(add-to-list 'eglot-server-programs
(cons '(c-mode c-ts-mode c++-mode c++-ts-mode objc-mode)
'("clangd" "--all-scopes-completion" "--background-index"
"--clang-tidy" "--completion-style=detailed"
"--header-insertion=never" "--pch-storage=memory"
"--function-arg-placeholders"))))
2023-11-27 15:53:58 -08:00
2024-10-17 20:28:16 -07:00
;; LTeX (languagetool)
(require 'ltex-eglot)
2024-01-10 17:19:27 -08:00
;; gud
(use-package gud
:demand t
:ensure nil
:after (project evil)
:bind (:map project-prefix-map
2024-09-13 01:20:27 -07:00
("U" . my/project-gdb))
2024-10-08 16:35:45 -07:00
:config
2024-01-10 17:19:27 -08:00
(setq gdb-debuginfod-enable-setting t)
(defvar my/project-gdb-command nil
"Command to use in `my/project-gdb'.")
(put 'my/project-gdb-command 'safe-local-variable (lambda (val)
(stringp val)))
(defun my/project-gdb (project command-line)
"Run gdb in the project root"
(interactive (let* ((project (project-current t))
2024-01-30 12:37:19 -08:00
(default-directory (project-root project)))
2024-01-10 17:19:27 -08:00
(list project (gud-query-cmdline 'gdb))))
(let ((default-directory (project-root project)))
(gdb command-line)))
(evil-set-initial-state 'gdb-locals-mode 'motion)
(evil-collection-inhibit-insert-state 'gdb-locals-mode-map)
(evil-define-key '(normal motion visual) gdb-locals-mode-map
(kbd "TAB") (keymap-lookup gdb-locals-mode-map "TAB")
(kbd "RET") #'gdb-edit-locals-value
(kbd "<mouse-1>") #'gdb-edit-locals-value
"q" #'kill-current-buffer)
(evil-set-initial-state 'gdb-registers-mode 'motion)
(evil-collection-inhibit-insert-state 'gdb-registers-mode-map)
(evil-define-key '(normal motion visual) gdb-registers-mode-map
(kbd "TAB") (keymap-lookup gdb-registers-mode-map "TAB")
(kbd "RET") #'gdb-edit-register-value
(kbd "<mouse-1>") #'gdb-edit-register-value
"q" #'kill-current-buffer
(kbd "C-c f") #'gdb-registers-toggle-filter
(kbd "C-c F") (lambda ()
"Customize the filter for the registers buffer."
(interactive)
(customize-option-other-window
'gdb-registers-filter-pattern-list)))
(evil-set-initial-state 'gdb-frames-mode 'motion)
(evil-collection-inhibit-insert-state 'gdb-frames-mode-map)
(evil-define-key '(normal motion visual) gdb-frames-mode-map
"q" #'kill-current-buffer
(kbd "RET") #'gdb-select-frame)
(evil-set-initial-state 'gdb-breakpoints-mode 'motion)
(evil-collection-inhibit-insert-state 'gdb-breakpoints-mode-map)
(evil-define-key '(normal motion visual) gdb-breakpoints-mode-map
(kbd "TAB") (keymap-lookup gdb-breakpoints-mode-map "TAB")
"q" #'gdb-delete-frame-or-window
"D" #'gdb-delete-breakpoint
(kbd "RET") #'gdb-goto-breakpoint
(kbd "<mouse-1>") #'gdb-goto-breakpoint
(kbd "SPC") #'gdb-toggle-breakpoint)
(evil-set-initial-state 'gdb-threads-mode 'motion)
(evil-collection-inhibit-insert-state 'gdb-threads-mode-map)
(evil-define-key '(normal motion visual) gdb-threads-mode-map
(kbd "TAB") (keymap-lookup gdb-threads-mode-map "TAB")
"q" #'gdb-delete-frame-or-window
"D" #'gdb-frame-disassembly-for-thread
(kbd "C-c f") #'gdb-display-stack-for-thread
(kbd "C-c i") #'gdb-interrupt-thread
(kbd "C-c l") #'gdb-display-locals-for-thread
(kbd "C-c r") #'gdb-display-registers-for-thread
(kbd "C-c c") #'gdb-continue-thread
(kbd "C-c d") #'gdb-display-disassembly-for-thread
(kbd "C-c s") #'gdb-step-thread
(kbd "C-c F") #'gdb-frame-stack-for-thread
(kbd "C-c L") #'gdb-frame-locals-for-thread
(kbd "C-c R") #'gdb-frame-registers-for-thread
(kbd "RET") #'gdb-select-thread
(kbd "<mouse-2>") #'gdb-select-thread))
2024-07-16 03:23:03 -07:00
;; dape
(use-package dape
:hook ((after-init . dape-breakpoint-load)
(kill-emacs . dape-breakpoint-save)
(dape-start . save-some-buffers)
(dape-display-source . pulse-momentary-highlight-one-line))
:bind (:map dape-info-parent-mode-map
("<tab>" . dape--info-buffer-tab))
2024-07-17 04:18:05 -07:00
:init
(setopt dape-default-breakpoints-file (no-littering-expand-var-file-name
"dape-breakpoints"))
2024-07-16 03:23:03 -07:00
:config
(setopt dape-buffer-window-arrangement 'right)
(dape-breakpoint-global-mode 1))
2024-01-08 21:32:05 -08:00
;; dumb-jump
(use-package dumb-jump
:init
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate))
2023-10-12 15:08:13 -07:00
;; yasnippet
(use-package yasnippet
:demand t
2023-10-12 15:08:13 -07:00
:bind ("C-c s" . yas-expand)
:config
2023-10-12 15:08:13 -07:00
(yas-global-mode 1))
;; project.el
(use-package project
2023-11-07 03:19:30 -08:00
:bind (("C-c v" . my/project-eshell-or-default)
2024-08-01 00:50:59 -07:00
([remap project-compile] . my/project-compile-or-default)
2023-10-12 16:56:14 -07:00
:map project-prefix-map
2023-11-07 03:19:30 -08:00
("s" . my/project-eshell)
2023-09-30 21:41:19 -07:00
("u" . my/project-run))
:init
2023-11-07 03:19:30 -08:00
(defvar eshell-buffer-name)
(defun my/project-eshell (prompt &optional arg)
"Switch to or create an eshell buffer in the current projects root."
(interactive (list t current-prefix-arg))
2023-10-12 16:56:14 -07:00
(if-let ((proj (project-current prompt))
2023-11-07 03:19:30 -08:00
(default-directory (project-root proj))
(eshell-buffer-name
(concat "*eshell for project " default-directory "*")))
2023-11-17 16:28:59 -08:00
(eshell arg)))
2023-11-07 03:19:30 -08:00
(defun my/project-eshell-or-default (&optional arg)
"Open an eshell for the current project, otherwise, open a normal eshell."
(interactive "P")
(unless (my/project-eshell nil arg)
(eshell arg)))
2024-08-01 00:50:59 -07:00
(defun my/project-compile-or-default ()
"If in a project, run `project-compile', otherwise run `compile'."
(interactive)
(if (project-current)
(call-interactively 'project-compile)
(call-interactively 'compile)))
(defvar my/project-run-command nil
"Command to run with `my/project-run'.")
(put 'my/project-run-command 'safe-local-variable (lambda (val)
(stringp val)))
2023-10-10 02:50:48 -07:00
(defvar my/project-run-dir nil
"Directory to run project in with `my/project-run'.")
(put 'my/project-run-dir 'safe-local-variable (lambda (val)
(stringp val)))
(defvar my/-project-run-history '()
"Commands previously run with `my/project-run'")
2023-11-02 21:38:31 -07:00
(defvar my/project-root-marker ".project-root"
"Marker file to look for in non-vc backed projects.")
2023-10-10 02:50:48 -07:00
(defun my/project-get-root-dir ()
"Get the root dir for the current project"
2023-10-20 02:29:29 -07:00
(let* ((proj (project-current nil))
(default-directory (if proj
(project-root proj)
default-directory)))
(if my/project-run-dir
(expand-file-name my/project-run-dir)
default-directory)))
(defun my/project-run (command comint)
"Like `project-compile', but for running a project.
COMMAND and COMINT are like `compile'."
2023-10-10 14:14:30 -07:00
(interactive
(list
(let ((default-directory (my/project-get-root-dir)))
(read-shell-command "Run Command: "
2024-04-21 02:33:12 -07:00
(or (car my/-project-run-history)
my/project-run-command)
2023-10-10 14:14:30 -07:00
(if (and my/project-run-command
(equal my/project-run-command
(car-safe my/-project-run-history)))
'(my/-project-run-history . 1)
'my/-project-run-history)))
(consp current-prefix-arg)))
2023-10-10 02:50:48 -07:00
(let* ((default-directory (my/project-get-root-dir))
(compilation-buffer-name-function (lambda (_)
(progn "*run project*")))
(compilation-directory default-directory)
2023-10-10 14:14:30 -07:00
(compile-history nil)
(compile-command nil))
(compile command comint)
(when (not my/project-run-command)
2023-11-02 21:38:31 -07:00
(setq my/project-run-command command))))
:config
(defun my/project-try-dotfile (dir)
(if-let (root (locate-dominating-file dir my/project-root-marker))
(list 'vc nil root)))
(add-hook 'project-find-functions #'my/project-try-dotfile))
2023-10-20 14:21:20 -07:00
;; nxml
(use-package nxml-mode
:ensure nil
:hook (nxml-mode . my/-nxml-setup)
:init
(defun my/-nxml-setup ()
"Setup `nxml-mode'."
(sgml-electric-tag-pair-mode 1)
(setq-local completion-at-point-functions
2023-10-20 15:27:19 -07:00
'(rng-completion-at-point cape-file)))
(add-to-list 'auto-mode-alist
`(,(concat
2024-10-15 16:43:52 -07:00
(regexp-opt '("gschema" "gresource" "ui")) "\\'")
. nxml-mode)))
2023-10-20 15:27:19 -07:00
2024-10-05 02:34:48 -07:00
;; Bibtex (built in)
2024-10-05 02:55:22 -07:00
(require 'bibtex)
(defun my/bibtex-in-entry-p (&optional exclude-braces)
"Return t is point is inside a BibTeX entry.
2024-10-05 02:34:48 -07:00
When EXCLUDE-BRACES is non-nil, don't count the first and last brace of the
2024-10-05 02:55:22 -07:00
entry as in the entry. That is, if the point is on the first { or last } of the
2024-10-05 02:34:48 -07:00
entry, return nil."
2024-10-05 02:55:22 -07:00
(save-excursion
2024-10-09 07:32:06 -07:00
(when (and exclude-braces (eq ?\} (char-after)))
2024-10-05 02:55:22 -07:00
(forward-char))
;; go to top level and check if the character at point is {
(let ((start-pos (point))
(last-valid (point)))
2024-11-19 19:25:21 -08:00
(condition-case nil
2024-10-05 02:55:22 -07:00
(while t
(backward-up-list 1 t t)
(setq last-valid (point)))
(error
(and
2024-10-09 07:32:06 -07:00
(eq ?\{ (char-after last-valid))
2024-10-05 02:55:22 -07:00
(or (not exclude-braces)
(not (= start-pos last-valid)))))))))
(defvar my/bibtex-indent-width 4
"Width to indent for `my/bibtex-calculate-indentation'.")
(defun my/bibtex-calculate-indentation ()
"Calculate the column to indent to on the current line."
(save-excursion
(back-to-indentation)
(if (my/bibtex-in-entry-p t)
my/bibtex-indent-width
0)))
(defun my/bibtex-empty-line-p ()
"Return t if the current line is only blank characters."
(save-excursion
(beginning-of-line)
(looking-at (rx (* blank) eol))))
(defun my/bibtex-indent-line ()
"Indent the current line."
(interactive)
(save-excursion
(beginning-of-line)
(when (looking-at (rx (+ blank)))
(delete-region (point) (match-end 0)))
(indent-to (my/bibtex-calculate-indentation)))
(when (looking-at (rx (+ blank) eol))
(end-of-line)))
(defun my/bibtex-indent-or-find-text ()
"Either indent the current line or jump to the current fields text.
2024-10-05 02:34:48 -07:00
If the current line is only whitespace call `my/bibtex-calculate-indentation',
otherwise, call `bibtex-find-text'."
2024-10-05 02:55:22 -07:00
(interactive)
(if (my/bibtex-empty-line-p)
(my/bibtex-indent-line)
(bibtex-find-text)))
(defun my/bibtex-indent-or-find-text-and-insert ()
"Like `my/bibtex-indent-or-find-text', but enter insert mode after."
(interactive)
(my/bibtex-indent-or-find-text)
(if (my/bibtex-empty-line-p)
(evil-append 1)
(evil-insert 1)))
(defun my/-bibtex-setup-indent ()
"Set up `bibtex-mode' indentation stuff."
(setq-local indent-line-function 'my/bibtex-indent-line
electric-indent-chars '(?\n ?\{ ?\} ?,)))
2024-10-14 02:10:55 -07:00
(defun my/-bibtex-fix-fill-prefix ()
"`bivtex-mode' has a bad habbit of messing up `fill-prefix'."
(when (eq major-mode 'bibtex-mode)
(setq-local fill-prefix nil)))
(advice-add 'bibtex-mode :after 'my/-bibtex-fix-fill-prefix)
2024-10-05 02:55:22 -07:00
(add-hook 'bibtex-mode-hook 'my/-bibtex-setup-indent)
2024-10-31 18:19:54 -07:00
(keymap-set bibtex-mode-map "RET" 'newline-and-indent)
(keymap-set bibtex-mode-map "TAB" 'my/bibtex-indent-or-find-text)
2024-10-05 02:55:22 -07:00
(evil-define-key 'normal bibtex-mode-map
(kbd "TAB") 'my/bibtex-indent-or-find-text-and-insert)
2024-10-05 02:34:48 -07:00
2024-10-09 07:32:06 -07:00
;; Latex help (from elisp file)
(require 'latex-help)
2024-10-04 12:49:16 -07:00
;; AUCTeX
(use-package auctex
:hook ((LaTeX-mode . turn-on-reftex)
2024-10-09 07:32:06 -07:00
(LaTeX-mode . LaTeX-math-mode)
(LaTeX-mode . my/-setup-LaTeX-mode)
2024-10-21 17:12:25 -07:00
(LaTeX-mode . flycheck-mode))
2024-10-10 06:42:08 -07:00
:bind (:map TeX-mode-map
2024-10-14 21:38:33 -07:00
("C-c ?" . latex-help))
2024-09-10 15:27:10 -07:00
:init
2024-10-04 12:49:16 -07:00
(add-to-list 'major-mode-remap-alist '(plain-tex-mode . plain-TeX-mode))
(add-to-list 'major-mode-remap-alist '(latex-mode . LaTeX-mode))
(add-to-list 'major-mode-remap-alist '(ams-tex-mode . AmSTeX-mode))
(add-to-list 'major-mode-remap-alist '(context-mode . ConTeXt-mode))
(add-to-list 'major-mode-remap-alist '(texinfo-mode . Texinfo-mode))
(add-to-list 'major-mode-remap-alist '(doctex-mode . docTeX-mode))
(add-to-list 'auto-mode-alist '("/\\.latexmkrc\\'" . perl-mode))
2024-10-17 20:28:16 -07:00
(add-to-list 'auto-mode-alist '("\\.[tT]e[xX]\\'" . LaTeX-mode))
2024-03-20 18:34:06 -07:00
:config
2024-10-14 16:12:36 -07:00
(defun my/-auctex-texdoc-setup-env (oldfun &rest args)
2024-10-14 21:38:33 -07:00
(let ((process-environment process-environment)
(emacs-cmd (concat "emacsclient" (and (not (display-graphic-p)) " -nw"))))
(setenv "PDFVIEWER_texdoc" "evince")
(setenv "MDVIEWER_texdoc" emacs-cmd)
(setenv "PAGER_texdoc" emacs-cmd)
2024-10-14 16:12:36 -07:00
(apply oldfun args)))
(advice-add 'TeX-documentation-texdoc :around 'my/-auctex-texdoc-setup-env)
2024-10-09 07:32:06 -07:00
(defun my/-setup-LaTeX-mode ()
(setq evil-lookup-func 'latex-help-at-point))
2024-10-04 12:49:16 -07:00
(setq TeX-auto-save t
TeX-parse-self t
reftex-plug-into-AUCTeX t)
(evil-define-operator my/evil-LaTeX-fill (beg end)
"Like `evil-fill', but using auctex."
;; The code here came straight from `evil-fill'
:move-point nil
:type line
(save-excursion
(ignore-errors (LaTeX-fill-region beg end))))
(evil-define-operator my/evil-LaTeX-fill-and-move (beg end)
"Like `evil-fill-and-move', but using auctex."
;; The code here came straight from `evil-fill-and-move'
:move-point nil
:type line
(let ((marker (make-marker)))
(move-marker marker (1- end))
(ignore-errors
(LaTeX-fill-region beg end)
(goto-char marker)
(evil-first-non-blank))))
(evil-define-key 'normal TeX-mode-map
"gq" 'my/evil-LaTeX-fill-and-move
"gw" 'my/evil-LaTeX-fill)
2024-10-04 12:49:16 -07:00
(setq-default TeX-master nil)
2024-10-08 16:35:45 -07:00
(require 'tex)
(TeX-global-PDF-mode 1))
2024-01-09 01:35:55 -08:00
2023-10-20 15:27:19 -07:00
;; blueprint
(use-package blueprint-ts-mode
2024-01-09 01:35:55 -08:00
:hook (blueprint-ts-mode . eglot-ensure)
2023-10-20 15:27:19 -07:00
:after eglot)
2023-10-20 14:21:20 -07:00
2024-01-09 01:35:55 -08:00
;; python-ts-mode
(use-package python-ts-mode
:ensure nil
:hook (python-ts-mode . eglot-ensure))
;; java-ts-mode
(use-package java-ts-mode
:hook (java-ts-mode . eglot-ensure))
2024-01-08 16:26:25 -08:00
;; c-ts-mode
(use-package c-ts-mode
:after evil
2024-01-09 01:35:55 -08:00
:hook ((c-ts-mode c++-ts-mode) . eglot-ensure)
2024-01-08 16:26:25 -08:00
:init
(setq-default c-ts-mode-indent-offset 4)
:config
(evil-define-key 'normal 'c-ts-mode-map
"go" #'ff-find-other-file
"gO" #'ff-find-other-file-other-window)
(evil-define-key 'normal 'c++-ts-mode-map
"go" #'ff-find-other-file
"gO" #'ff-find-other-file-other-window)
(evil-define-key 'normal 'objc-mode-map
"go" #'ff-find-other-file
"gO" #'ff-find-other-file-other-window))
2024-01-09 01:35:55 -08:00
;; php-mode
(use-package php-mode
:hook (php-mode . eglot-ensure))
;; web-mode
(use-package web-mode
:hook (web-mode . eglot-ensure)
:init
(add-to-list 'eglot-server-programs
'(web-mode . ("vscode-html-language-server" "--stdio"))))
;; Polymode
(use-package polymode
:config
(define-hostmode my/poly-web-hostmode
:mode 'web-mode)
(define-innermode my/poly-php-innermode
:mode 'php-mode
:head-matcher "\<\?php"
:tail-matcher "\?\>"
:head-mode 'body
:tail-mode 'body)
(define-polymode my/poly-web-mode
:hostmode 'my/poly-web-hostmode
:innermodes '(my/poly-php-innermode))
(add-to-list 'auto-mode-alist '("\\.php\\|\\.phtml\\'" . my/poly-web-mode)))
;; shell-mode
(use-package sh-script
:ensure nil
:hook (sh-mode . my/-setup-sh-mode)
:init
(defun my/-setup-sh-mode ()
(add-to-list 'completion-at-point-functions #'cape-file)))
2024-03-08 19:54:16 -08:00
;; go mode
2024-03-08 23:27:07 -08:00
(use-package go-mode
2024-03-23 04:56:00 -07:00
:defer nil
:hook (go-mode . eglot-ensure))
2024-03-08 19:54:16 -08:00
(use-package go-ts-mode
:ensure nil
2024-03-08 23:27:07 -08:00
:hook (go-ts-mode . eglot-ensure))
2024-03-08 19:54:16 -08:00
2023-09-20 00:50:34 -07:00
;; rust
(use-package rust-mode)
2024-01-09 01:35:55 -08:00
(use-package rust-ts-mode
:ensure nil
2024-01-10 05:02:27 -08:00
:hook (rust-ts-mode . eglot-ensure))
2023-09-20 00:50:34 -07:00
2024-05-02 17:06:27 -07:00
;; zig
(use-package zig-mode
:hook (zig-mode . eglot-ensure))
2024-03-27 00:43:39 -07:00
;; lua
(use-package lua-mode
:hook (lua-mode . eglot-ensure))
;; markdown
2023-12-13 01:28:49 -08:00
(use-package markdown-mode
2024-04-20 04:48:55 -07:00
:hook (markdown-mode . auto-fill-mode))
2023-12-01 13:15:13 -08:00
;; groovy
(use-package groovy-mode)
;; cmake
2023-11-27 15:53:58 -08:00
(require 'cmake-mode)
(with-eval-after-load 'cmake-mode
(defun my/setup-cmake-ts-mode ()
"Setup `cmake-ts-mode' buffers."
2023-11-27 15:53:58 -08:00
(setq-local indent-line-function #'cmake-indent))
(add-hook 'cmake-ts-mode-hook #'my/setup-cmake-ts-mode))
2024-04-24 21:05:48 -07:00
;; kdl
(require 'kdl-ts-mode)
2023-09-20 00:50:34 -07:00
;; json
2024-01-09 04:50:59 -08:00
(use-package json-ts-mode
:hook (json-ts-mode . eglot-ensure))
2023-09-20 00:50:34 -07:00
(use-package json-mode)
2024-10-23 00:18:47 -07:00
;; csv
(use-package csv-mode)
2023-10-13 11:41:29 -07:00
;; firejail
(require 'firejail-mode)
2023-09-23 16:48:22 -07:00
;; yaml
2024-01-09 04:50:59 -08:00
(use-package yaml-ts-mode
:hook ((yaml-ts-mode . eglot-ensure)
(yaml-ts-mode . my/-setup-yaml-ts-mode))
:init
(defun my/-setup-yaml-ts-mode ()
(setq indent-line-function #'yaml-indent-line)))
2023-09-23 16:48:22 -07:00
(use-package yaml-mode)
2023-10-10 14:14:30 -07:00
;; yuck (config language for eww)
(use-package yuck-mode)
2024-09-13 01:20:27 -07:00
;; Some Elisp indentation stuff
;; Source: https://github.com/magit/emacsql
;; emacsql.el line 394
(defun my/lisp-inside-plist-p ()
"Return t if point is inside a plist."
(save-excursion
(let ((start (point)))
(beginning-of-defun)
(when-let ((sexp (nth 1 (parse-partial-sexp (point) start))))
(goto-char sexp)
(looking-at (rx "(" (* (syntax whitespace)) ":"))))))
(defun my/-calculate-indent-fix-plists (oldfun &rest args)
"This function is meant to advise `calculate-lisp-indent'.
It calls OLDFUN with ARGS in such an environment as to prevent the default
indentation of plists."
(if (and (eq major-mode 'emacs-lisp-mode)
(save-excursion
(beginning-of-line)
(my/lisp-inside-plist-p)))
2024-09-13 01:20:27 -07:00
(let ((lisp-indent-offset 1))
(apply oldfun args))
(apply oldfun args)))
(advice-add 'calculate-lisp-indent :around
'my/-calculate-indent-fix-plists)
2024-09-16 00:44:50 -07:00
(defvar my/max-lisp-noindent-comment-search-lines 30
2024-09-13 01:20:27 -07:00
"Max lines to search for the noindent comment.")
(defun my/-calculate-lisp-indent-noindent-comment (oldfun &rest args)
"This function is meant to advise `calculate-lisp-indent'.
It calls OLDFUN with ARGS, unless the line ends with the comment
; noindent [LINES]
In this case, it just returns the current amount of indentation. LINES is the
number of lines that this comment affects. This is limited by
`my/max-lisp-noindent-comment-search-lines'.
This only works if its on the first or second form in a block. I think this is
because the indentation code only checks those and then assumes the same
indentation for every following line in the same block. This is probably OK as
I can't imagine too many instances where you need to randomly change the indent
midway through a block, and in those cases you can just stick this on the first
line in the block and manually deal with indentation."
(if (and (save-excursion
(end-of-line)
(re-search-backward
(rx (+ ";") (syntax whitespace) "noindent"
(? (syntax whitespace) (group (+ num)))
line-end)
(pos-bol (- my/max-lisp-noindent-comment-search-lines))
t))
(save-excursion
;; if we are on a blank line, move forward a line
(when (zerop (length (buffer-substring-no-properties
(pos-bol) (pos-eol))))
(beginning-of-line 2))
(<= (count-lines (match-beginning 0) (pos-eol))
(if-let ((match (match-string 1)))
(string-to-number match)
1))))
(save-excursion
(beginning-of-line)
(looking-at (rx (* blank)))
(length (match-string 0)))
(apply oldfun args)))
(advice-add 'calculate-lisp-indent :around
'my/-calculate-lisp-indent-noindent-comment)
2024-07-15 02:11:26 -07:00
;; sly
(use-package sly
2024-10-21 17:12:25 -07:00
;; :hook (lisp-mode . my/-lisp-mode-autoconnect-sly)
2024-07-15 02:11:26 -07:00
:bind (:map sly-mode-map
("C-c e" . my/diagnostic-at-point))
2024-07-15 02:11:26 -07:00
:autoload sly-connected-p
:init
(defun my/-lisp-mode-autoconnect-sly ()
(unless (sly-connected-p)
(sly)))
(setq inferior-lisp-program "/usr/bin/sbcl")
(defun my/-sly-fix-special-buffers ()
(when (string-match-p (rx bos "*" (* any) "*" eos) (buffer-name))
(setq-local show-trailing-whitespace nil)))
(add-hook 'lisp-mode-hook 'my/-sly-fix-special-buffers)
2024-07-12 22:40:56 -07:00
:config
2024-07-15 02:11:26 -07:00
(sly-symbol-completion-mode -1))
2023-09-21 16:02:36 -07:00
2023-12-24 04:58:55 -08:00
;; pdf-tools
(use-package pdf-tools
:hook (pdf-view-mode . my/setup-pdf-view-mode)
:init
2024-02-10 03:16:21 -08:00
(setq pdf-misc-print-program-executable "lp")
2023-12-24 04:58:55 -08:00
(defun my/setup-pdf-view-mode ()
(display-line-numbers-mode -1)
(evil-define-key '(motion normal visual) 'local
(kbd "C-s") #'isearch-forward
(kbd "C-r") #'isearch-backward)
(setq-local cursor-type nil))
2024-01-02 23:45:05 -08:00
(pdf-tools-install))
2023-12-24 04:58:55 -08:00
2024-10-15 21:02:09 -07:00
;; doc view
(use-package doc-view
:ensure nil
:hook (doc-view-mode . my/-setup-doc-view-mode)
:init
(defun my/-setup-doc-view-mode ()
(display-line-numbers-mode -1)
(evil-define-key '(motion normal visual) 'local
(kbd "C-s") #'isearch-forward
(kbd "C-r") #'isearch-backward)))
;; calc
(use-package calc
:ensure nil
2024-04-20 16:14:34 -07:00
:bind (("C-c m" . quick-calc)
:map calc-mode-map
("M-<tab>" . calc-roll-up)
("M-TAB" . calc-roll-up))
:hook ((calc-mode calc-trail-mode) . my/setup-calc-calc-trail-mode)
:init
(defun my/setup-calc-calc-trail-mode ()
(setq-local doom-modeline-percent-position '()
truncate-partial-width-windows nil)
(visual-line-mode -1)
(display-line-numbers-mode -1)
(toggle-truncate-lines 1))
:config
(evil-define-key '(normal visual motion) calc-edit-mode-map
(kbd "RET") 'calc-edit-return
(kbd "<return>") 'calc-edit-return)
(defun my/-calc-float-mode-string ()
(cl-destructuring-bind (mode prec) calc-float-format
(concat
(upcase-initials (symbol-name mode))
(unless (zerop prec)
(concat ": " (number-to-string prec))))))
(doom-modeline-def-segment calc
2024-10-08 16:35:45 -07:00
"Display calculator icons and info."
(concat
(doom-modeline-spc)
(when-let ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "🖩" "")))
(concat
(doom-modeline-display-icon icon)
(doom-modeline-vspc)))
(doom-modeline--buffer-simple-name)
(when (eq major-mode 'calc-mode)
(concat
(doom-modeline-spc)
(number-to-string calc-internal-prec)
(doom-modeline-spc)
(upcase-initials (symbol-name calc-angle-mode))
(doom-modeline-spc)
(my/-calc-float-mode-string)
(when calc-prefer-frac
(concat
(doom-modeline-spc)
"Frac"))
(cond
(calc-algebraic-mode
(concat
(doom-modeline-spc)
"Alg"))
(calc-incomplete-algebraic-mode
(concat
(doom-modeline-spc)
"IAlg"))))))))
2024-03-04 21:16:21 -08:00
;; sage (for when calc is not enough)
(use-package sage-shell-mode
2024-03-04 21:25:52 -08:00
:demand
2024-03-04 21:16:21 -08:00
:bind ("C-c g" . my/run-sage)
:hook (sage-shell-mode . my/-setup-sage-shell-mode)
:init
(defun my/-setup-sage-shell-mode ()
(setq-local comint-dynamic-complete-functions
'(comint-c-a-p-replace-by-expanded-history)))
2024-03-04 21:25:52 -08:00
:config
2024-03-04 21:16:21 -08:00
(defun my/run-sage (p)
"Like `sage-shell:run-sage', but does not ask anything without a prefix
argument."
(interactive "P")
(let ((sage-shell:ask-command-options p))
(funcall-interactively #'sage-shell:run-sage
(sage-shell:read-command)))))
2024-10-09 07:32:06 -07:00
;; fricas (because I like calculators)
2024-03-19 13:04:41 -07:00
(add-to-list 'load-path "/usr/lib/fricas/emacs/")
(use-package fricas
:ensure nil
2024-03-19 14:55:30 -07:00
:custom
2024-03-20 02:44:57 -07:00
(fricas-run-command "fricas -nosman")
2024-03-19 14:55:30 -07:00
:init
;; Fix `fricas-mode' messing up `completion-at-point-functions'
(advice-add #'fricas-mode :around
#'(lambda (oldfun &rest r)
2024-03-20 02:44:57 -07:00
(let ((temp-capfs))
2024-03-19 14:55:30 -07:00
(let ((completion-at-point-functions '(t)))
(apply oldfun r)
2024-03-20 02:44:57 -07:00
(setq temp-capfs completion-at-point-functions))
(setq-local completion-at-point-functions temp-capfs)))
2024-03-19 14:55:30 -07:00
'((name . "my/-fricas-fix-capfs")))
2024-03-19 13:04:41 -07:00
:config
2024-03-19 15:04:36 -07:00
(face-spec-set 'fricas-type-time '((t (:foreground unspecified
:background unspecified
2024-03-19 13:04:41 -07:00
:inherit font-lock-type-face))))
2024-03-19 15:04:36 -07:00
(face-spec-set 'fricas-message '((t (:foreground unspecified
:background unspecified
2024-03-19 13:04:41 -07:00
:inherit error))))
2024-03-19 15:04:36 -07:00
(face-spec-set 'fricas-undefined '((t (:foreground unspecified
:background unspecified
2024-03-19 13:04:41 -07:00
:inherit nerd-icons-lblue))))
2024-03-19 15:04:36 -07:00
(face-spec-set 'fricas-algebra '((t (:foreground unspecified
:background unspecified
2024-03-19 14:55:30 -07:00
:weight bold
2024-03-19 13:04:41 -07:00
:inherit fricas-prompt))))
2024-03-20 02:44:57 -07:00
(face-spec-set 'fricas-TeX '((t (:foreground "black"
:background "white"
2024-03-19 13:04:41 -07:00
:inherit fricas-prompt)))))
2024-03-06 14:06:41 -08:00
;; gnuplot (mostly for org-plot)
(use-package gnuplot)
2023-12-27 22:43:15 -08:00
;; eat
(use-package eat
2024-09-20 12:03:09 -07:00
:bind (("C-c V" . my/project-eat-or-default)
:map eat-mode-map
("M-o" . ace-window)
:map eat-semi-char-mode-map
("M-o" . ace-window)
:map eat-eshell-emacs-mode-map
("M-o" . ace-window)
:map eat-eshell-semi-char-mode-map
("M-o" . ace-window))
2023-12-27 22:43:15 -08:00
:config
(defvar my/project-eat-hash-table (make-hash-table :test 'equal)
"Hash table that maps project root dirs to eat buffers.")
(defun my/project-eat (prompt)
"Switch to or create a eat buffer in the current projects root."
2023-11-07 03:19:30 -08:00
(interactive (list t))
(if-let ((proj (project-current prompt))
(default-directory (project-root proj)))
2023-12-27 22:43:15 -08:00
(if-let ((eat-buff (gethash default-directory
my/project-eat-hash-table))
((buffer-live-p eat-buff)))
(switch-to-buffer eat-buff)
2024-03-04 21:16:21 -08:00
(let ((eat-buffer-name (concat "*eat for project " default-directory
"*"))
(eat-term-name (if (file-remote-p default-directory)
"xterm-256color"
eat-term-name)))
2023-12-27 22:43:15 -08:00
(puthash default-directory
(eat)
2024-01-13 03:50:09 -08:00
my/project-eat-hash-table)))))
2023-12-27 22:43:15 -08:00
(defun my/project-eat-or-default ()
"Open an eat for the current project, otherwise, open a normal eat."
2023-11-07 03:19:30 -08:00
(interactive)
2023-12-27 22:43:15 -08:00
(unless (my/project-eat nil)
(if-let ((eat-buff (gethash nil my/project-eat-hash-table))
((buffer-live-p eat-buff)))
(switch-to-buffer eat-buff)
2024-03-04 21:16:21 -08:00
(puthash nil (let ((eat-term-name (if (file-remote-p default-directory)
"xterm-256color"
eat-term-name)))
2024-10-15 16:43:52 -07:00
(eat))
my/project-eat-hash-table)))))
2023-11-06 02:34:54 -08:00
;; eshell stuff
(use-package eshell
:ensure nil
:defer nil
2023-11-07 03:19:30 -08:00
:hook ((eshell-load . eat-eshell-visual-command-mode)
(eshell-load . eat-eshell-mode)
(eshell-mode . my/-eshell-mode-setup))
2024-07-24 01:52:47 -07:00
:bind (:map eshell-mode-map
2024-10-14 16:12:36 -07:00
("TAB" . completion-at-point)
("<tab>" . completion-at-point))
2023-11-06 02:34:54 -08:00
:init
2023-11-07 03:19:30 -08:00
(defun my/-eshell-mode-setup ()
"Setup function run from `eshell-mode-hook'"
(setq-local corfu-auto nil))
2023-11-06 02:34:54 -08:00
(setq-default eshell-command-aliases-list
2023-11-07 03:19:30 -08:00
'(("clear" "clear t")
("e" "find-file $1")
("n" "find-file $1")
("emacs" "find-file $1")
("nvim" "find-file $1")
("ls" "eza --git -F $*")
("la" "ls -a $*")
("l" "ls -l $*")
("ll" "la -l $*")
("gt" "git status $*")
("gp" "git push $*")
("gu" "git pull $*")
("gf" "git fetch $*")
("ga" "git add $*")
2023-11-07 19:46:14 -08:00
("gcm" "git commit -m ${string-join $* \" \"}")
2023-11-27 21:45:25 -08:00
("ldg" "ledger -f \"$HOME/docs/finance/finances.ledger\" $*")
("tp" "trash-put $*")
("trr" "trash-restore $*")
("tre" "trash-empty $*")
("tre" "trash-empty $*")
("trm" "trash-rm $*")
2023-12-24 04:58:55 -08:00
("rm" "echo 'rm: I''m unsafe! Don''t use me.'; false")
("\\rm" "eshell/rm")))
2024-01-09 15:16:54 -08:00
(defvar my/eshell-bm-auto-ls t
"Weather or not to run ls after `eshell/bm'")
2023-11-07 03:19:30 -08:00
(defun eshell/bm (&optional name)
"Change to directory of bookmark NAME.
If no name is given, list all bookmarks instead."
(if name
2024-01-09 15:16:54 -08:00
(progn
(eshell/cd (bookmark-get-filename name))
(when my/eshell-bm-auto-ls
(eshell/ls)))
2024-01-17 04:16:49 -08:00
(eshell-print (string-join (bookmark-all-names) " ")))))
2023-11-06 02:34:54 -08:00
(use-package esh-help
:hook (eshell-mode . my/-setup-eshell-help-func)
:init
(defun my/-setup-eshell-help-func ()
(eldoc-mode 1)
(setq-local evil-lookup-func #'esh-help-run-help))
(setup-esh-help-eldoc))
(use-package eshell-syntax-highlighting
:init
(eshell-syntax-highlighting-global-mode 1))
2024-01-17 04:16:49 -08:00
(use-package eshell-starship
:ensure nil
:demand t
:hook (eshell-prompt-mode . eshell-starship-prompt-mode))
2023-11-06 02:34:54 -08:00
2023-09-18 15:06:41 -07:00
;; proced
(use-package proced
2023-09-27 04:07:01 -07:00
:bind ("C-x j" . proced)
2023-09-18 15:06:41 -07:00
:init
(evil-define-key '(motion visual normal) proced-mode-map
"u" 'proced-unmark)
2023-09-18 15:06:41 -07:00
(setq proced-auto-update-flag t
2024-10-15 17:32:33 -07:00
proced-auto-update-interval 1)
(defun my/-setup-proced-mode ()
(visual-line-mode -1)
(setq-local truncate-lines t))
(add-hook 'proced-mode-hook 'my/-setup-proced-mode))
2023-09-18 15:06:41 -07:00
;; dired
(use-package dired
:ensure nil
:init
2023-10-30 22:57:54 -07:00
(setq-default dired-kill-when-opening-new-dired-buffer t)
2024-01-06 22:39:55 -08:00
(setq delete-by-moving-to-trash t
dired-recursive-copies 'always
dired-recursive-deletes 'always
dired-dwim-target t
dired-create-destination-dirs 'ask
dired-create-destination-dirs-on-trailing-dirsep t
dired-isearch-filenames 'dwim
dired-do-revert-buffer (lambda (dir)
(not (file-remote-p dir)))
dired-clean-up-buffers-too t
dired-clean-confirm-killing-deleted-buffers t)
2023-09-18 15:06:41 -07:00
(evil-define-key '(normal visual motion) dired-mode-map
2023-09-21 03:20:43 -07:00
"u" #'dired-unmark
"U" #'dired-unmark-all-marks))
2023-09-18 15:06:41 -07:00
2023-09-22 02:53:16 -07:00
;; ibuffer
(use-package ibuffer
:bind ("C-x C-b" . ibuffer))
2023-09-18 15:06:41 -07:00
;; magit
2023-12-27 22:49:30 -08:00
(use-package magit
:init
(evil-define-key '(normal visual motion) magit-mode-map
"s" #'magit-stage-file
"S" #'magit-stage-modified))
2023-09-20 00:50:34 -07:00
2023-09-27 04:07:01 -07:00
;; org-mode
(use-package org
2024-10-20 00:44:30 -07:00
:pin gnu
2023-09-27 04:07:01 -07:00
:bind (("C-c c" . org-capture)
("C-c a" . org-agenda)
("C-c l" . org-store-link)
:map org-mode-map
("C-c t" . org-table-create))
2024-03-06 11:40:17 -08:00
:hook (org-mode . org-table-header-line-mode)
2023-09-27 04:07:01 -07:00
:init
2024-10-20 00:44:30 -07:00
(font-lock-add-keywords 'org-mode
`((,(rx bol (* " ") (group "-") " ")
(0 (prog1 nil
(compose-region (match-beginning 1)
(match-end 1) ""))))))
2023-09-27 04:07:01 -07:00
(setq org-directory "~/org"
org-agenda-files '("~/org/")
org-log-into-drawer t
org-log-done 'time
org-log-redeadline 'time
2024-05-14 02:06:00 -07:00
org-log-reschedule 'time
org-preview-latex-default-process 'dvisvgm
2024-10-20 00:44:30 -07:00
org-highlight-latex-and-related '(native entities)
org-startup-with-inline-images t
org-adapt-indentation t
org-hide-leading-stars t
org-html-with-latex 'dvisvgm
2024-05-14 02:06:00 -07:00
org-preview-latex-process-alist
'((dvisvgm
:image-input-type "dvi"
:image-output-type "svg"
:image-size-adjust (1.7 . 1.5)
:latex-compiler ("pdflatex -interaction nonstopmode -output-format=dvi -output-directory=%o %f")
2024-10-20 00:44:30 -07:00
:image-converter ("dvisvgm %o%b.dvi --no-fonts --exact-bbox --scale=%S --output=%O"))))
(defun my/-org-allow-in-derived-mode (oldfun &rest r)
"Allow OLDFUN to run, even if `major-mode' is only derived from `org-mode'.
R is rest of the arguments to OLDFUN."
(let ((major-mode (if (derived-mode-p 'org-mode)
'org-mode
major-mode)))
(apply oldfun r)))
(advice-add 'org-element-at-point :around 'my/-org-allow-in-derived-mode)
(advice-add 'org-table-header-line-mode :around 'my/-org-allow-in-derived-mode))
2023-09-27 04:07:01 -07:00
(use-package evil-org
:after org
2023-09-30 21:41:19 -07:00
:hook (org-mode . evil-org-mode)
2023-09-27 04:07:01 -07:00
:init
(require 'evil-org-agenda)
(evil-org-agenda-set-keys))
2023-11-07 19:36:39 -08:00
;; ledger
(use-package ledger-mode)
(use-package flycheck-ledger
:hook (ledger-mode . flycheck-mode))
2023-09-27 04:07:01 -07:00
;; khard contacts
(require 'khard)
2024-10-16 01:52:45 -07:00
;; This is also in khard (see above), it's just also here so that if I remove
;; that file ever, other things will not break.
(defun my/message-in-header-p (name &optional testfn)
"If in field NAME, return the start of the header, otherwise, return nil.
The name is compared with the field name using TESTFN (defaults to `equal')."
(save-excursion
(when (and (message-point-in-header-p)
(message-beginning-of-header t))
(beginning-of-line)
(when (and (looking-at (rx bol (group (+? any)) ":" (? " ")))
(funcall (or testfn 'equal) (match-string 1) name))
(match-end 0)))))
2023-09-22 02:50:19 -07:00
;; mu4e
(use-package mu4e
:ensure nil
:defer nil
2023-10-19 01:30:50 -07:00
:hook ((mu4e-index-updated . my/-mu4e-enable-index-messages)
2024-01-04 00:14:49 -08:00
(mu4e-main-mode . my/-mu4e-setup-main-mode)
2024-10-16 01:52:45 -07:00
(mu4e-view-mode . my/-mu4e-setup-view-mode)
(mu4e-compose-mode . my/-mu4e-setup-compose-mode))
:bind (("C-x C-m" . mu4e)
:map message-mode-map
("C-c k" . khard-insert-email-contact)
:map mu4e-headers-mode-map
([remap mu4e-headers-mark-for-trash] .
my/mu4e-headers-mark-for-trash)
:map mu4e-view-mode-map
([remap mu4e-view-mark-for-trash] .
my/mu4e-view-mark-for-trash))
:init
(require 'mu4e)
(evil-define-key '(normal motion) mu4e-main-mode-map "q" #'bury-buffer)
2024-03-28 13:29:01 -07:00
(evil-define-key '(normal motion) mu4e-view-mode-map "gy" #'mu4e-view-save-url)
2024-01-04 00:14:49 -08:00
(defun my/-mu4e-setup-view-mode ()
(setq-local global-hl-line-mode nil))
2023-10-19 01:30:50 -07:00
(defun my/-mu4e-setup-main-mode ()
(setq-local default-directory "~/"))
(defun my/-mu4e-enable-index-messages ()
(setq mu4e-hide-index-messages nil))
(defun my/mu4e-update-mail-and-index-silent ()
"Run `mu4e-update-mail-and-index' without any messages in the background."
(setq mu4e-hide-index-messages t)
(mu4e-update-mail-and-index t))
(defun my/mu4e-headers-mark-for-trash ()
"Move the message a point to the trash without marking it was deleted
(trashed)."
(interactive)
(when (mu4e-thread-message-folded-p)
2024-09-13 01:20:27 -07:00
(mu4e-warn "Cannot mark folded messages"))
(mu4e-mark-at-point 'move mu4e-trash-folder)
(when mu4e-headers-advance-after-mark
(mu4e-headers-next)))
(defun my/mu4e-view-mark-for-trash ()
"Like `my/mu4e-headers-mark-for-trash', but for `mu4e-view-mode'."
(interactive)
(mu4e--view-in-headers-context
(my/mu4e-headers-mark-for-trash)))
2024-10-16 01:52:45 -07:00
(defun my/-mu4e-enable-autocomplete-in-header ()
;; corfu auto must be t (not the integer returned by
;; `my/message-in-header-p'
(setq-local corfu-auto (and (not (window-minibuffer-p))
(my/message-in-header-p "To")
t)))
(defun my/-mu4e-setup-compose-mode ()
(add-hook 'post-command-hook 'my/-mu4e-enable-autocomplete-in-header
nil t)
(add-to-list
(make-local-variable 'completion-at-point-functions)
(cape-capf-super #'mu4e-complete-contact #'khard-message-mode-capf)))
(defun my/-mu4e-fix-cycle-threshold ()
(setq-local completion-cycle-threshold nil))
(advice-add 'mu4e--compose-setup-completion :after
'my/-mu4e-fix-cycle-threshold)
(defvar my/mu4e-interesting-mail-query
(concat "flag:unread AND NOT flag:trashed AND NOT "
"maildir:/protonmail/Trash AND NOT maildir:/protonmail/Spam")
"Flag for mail which will appear as \"unread\" and will be notified.")
2024-10-20 00:44:30 -07:00
(setq message-kill-buffer-on-exit t
message-confirm-send t
message-send-mail-function 'sendmail-send-it
mu4e-change-filenames-when-moving t
mu4e-context-policy 'pick-first
2024-09-13 23:48:23 -07:00
mu4e-attachment-dir "~/downloads/"
mu4e-last-update-buffer " *mu4e-last-update*"
mu4e-index-update-error-warning nil
mu4e-get-mail-command "mbsync protonmail"
mu4e-completing-read-function #'completing-read-default
2023-11-17 16:33:53 -08:00
mu4e-compose-context-policy 'ask-if-none
mu4e-contexts
(list (make-mu4e-context
:name "Personal"
:match-func (lambda (msg)
(when msg
(string-match-p "^/protonmail/"
(mu4e-message-field msg
:maildir))))
:vars `((user-mail-address . ,(my/get-private 'mu4e-email))
(user-full-name . ,(my/get-private 'mu4e-name))
(message-signature . nil)
(mu4e-refile-folder . "/protonmail/Archive")
(mu4e-sent-folder . "/protonmail/Sent")
(mu4e-drafts-folder . "/protonmail/Drafts")
(mu4e-trash-folder . "/protonmail/Trash")
(mu4e-bookmarks
. ((:name "Inbox"
:query "maildir:/protonmail/Inbox"
:key ?i)
(:name "Unread"
:query ,my/mu4e-interesting-mail-query
:key ?u))))))))
2023-09-22 02:50:19 -07:00
(use-package mu4e-alert
:after mu4e
:hook (after-init . mu4e-alert-enable-notifications)
2023-09-23 16:48:22 -07:00
:init
2023-11-17 16:33:53 -08:00
(setq mu4e-alert-set-window-urgency nil
mu4e-alert-interesting-mail-query my/mu4e-interesting-mail-query)
2023-09-22 02:50:19 -07:00
:config
(mu4e-alert-set-default-style 'libnotify))
2023-09-27 04:07:01 -07:00
(mu4e t)
(mu4e-context-switch nil "Personal")
2023-09-22 02:50:19 -07:00
2024-10-20 00:44:30 -07:00
;; mu4e compose HTML messages
(use-package org-mime)
(require 'org-mu4e-compose)
(setq mail-user-agent 'org-mu4e-user-agent
org-mime-org-html-with-latex-default 'dvisvgm
org-mime-export-options '(:with-latex dvisvgm :with-footnotes t))
(evil-define-key '(normal visual) org-mu4e-compose-mode-map
"G" #'mu4e-compose-goto-bottom
"gg" #'mu4e-compose-goto-top)
(evil-define-key 'normal org-mu4e-compose-mode-map
"ZZ" #'message-send-and-exit
"ZD" #'message-dont-send
"ZQ" #'message-kill-buffer
"ZF" #'mml-attach-file)
2024-10-21 04:56:01 -07:00
(evil-define-key 'normal mu4e-view-mode-map
"R" 'org-mu4e-compose-reply
"cr" 'org-mu4e-compose-reply)
(evil-define-key 'normal mu4e-headers-mode-map
"R" 'org-mu4e-compose-reply
"cr" 'org-mu4e-compose-reply)
2024-10-20 00:44:30 -07:00
(defun my/-setup-org-mu4e-compose-mode ()
"Setup up stuff in `org-mu4e-compose' buffers."
(setq-local ltex-eglot-variable-save-method 'file)
;; this should come last so it can pick up the above
2024-10-21 17:12:25 -07:00
;; (eglot-ensure)
)
2024-10-20 00:44:30 -07:00
(add-hook 'org-mu4e-compose-mode-hook #'my/-setup-org-mu4e-compose-mode)
;; elfeed
(use-package elfeed
:bind (("C-c d" . elfeed))
:custom
(elfeed-feeds
'(("https://archlinux.org/feeds/news/" linux arch)
("https://9to5linux.com/feed/atom" linux news)))
:config
2024-04-17 02:59:08 -07:00
(setq elfeed-log-buffer-name " *elfeed-log*")
(evil-define-key '(normal motion) elfeed-search-mode-map
2024-05-08 20:26:13 -07:00
"r" #'elfeed-search-fetch)
(elfeed-db-load))
;; helpful
(use-package helpful
2024-01-10 17:19:27 -08:00
:hook ((emacs-lisp-mode . my/-helpful-setup-emacs-lisp-mode)
(helpful-mode . my/-setup-helpful-mode))
:bind (:map help-map
2024-09-13 01:20:27 -07:00
("f" . helpful-callable)
("v" . helpful-variable)
("k" . helpful-key)
("o" . helpful-symbol)
("x" . helpful-command)
("F" . helpful-function)
:map helpful-mode-map
("<mouse-8>" . my/helpful-history-back)
("<mouse-9>" . my/helpful-history-forward)
("<normal-state><" . my/helpful-history-back)
("<normal-state>>" . my/helpful-history-forward))
:init
(defun my/-helpful-setup-emacs-lisp-mode ()
(setq-local evil-lookup-func #'helpful-at-point))
2024-01-10 17:19:27 -08:00
(defun my/-setup-helpful-mode ()
2024-10-20 00:44:30 -07:00
(setq-local evil-lookup-func #'helpful-at-point
tab-width 8))
2024-10-09 07:32:06 -07:00
(defvar my/helpful-symbol-history-size 50
"Max size of `my/helpful-symbol-history'.")
(defvar my/helpful-symbol-history '()
"History of helpful symbols.")
2024-10-09 07:32:06 -07:00
(defvar my/-helpful-inhibit-history nil
"If non-nil, don't add symbols to `my/helpful-symbol-history'.")
(defvar my/-helpful-last-entry nil
"Last entry looked up with helpful.")
(defun my/helpful-history-back (count)
"Go back COUNT symbols in `my/helpful-symbol-history'. If called
interactively, COUNT defaults to 1."
(interactive "p")
(my/helpful-history-forward (- count)))
(defun my/helpful-history-forward (count)
"Move COUNT symbols in `my/helpful-symbol-history'. If COUNT is negative,
move back. If COUNT is larger than the history, go to the newest entry. Go to
the oldest entry if -COUNT is larger than the history."
(interactive "p")
(when helpful--sym
(let* ((hist-len (length my/helpful-symbol-history))
(current-pos (seq-position my/helpful-symbol-history
(cons helpful--sym
helpful--callable-p)
'equal))
(new-pos (- current-pos count)))
(cond
;; if already at the newest element, signal an error
((and (> count 0) (= current-pos 0))
(message "%s" "No newer symbol!"))
;; if already at the oldest element, signal an error
((and (< count 0) (= (1+ current-pos) hist-len))
(message "%s" "No older symbol!"))
(t
2024-10-09 07:32:06 -07:00
(let ((my/-helpful-inhibit-history t)
(entry (cond
((<= new-pos 0)
(seq-first my/helpful-symbol-history))
((>= new-pos hist-len)
(car (last my/helpful-symbol-history)))
(t
(nth new-pos my/helpful-symbol-history)))))
(if (cdr entry)
(helpful-callable (car entry))
(helpful-variable (car entry)))))))))
(defun my/-helpful-switch-buffer-function (helpful-buf)
"Like `pop-to-buffer', but kill previous helpful buffers and save the new
buffers `helpful--sym' to `my/helpful-symbol-history'."
2024-10-09 07:32:06 -07:00
(cl-loop with window = nil
for buf in (buffer-list)
when (and
(not (eq buf helpful-buf))
(eq (buffer-local-value 'major-mode buf) 'helpful-mode))
do
(when-let (cur-window (get-buffer-window buf nil))
(setq window cur-window))
(kill-buffer buf)
finally
2024-10-09 07:32:06 -07:00
(let ((entry (cons (buffer-local-value 'helpful--sym helpful-buf)
(buffer-local-value 'helpful--callable-p
helpful-buf))))
(unless my/-helpful-inhibit-history
(when-let (from-current-hist
(member my/-helpful-last-entry
my/helpful-symbol-history))
(setq my/helpful-symbol-history from-current-hist))
(cl-pushnew entry my/helpful-symbol-history :test 'equal)
(setq my/helpful-symbol-history
2024-10-09 07:32:06 -07:00
(seq-take my/helpful-symbol-history
my/helpful-symbol-history-size)))
(setq my/-helpful-last-entry entry))
(if window
(window--display-buffer helpful-buf window 'reuse)
(pop-to-buffer helpful-buf))))
(setq helpful-switch-buffer-function 'my/-helpful-switch-buffer-function
helpful-max-buffers 2))
2024-09-12 18:01:06 -07:00
(defun my/greyify-color (color percent &optional frame)
"Make COLOR closer to black by PERCENT on FRAME.
Color can be any color which can be passed to `color-values'."
(cl-destructuring-bind (&optional r g b)
(color-name-to-rgb color frame)
(when (and r g b)
(let ((scale (- 1.0 (/ percent 100.0))))
(color-rgb-to-hex (* r scale)
(* g scale)
(* b scale))))))
2024-01-08 21:02:11 -08:00
;; rainbow-delimiters
2023-09-20 00:50:34 -07:00
(use-package rainbow-delimiters
2024-09-12 18:01:06 -07:00
:hook (prog-mode . rainbow-delimiters-mode)
:config
;; generate dark version of the rainbow delimiters faces
(defun my/-rainbow-delimiters-recalc-dark-faces (&optional frame)
(unless frame (setq frame (selected-frame)))
(dotimes (i 9)
(when-let ((old-face (intern-soft
(format "rainbow-delimiters-depth-%d-face"
(1+ i))))
(new-face
(intern
(format "my/rainbow-delimiters-depth-%d-dark-face"
(1+ i))))
(old-color (face-attribute old-face :foreground frame))
(new-color (my/greyify-color old-color 50 frame)))
(set-face-attribute new-face frame :foreground new-color))))
(add-hook 'after-make-frame-functions
#'my/-rainbow-delimiters-recalc-dark-faces)
(add-hook 'server-after-make-frame-hook
#'my/-rainbow-delimiters-recalc-dark-faces)
(defun my/rainbow-delimiters-parinfer-pick-face (depth match loc)
"Version of `rainbow-delimiters-default-pick-face' that colors closing
parenthesis darker than opening ones. This function defers to
`rainbow-delimiters-default-pick-face' and just changes the output if it returns
one of the normal rainbow-delimiters-depth-N-face faces."
(save-match-data
(let* ((base-face (rainbow-delimiters-default-pick-face depth match loc))
(base-name (symbol-name base-face)))
(if (and evil-cleverparens-mode
2024-09-12 18:01:06 -07:00
(eq ?\) (char-syntax
(elt (buffer-substring-no-properties loc (1+ loc)) 0)))
(string-match (rx string-start "rainbow-delimiters-depth-"
(group (+ num))
"-face" string-end)
base-name))
(or (intern-soft (format "my/rainbow-delimiters-depth-%s-dark-face"
(match-string 1 base-name)))
base-face)
base-face))))
(setopt rainbow-delimiters-pick-face-function
'my/rainbow-delimiters-parinfer-pick-face))
2023-09-18 13:05:09 -07:00
2024-01-08 21:02:11 -08:00
;; auto-highlight-symbol
(use-package auto-highlight-symbol
:hook (lisp-data-mode . auto-highlight-symbol-mode)
:init
(setq ahs-face 'bold
ahs-face-unfocused 'bold
2024-01-08 21:32:05 -08:00
ahs-definition-face 'bold
ahs-definition-face-unfocused 'bold
2024-01-08 21:02:11 -08:00
ahs-plugin-default-face 'bold
ahs-plugin-default-face-unfocused 'bold))
2023-09-18 13:05:09 -07:00
;; Theme (doom-themes)
(use-package doom-themes
:config
(load-theme 'doom-molokai t)
(doom-themes-org-config))
;; solaire-mode
(use-package solaire-mode
:config
(solaire-global-mode 1))
2023-09-21 03:20:43 -07:00
2024-05-15 18:54:06 -07:00
;; Highlight todos
(use-package hl-todo
:config
(global-hl-todo-mode 1))
(use-package magit-todos
:after (hl-todo magit)
:config
(magit-todos-mode 1))
2023-09-21 03:20:43 -07:00
;; icons
(use-package nerd-icons)
(use-package nerd-icons-completion
:config
(nerd-icons-completion-mode))
(use-package nerd-icons-dired
:hook (dired-mode . nerd-icons-dired-mode))
(use-package kind-icon
:after corfu
:init
(setq kind-icon-default-face 'corfu-default
kind-icon-default-style
'(:padding -1 :stroke 0 :margin 0 :radius 0 :height 0.5 :scale 1))
:config
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
;; modeline (doom-modeline)
(use-package doom-modeline
:init
(setq doom-modeline-support-imenu t)
(doom-modeline-mode 1))
2023-09-27 04:07:01 -07:00
2023-09-29 23:13:35 -07:00
;; dashboard.el
(use-package dashboard
:config
(dashboard-setup-startup-hook)
(setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))
2024-01-07 02:56:59 -08:00
dashboard-force-refresh t
2023-09-29 23:13:35 -07:00
dashboard-display-icons-p t
dashboard-icon-type 'nerd-icons
dashboard-set-file-icons t
dashboard-projects-backend 'project-el
2023-09-29 23:13:35 -07:00
dashboard-items '((recents . 5)
(projects . 5)
2023-09-29 23:13:35 -07:00
(bookmarks . 5))))
2023-10-24 01:14:38 -07:00
;; page break lines
(use-package page-break-lines
:config
(global-page-break-lines-mode 1)
2024-05-14 18:52:48 -07:00
(add-to-list 'page-break-lines-modes 'prog-mode)
2024-09-13 01:20:27 -07:00
(add-to-list 'page-break-lines-modes 'text-mode)
(add-to-list 'page-break-lines-modes 'helpful-mode))
2023-10-24 01:14:38 -07:00
2024-01-14 05:40:54 -08:00
;; fun!
(use-package mines)
2024-09-12 18:01:06 -07:00
;;; init.el ends here