refactor: Move user config into modules/
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
;;; syd-lang-agda.el -*- lexical-binding: t; -*-
|
||||
|
||||
(with-eval-after-load 'agda2
|
||||
(general-define-key
|
||||
:keymaps 'agda2-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"?" #'agda2-show-goals
|
||||
"." #'agda2-goal-and-context-and-inferred
|
||||
"," #'agda2-goal-and-context
|
||||
"=" #'agda2-show-constraints
|
||||
"SPC" #'agda2-give
|
||||
"a" #'agda2-mimer-maybe-all
|
||||
"b" #'agda2-previous-goal
|
||||
"c" #'agda2-make-case
|
||||
"d" #'agda2-infer-type-maybe-toplevel
|
||||
"e" #'agda2-show-context
|
||||
"f" #'agda2-next-goal
|
||||
"gG" #'agda2-go-back
|
||||
"h" #'agda2-helper-function-type
|
||||
"l" #'agda2-load
|
||||
"n" #'agda2-compute-normalised-maybe-toplevel
|
||||
"p" #'agda2-module-contents-maybe-toplevel
|
||||
"r" #'agda2-refine
|
||||
"s" #'agda2-solveAll
|
||||
"t" #'agda2-goal-type
|
||||
"w" #'agda2-why-in-scope-maybe-toplevel
|
||||
"x c" #'agda2-compile
|
||||
"x d" #'agda2-remove-annotations
|
||||
"x h" #'agda2-display-implicit-arguments
|
||||
"x q" #'agda2-quit
|
||||
"x r" #'agda2-restart)
|
||||
(general-def
|
||||
:keymaps 'agda2-mode-map
|
||||
:states '(motion normal)
|
||||
"[ n" #'agda2-previous-goal
|
||||
"] n" #'agda2-next-goal)
|
||||
(setq agda2-fontset-name "JuliaMono"))
|
||||
|
||||
(provide 'syd-lang-agda)
|
||||
@@ -1,106 +0,0 @@
|
||||
;;; syd-lang-clojure.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package clojure-mode
|
||||
:mode (("\\.\\(clj\\|cljd\\|dtm\\|edn\\|lpy\\)\\'" . clojure-mode)
|
||||
("\\.cljc\\'" . clojurec-mode)
|
||||
("\\.cljs\\'" . clojurescript-mode)
|
||||
("\\(?:build\\|profile\\)\\.boot\\'" . clojure-mode))
|
||||
:interpreter (("bb" . clojure-mode)
|
||||
("nbb" . clojurescript-mode))
|
||||
:config
|
||||
(add-hook 'clojure-mode-hook #'syd-lisp-mode)
|
||||
(dolist (c '(?- ?_ ?? ?! ?+ ?* ?/ ?: ?> ?< ?= ?&))
|
||||
(modify-syntax-entry c "w" clojure-mode-syntax-table)))
|
||||
|
||||
(use-package cider
|
||||
:after clojure-mode)
|
||||
|
||||
(defun syd-clojure-open-repl (&optional arg type)
|
||||
"Open a Cider REPL for clojure and return the buffer."
|
||||
(interactive "P")
|
||||
;; TODO: Better error handling
|
||||
;; type is `clj' for clojure and `cljs' for clojurescript
|
||||
;; ... with no type specified, assume `clj'.
|
||||
(let ((type (or type 'clj)))
|
||||
(if-let* ((buffer (cider-current-repl type)))
|
||||
(pop-to-buffer buffer)
|
||||
(let ((process (cond ((eq type 'clj) (cider-jack-in-clj arg))
|
||||
((eq type 'cljs) (cider-jack-in-cljs arg)))))
|
||||
(message "Starting CIDER server for the first time...")
|
||||
(while (and (process-live-p process)
|
||||
(not (cider-current-repl type)))
|
||||
(sit-for 1))
|
||||
(message "Starting CIDER server for the first time...done")
|
||||
(pop-to-buffer (cider-current-repl type))))))
|
||||
|
||||
(defun syd-clojure-open-cljs-repl (&optional arg)
|
||||
(interactive "P")
|
||||
(syd-clojure-open-repl arg 'cljs))
|
||||
|
||||
(use-package cider-mode
|
||||
:straight nil
|
||||
;; :after clojure-mode
|
||||
:hook (clojure-mode-local-vars . cider-mode)
|
||||
:init
|
||||
(with-eval-after-load 'clojure-mode
|
||||
(set-repl-handler! '(clojure-mode clojurec-mode)
|
||||
#'syd-clojure-open-repl :persist t)
|
||||
(set-repl-handler! 'clojurescript-mode
|
||||
#'syd-clojure-open-cljs-repl :persist t)
|
||||
(set-eval-handler! '(clojure-mode clojurec-mode clojurescript-mode)
|
||||
#'cider-eval-region))
|
||||
:custom ((cider-show-error-buffer nil))
|
||||
:general
|
||||
;; DEPRECATED: Remove once a `map!' equivalent is implemented.
|
||||
(:keymaps 'cider-repl-mode-map
|
||||
:states '(normal insert)
|
||||
"C-k" #'cider-repl-backward-input
|
||||
"C-j" #'cider-repl-forward-input
|
||||
"C-s" #'cider-repl-previous-matching-input)
|
||||
;; DEPRECATED: Remove once a `map!' equivalent is implemented.
|
||||
(:keymaps 'clojure-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"\"" #'cider-jack-in-cljs
|
||||
"'" #'cider-jack-in-clj
|
||||
"c" #'cider-connect-clj
|
||||
"C" #'cider-connect-cljs
|
||||
"r l" #'cider-load-buffer
|
||||
"r n" #'cider-repl-set-ns
|
||||
"r r" #'cider-ns-refresh
|
||||
"r R" #'cider-restart
|
||||
"r q" #'cider-quit
|
||||
"h c" #'cider-cheatsheet)
|
||||
:config
|
||||
(add-hook 'cider-mode-hook #'eldoc-mode)
|
||||
(add-hook 'cider-repl-mode-hook #'syd-lisp-mode)
|
||||
(set-popup-rules!
|
||||
`(("^\\*cider-error\\*" :ignore t)
|
||||
("^\\*cider-repl" :quit nil :ttl nil)
|
||||
("^\\*cider-repl-history" :vslot 2 :ttl nil)
|
||||
(,(rx bol "*cider-nrepl-middleware") :slot 3 :quit t :ttl 0)
|
||||
(,(rx bol "*cider-cheatsheet*")
|
||||
:width ,(lambda (win)
|
||||
(with-selected-window win
|
||||
(enlarge-window (- (min 45 (* 0.2 (frame-width)))
|
||||
(window-width))
|
||||
t)))
|
||||
:side right :vslot -8 :quit t :select t)
|
||||
(,(rx bol "*cider-doc*")
|
||||
:slot 2 :vslot -8 :quit t :select t)))
|
||||
;; DEPRECATED: Remove once syd-strategies is working.
|
||||
(syd-add-hook 'clojure-mode-hook
|
||||
(defun syd-clojure-set-handlers-h ()
|
||||
(setq-local syd-lookup-documentation-handlers
|
||||
(list #'cider-doc))))
|
||||
|
||||
;; Correctly indent some common macros.
|
||||
(put-clojure-indent 'match 1))
|
||||
|
||||
;; Give different pairs of delimiters different colours.
|
||||
(use-package rainbow-delimiters
|
||||
:hook (clojure-mode . rainbow-delimiters-mode))
|
||||
|
||||
(provide 'syd-lang-clojure)
|
||||
@@ -1,105 +0,0 @@
|
||||
;;; emacs-lisp.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-handle-repl)
|
||||
(require 'syd-handle-lookup)
|
||||
(require 'syd-handle-eval)
|
||||
(require 'syd-lisp-lib)
|
||||
;; (require 'handle)
|
||||
|
||||
;; Don't `use-package' `ielm', since it's loaded by Emacs. You'll get weird
|
||||
;; autoload errors if you do.
|
||||
;; https://www.reddit.com/r/emacs/comments/q7fjbi/comment/lml127d
|
||||
(use-package emacs
|
||||
:custom ((ielm-history-file-name ; Stay out of my config dir!
|
||||
(file-name-concat syd-cache-dir "ielm-history.eld"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd/open-emacs-lisp-repl ()
|
||||
(interactive)
|
||||
(pop-to-buffer
|
||||
(or (get-buffer "*ielm*")
|
||||
(progn (ielm) ; Creates the *ielm* buffer.
|
||||
(let ((b (get-buffer "*ielm*")))
|
||||
;; We leave it to the enclosing `pop-to-buffer' to display the
|
||||
;; buffer.
|
||||
(bury-buffer b)
|
||||
b)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-emacs-lisp-lookup-documentation (identifier)
|
||||
"Lookup IDENTIFIER with `describe-symbol'"
|
||||
;; HACK: Much to my frustration, `describe-symbol' has no defined return
|
||||
;; value. To test if the call was successful or not, we check if any window
|
||||
;; is displaying the help buffer. This breaks if
|
||||
;; `syd-emacs-lisp-lookup-documentation' is called while the help buffer is
|
||||
;; already open.
|
||||
(describe-symbol (intern identifier))
|
||||
(let ((buffer (get-buffer (help-buffer))))
|
||||
(and (get-buffer-window-list buffer)
|
||||
buffer)))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-emacs-lisp-eval (beg end)
|
||||
"Evaluate a region and print it to the echo area (if one line long), otherwise
|
||||
to a pop up buffer."
|
||||
(syd-eval-display-results
|
||||
(string-trim-right
|
||||
(let ((buffer (generate-new-buffer " *eval-output*"))
|
||||
(debug-on-error t))
|
||||
(unwind-protect
|
||||
(condition-case-unless-debug e
|
||||
(progn (eval-region beg end buffer load-read-function)
|
||||
(with-current-buffer buffer
|
||||
(let ((pp-max-width nil))
|
||||
(require 'pp)
|
||||
(pp-buffer)
|
||||
(replace-regexp-in-string
|
||||
"\\\\n" "\n" (string-trim-left (buffer-string))))))
|
||||
(error (format "ERROR: %s" e)))
|
||||
(kill-buffer buffer))))
|
||||
:source-buffer (current-buffer)
|
||||
:force-popup current-prefix-arg))
|
||||
|
||||
(dolist (m '(emacs-lisp-mode lisp-data-mode))
|
||||
(set-repl-handler! 'emacs-lisp-mode
|
||||
#'syd/open-emacs-lisp-repl)
|
||||
(set-eval-handler! 'emacs-lisp-mode
|
||||
#'syd-emacs-lisp-eval))
|
||||
|
||||
(syd-add-hook '(emacs-lisp-mode-hook lisp-data-mode)
|
||||
#'syd-lisp-mode)
|
||||
|
||||
;; DEPRECATED: Remove once syd-strategies is working.
|
||||
(syd-add-hook '(emacs-lisp-mode-hook help-mode-hook lisp-data-mode)
|
||||
(defun syd-emacs-set-handlers-h ()
|
||||
(setq-local syd-lookup-documentation-handlers
|
||||
(list #'syd-emacs-lisp-lookup-documentation))))
|
||||
|
||||
;; Semantic highlighting for Elisp.
|
||||
(use-package highlight-defined
|
||||
:hook (emacs-lisp-mode-hook . highlight-defined-mode))
|
||||
|
||||
;; Automatically and inteligently expand abbreviations. E.g. `wcb` will be
|
||||
;; expanded to `(with-current-buffer)`, but only where it makes sense for a
|
||||
;; function/macro call to be.
|
||||
(use-package sotlisp
|
||||
:straight (:host github
|
||||
:repo "Malabarba/speed-of-thought-lisp")
|
||||
:hook (emacs-lisp-mode . speed-of-thought-mode))
|
||||
|
||||
;; Give different pairs of delimiters different colours.
|
||||
(use-package rainbow-delimiters
|
||||
:hook (emacs-lisp-mode . rainbow-delimiters-mode))
|
||||
|
||||
(use-package macrostep
|
||||
:commands (macrostep-expand)
|
||||
:init
|
||||
(general-define-key
|
||||
:keymaps 'emacs-lisp-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"m" #'macrostep-expand))
|
||||
|
||||
(provide 'syd-lang-emacs-lisp)
|
||||
@@ -1,73 +0,0 @@
|
||||
;;; syd-lang-haskell.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-handle-repl)
|
||||
(require 'syd-handle-lookup)
|
||||
|
||||
(defun syd-haskell-open-repl ()
|
||||
"Open a Haskell REPL."
|
||||
(interactive)
|
||||
(require 'inf-haskell)
|
||||
(run-haskell))
|
||||
|
||||
(defun syd-haskell-evil-open-above ()
|
||||
"Opens a line above the current, following Haskell-mode's indentation"
|
||||
(interactive)
|
||||
(evil-beginning-of-line)
|
||||
(haskell-indentation-newline-and-indent)
|
||||
(evil-previous-line)
|
||||
(haskell-indentation-indent-line)
|
||||
(evil-append-line nil))
|
||||
|
||||
(defun syd-haskell-evil-open-below ()
|
||||
"Opens a line below the current, following Haskell-mode's indentation"
|
||||
(interactive)
|
||||
(evil-append-line nil)
|
||||
(haskell-indentation-newline-and-indent))
|
||||
|
||||
(use-package haskell-mode
|
||||
:mode (("\\.l?hs'" . haskell-literate-mode)
|
||||
("\\.hs'" . haskell-mode))
|
||||
:custom (; Show errors in REPL, not popup buffers.
|
||||
(haskell-interactive-popup-errors nil)
|
||||
(haskell-process-suggest-remove-import-line t)
|
||||
(haskell-process-auto-import-loaded-modules t))
|
||||
:general
|
||||
;; DEPRECATED: Remove once a `map!' equivalent is implemented.
|
||||
(:keymaps 'haskell-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"c" #'haskell-cabal-visit-file
|
||||
"h s" #'haskell-hoogle-start-server
|
||||
"h q" #'haskell-hoogle-kill-server)
|
||||
(:keymaps 'interactive-haskell-mode-map
|
||||
:states '(normal insert)
|
||||
"C-j" #'haskell-interactive-mode-history-next
|
||||
"C-k" #'haskell-interactive-mode-history-previous)
|
||||
(:keymaps 'haskell-mode-map
|
||||
:states 'normal
|
||||
[remap evil-open-above] #'syd-haskell-evil-open-above
|
||||
[remap evil-open-below] #'syd-haskell-evil-open-below)
|
||||
:config
|
||||
(set-repl-handler! '(haskell-mode haskell-cabal-mode literate-haskell-mode)
|
||||
#'syd-haskell-open-repl
|
||||
;; Haskell-mode provides IDE features by communicating with a persistent
|
||||
;; REPL process à la Lisp.
|
||||
:persist t)
|
||||
(add-to-list 'completion-ignored-extensions ".hi")
|
||||
|
||||
;; Don't kill REPL popup on ESC/C-g
|
||||
(set-popup-rule! "^\\*haskell\\*" :quit nil)
|
||||
(syd-add-hook 'haskell-mode-local-vars-hook
|
||||
;; Folding of Haskell sections.
|
||||
#'haskell-collapse-mode
|
||||
#'interactive-haskell-mode))
|
||||
|
||||
(use-package lsp-haskell
|
||||
:defer t
|
||||
:init
|
||||
(add-hook 'haskell-mode-local-vars-hook #'lsp 'append)
|
||||
(add-hook 'haskell-literate-mode-local-vars-hook #'lsp 'append))
|
||||
|
||||
(provide 'syd-lang-haskell)
|
||||
@@ -1,40 +0,0 @@
|
||||
;;; syd-lang-nix.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-handle-repl)
|
||||
(require 'syd-handle-lookup)
|
||||
|
||||
(defun syd-nix-open-nix-repl ()
|
||||
(interactive)
|
||||
;; If possible, cd to the project root. Flakes force you to use relative
|
||||
;; paths, which can be annoying in combination with
|
||||
;;
|
||||
;; REVIEW: Should this be something handled by `syd--call-repl-handler'?
|
||||
(-some-> (syd-project-root) cd)
|
||||
(nix-repl)
|
||||
(current-buffer))
|
||||
|
||||
(use-package nix-mode
|
||||
:mode "\\.nix\\'"
|
||||
:init
|
||||
(add-to-list 'auto-mode-alist
|
||||
(cons (rx "/flake.lock'")
|
||||
(if (fboundp 'json-mode)
|
||||
'json-mode
|
||||
'js-mode)))
|
||||
:config
|
||||
(add-hook 'nix-mode-hook #'lsp)
|
||||
(set-popup-rule! (rx bol "*nixos-options-doc*" eol) :ttl 0 :quit t)
|
||||
(set-repl-handler! 'nix-mode #'syd-nix-open-nix-repl)
|
||||
(dolist (c '(?- ?_))
|
||||
(modify-syntax-entry c "w" nix-mode-syntax-table))
|
||||
|
||||
;; Inform Smartparens and Evil-surround of Nix's alternative string syntax.
|
||||
(with-eval-after-load 'smartparens
|
||||
(sp-local-pair 'nix-mode "''" "''"))
|
||||
(syd-add-hook 'nix-mode-hook
|
||||
(defun syd-nix--configure-evil-surround-h ()
|
||||
(with-eval-after-load 'evil-surround
|
||||
(push '(?Q . ("''" . "''"))
|
||||
evil-surround-pairs-alist)))))
|
||||
|
||||
(provide 'syd-lang-nix)
|
||||
@@ -1,6 +0,0 @@
|
||||
;;; syd-lang-sql.el -*- lexical-binding: t; -*-
|
||||
|
||||
(with-eval-after-load 'sql
|
||||
(add-hook 'sql-interactive-mode-hook #'syd-repl-mode))
|
||||
|
||||
(provide 'syd-lang-sql)
|
||||
@@ -1,11 +0,0 @@
|
||||
;;; syd-age.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package age
|
||||
:hook (on-first-file . age-file-enable)
|
||||
:custom
|
||||
;; We use rage over age, as the former supports pinentry.
|
||||
((age-program "rage")
|
||||
(age-default-identity (expand-file-name "~/private-keys/age/crumb.age"))
|
||||
(age-default-recipient (expand-file-name "~/public-keys/age/crumb.pub"))))
|
||||
|
||||
(provide 'syd-age)
|
||||
@@ -1,79 +0,0 @@
|
||||
;;; syd-autosave.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-prelude)
|
||||
|
||||
(setq backup-directory-alist
|
||||
`(("." . ,(file-name-concat syd-data-dir "backup")))
|
||||
auto-save-list-file-prefix (let ((dir (file-name-concat syd-cache-dir
|
||||
"autosave/")))
|
||||
(make-directory dir t)
|
||||
dir)
|
||||
;; Nil means untracked files under VC won't get backed up.
|
||||
vc-make-backup-files t
|
||||
;; Nil will clobber symlinks.
|
||||
backup-by-copying t
|
||||
;; Use versioned backups.
|
||||
version-control t
|
||||
;; Don't create ugly lockfiles. See
|
||||
;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Interlocking.html#Interlocking
|
||||
;; This is a good feature, but not very relevant to a single-user system.
|
||||
create-lockfiles nil
|
||||
auto-save-file-name-transforms
|
||||
;; Good grief, girl...
|
||||
`(("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'"
|
||||
,(concat auto-save-list-file-prefix "tramp-\\2") t)
|
||||
(".*"
|
||||
,(file-name-concat syd-cache-dir "autosave") t))
|
||||
kept-new-versions 5
|
||||
delete-old-versions t)
|
||||
|
||||
;; Save your cursor position in recently-opened files.
|
||||
(use-package saveplace
|
||||
:hook (on-first-file-hook . save-place-mode)
|
||||
:custom (save-place-file (file-name-concat syd-cache-dir "places")))
|
||||
|
||||
;; Keep track of recently-visited files.
|
||||
(use-package recentf
|
||||
:hook ((on-first-file-hook . recentf-mode)
|
||||
(find-file-hook . recentf-save-list))
|
||||
:custom (recentf-save-file (file-name-concat syd-data-dir "recentf")))
|
||||
|
||||
(use-package savehist
|
||||
:defer-incrementally custom
|
||||
:hook (on-first-input-hook . savehist-mode)
|
||||
:custom (savehist-file (file-name-concat syd-cache-dir "savehist"))
|
||||
:config
|
||||
(setq savehist-save-minibuffer-history t
|
||||
savehist-autosave-interval nil ; save on kill only
|
||||
savehist-additional-variables
|
||||
'(kill-ring ; persist clipboard
|
||||
register-alist ; persist macros
|
||||
mark-ring global-mark-ring ; persist marks
|
||||
search-ring regexp-search-ring)) ; persist searches
|
||||
(syd-add-hook 'savehist-save-hook
|
||||
(defun syd--savehist-unpropertize-variables-h ()
|
||||
"Remove text properties from `kill-ring' to reduce savehist cache size."
|
||||
(setq kill-ring
|
||||
(mapcar #'substring-no-properties
|
||||
(cl-remove-if-not #'stringp kill-ring))
|
||||
register-alist
|
||||
(cl-loop for (reg . item) in register-alist
|
||||
if (stringp item)
|
||||
collect (cons reg (substring-no-properties item))
|
||||
else collect (cons reg item))))
|
||||
(defun syd--savehist-remove-unprintable-registers-h ()
|
||||
"Remove unwriteable registers (e.g. containing window configurations).
|
||||
Otherwise, `savehist' would discard `register-alist' entirely if we don't omit
|
||||
the unwritable tidbits."
|
||||
;; Save new value in the temp buffer savehist is running
|
||||
;; `savehist-save-hook' in. We don't want to actually remove the
|
||||
;; unserializable registers in the current session!
|
||||
(setq-local register-alist
|
||||
(cl-remove-if-not #'savehist-printable register-alist)))))
|
||||
|
||||
(with-eval-after-load 'bookmark
|
||||
;; Stay out of my config dir!
|
||||
(setq bookmark-default-file (file-name-concat syd-data-dir "bookmarks")))
|
||||
|
||||
|
||||
(provide 'syd-autosave)
|
||||
@@ -1,154 +0,0 @@
|
||||
;;; syd-completion.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package emacs
|
||||
:custom
|
||||
;; Allow the opening of new minibuffers from inside existing minibuffers.
|
||||
((enable-recursive-minibuffers t)
|
||||
;; Hide commands in M-x which do not work in the current mode.
|
||||
(read-extended-command-predicate #'command-completion-default-include-p))
|
||||
:config
|
||||
;; Disable blinking cursor. Aesthetically, I personally don't fancy it;
|
||||
;; technically, it doesn't play well with `evil-terminal-cursor-changer'.
|
||||
(blink-cursor-mode -1))
|
||||
|
||||
;; Consult adds various search and navigation tools using Emacs' completing-read
|
||||
;; function; i.e., in our case, Vertico.
|
||||
(use-package consult
|
||||
:defer t
|
||||
:config
|
||||
(advice-add #'consult-recent-file
|
||||
:before #'syd-enable-recentf-mode-a))
|
||||
|
||||
(use-package embark-consult
|
||||
:after (embark consult))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-vertico-embark-preview ()
|
||||
"Previews candidate in vertico buffer, unless it's a consult command"
|
||||
(interactive)
|
||||
(unless (bound-and-true-p consult--preview-function)
|
||||
(if (fboundp 'embark-dwim)
|
||||
(save-selected-window
|
||||
(let (embark-quit-after-action)
|
||||
(embark-dwim)))
|
||||
(user-error "Embark not installed, aborting..."))))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-enable-recentf-mode-a ()
|
||||
"Used as :before advice for `consult-recent-file' to ensure recentf mode is
|
||||
enabled."
|
||||
;; REVIEW: Shall we take any extra precautions to only enable `recentf-mode'
|
||||
;; if it was going to be enabled anyway?
|
||||
(recentf-mode 1))
|
||||
|
||||
;; Vertico is a simple completion engine that replaces Emacs' built-in
|
||||
;; completion engine, achieving Just Works™ compatibility. This is in contrast
|
||||
;; to e.g. Helm and Ivy, which spawn ecosystems orthogonal to Emacs, and
|
||||
;; diametrically-opposed to each other.
|
||||
(use-package vertico
|
||||
:hook (on-first-input . vertico-mode)
|
||||
:general
|
||||
(:keymaps 'vertico-map
|
||||
"DEL" #'vertico-directory-delete-char
|
||||
"C-SPC" #'syd-vertico-embark-preview
|
||||
"C-j" #'vertico-next
|
||||
"C-k" #'vertico-previous
|
||||
"C-M-j" #'vertico-next-group
|
||||
"C-M-k" #'vertico-previous-group)
|
||||
(:keymaps 'vertico-map
|
||||
:states 'normal
|
||||
"j" #'vertico-next
|
||||
"k" #'vertico-previous
|
||||
"RET" #'vertico-exit)
|
||||
:custom ((vertico-resize nil)
|
||||
(vertico-count 17)
|
||||
(vertico-cycle t))
|
||||
:config
|
||||
(setq-default completion-in-region-function #'consult-completion-in-region)
|
||||
;; Cleans up path when moving directories with shadowed paths syntax, e.g.
|
||||
;; cleans ~/foo/bar/// to /, and ~/foo/bar/~/ to ~/.
|
||||
(add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy))
|
||||
|
||||
(defun syd-vertico-orderless-dispatch (pattern _index _total)
|
||||
"Like `orderless-affix-dispatch', but allows affixes to be escaped.
|
||||
|
||||
Shamelessly stolen from Doom. }:3"
|
||||
(let ((len (length pattern))
|
||||
(alist orderless-affix-dispatch-alist))
|
||||
(when (> len 0)
|
||||
(cond
|
||||
;; Ignore single dispatcher character
|
||||
((and (= len 1) (alist-get (aref pattern 0) alist)) #'ignore)
|
||||
;; Prefix
|
||||
((when-let ((style (alist-get (aref pattern 0) alist))
|
||||
((not (char-equal (aref pattern (max (1- len) 1)) ?\\))))
|
||||
(cons style (substring pattern 1))))
|
||||
;; Suffix
|
||||
((when-let ((style (alist-get (aref pattern (1- len)) alist))
|
||||
((not (char-equal (aref pattern (max 0 (- len 2))) ?\\))))
|
||||
(cons style (substring pattern 0 -1))))))))
|
||||
|
||||
;; Orderless provides a completion style that divides the pattern into
|
||||
;; space-separated components, and matches candidates that match all of the
|
||||
;; components in any order. Each component can match in any one of several
|
||||
;; ways: literally, as a regexp, as an initialism, in the flex style, or as
|
||||
;; multiple word prefixes. By default, regexp and literal matches are enabled.
|
||||
(use-package orderless
|
||||
:after vertico
|
||||
:custom ((completion-styles '(orderless basic))
|
||||
(completion-category-overrides
|
||||
'((file
|
||||
(styles ;basic-remote
|
||||
orderless partial-completion))))
|
||||
(orderless-style-dispatchers '(syd-vertico-orderless-dispatch))
|
||||
;; TODO: See Doom's `+vertico-orderless-dispatch'.
|
||||
(orderless-affix-dispatch-alist
|
||||
'((?! . orderless-without-literal)
|
||||
(?& . orderless-annotation)
|
||||
;; %1 -> {1, ₁, ꘡, ⒈, ...}
|
||||
(?% . char-fold-to-regexp)
|
||||
;; ,wcb -> {with-current-buffer, widget-convert-button, ...}
|
||||
(?, . orderless-initialism)
|
||||
(?= . orderless-literal)
|
||||
(?^ . orderless-literal-prefix)
|
||||
(?~ . orderless-flex)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun embark-which-key-indicator ()
|
||||
"An embark indicator that displays keymaps using which-key. The which-key
|
||||
help message will show the type and value of the current target followed by an
|
||||
ellipsis if there are further targets."
|
||||
(lambda (&optional keymap targets prefix)
|
||||
(if (null keymap)
|
||||
(which-key--hide-popup-ignore-command)
|
||||
(which-key--show-keymap
|
||||
(if (eq (plist-get (car targets) :type) 'embark-become)
|
||||
"Become"
|
||||
(format "Act on %s '%s'%s"
|
||||
(plist-get (car targets) :type)
|
||||
(embark--truncate-target (plist-get (car targets) :target))
|
||||
(if (cdr targets) "…" "")))
|
||||
(if prefix
|
||||
(pcase (lookup-key keymap prefix 'accept-default)
|
||||
((and (pred keymapp) km) km)
|
||||
(_ (key-binding prefix 'accept-default)))
|
||||
keymap)
|
||||
nil nil t (lambda (binding)
|
||||
(not (string-suffix-p "-argument" (cdr binding))))))))
|
||||
|
||||
;; TODO: Mark the Embark export buffer as a popup.
|
||||
(use-package embark
|
||||
:after vertico
|
||||
:defer t
|
||||
:custom ((which-key-use-C-h-commands nil)
|
||||
(prefix-help-command #'embark-prefix-help-command)
|
||||
;; Embark uses their own custom interface that is essentially
|
||||
;; equivalent to which-key; just use which-key. }:)
|
||||
(embark-indicators '(embark-which-key-indicator)))
|
||||
:general
|
||||
(:keymaps 'minibuffer-local-map
|
||||
"C-;" `("Actions" . ,#'embark-act))
|
||||
(:keymaps 'syd-leader-map
|
||||
"a" `("Actions" . ,#'embark-act)))
|
||||
|
||||
(provide 'syd-completion)
|
||||
@@ -1,14 +0,0 @@
|
||||
;;; syd-custom.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; To discourage use of the custom file, we store it somewhere will
|
||||
;; Impermanence will wipe it.
|
||||
(use-package emacs
|
||||
;; TODO: I'd like to allow /some/ custom variables. E.g., the trusted
|
||||
;; dir-locals files. See `hack-dir-local-variables'. It has some hooks that
|
||||
;; should make this accomplishable.
|
||||
:custom (custom-file (file-name-concat syd-data-dir "custom.el"))
|
||||
:config
|
||||
(when (file-readable-p custom-file)
|
||||
(load custom-file)))
|
||||
|
||||
(provide 'syd-custom)
|
||||
@@ -1,73 +0,0 @@
|
||||
;;; syd-dired.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun syd-dired-here ()
|
||||
(interactive)
|
||||
(dired default-directory))
|
||||
|
||||
(use-package dired
|
||||
;; Built-in to Emacs.
|
||||
:straight nil
|
||||
:general
|
||||
(:keymaps 'syd-leader-open-map
|
||||
"-" #'syd-dired-here)
|
||||
(:keymaps 'syd-leader-project-map
|
||||
"-" #'project-dired)
|
||||
(:keymaps 'dired-mode-map
|
||||
:states '(normal motion)
|
||||
"g r" #'revert-buffer)
|
||||
:commands dired-jump
|
||||
:custom (;; When there are other Dired windows open, suggest them as targets
|
||||
;; for renaming/copying.
|
||||
(dired-dwim-target t)
|
||||
;; Don't prompt to revert, just do it.
|
||||
(dired-auto-revert-buffer #'dired-buffer-stale-p)
|
||||
(dired-listing-switches
|
||||
(mapconcat
|
||||
#'identity
|
||||
'("-l" ; Mandatory!
|
||||
"--almost-all" ; Show hidden files; omit '.' and '..'.
|
||||
"--human-readable" ; Display sizes in human-readable units.
|
||||
"--time-style=+") ; Omit times/dates.
|
||||
" "))
|
||||
;; Always copy recursively
|
||||
(dired-recursive-copies 'always)
|
||||
;; Prompt for confirmation for each top-level directory being
|
||||
;; deleted.
|
||||
(dired-recursive-deletes 'top)
|
||||
(dired-create-destination-dirs 'ask)
|
||||
(dired-create-destination-dirs-on-trailing-dirsep t)
|
||||
;; Where to store image caches
|
||||
(image-dired-dir (concat syd-cache-dir "image-dired/"))
|
||||
(image-dired-db-file (concat image-dired-dir "db.el"))
|
||||
(image-dired-gallery-dir (concat image-dired-dir "gallery/"))
|
||||
(image-dired-temp-image-file (concat image-dired-dir "temp-image"))
|
||||
(image-dired-temp-rotate-image-file (concat image-dired-dir "temp-rotate-image"))
|
||||
;; Increase thumbnail sizes.
|
||||
(image-dired-thumb-size 150))
|
||||
:config
|
||||
(set-popup-rule! "^\\*image-dired"
|
||||
:slot 20 :size 0.8 :select t :quit nil :ttl 0)
|
||||
|
||||
;; On ESC, abort `wdired-mode' (will prompt)
|
||||
(syd-add-hook 'syd-escape-hook
|
||||
(defun syd-dired--wdired-exit-h ()
|
||||
(when (eq major-mode 'wdired-mode)
|
||||
(wdired-exit)
|
||||
t))))
|
||||
|
||||
(use-package diredfl
|
||||
:hook ((dired-mode . diredfl-mode)
|
||||
(dirvish-directory-view-mode . diredfl-mode)))
|
||||
|
||||
(use-package dirvish
|
||||
:after dired
|
||||
:custom ((dirvish-cache-dir (file-name-concat syd-cache-dir "dirvish/"))
|
||||
(dirvish-reuse-session 'open)
|
||||
(dirvish-default-layout '(0 0.4 0.6))
|
||||
(dirvish-hide-details '(dirvish dirvish-fd dirvish-side)))
|
||||
:config
|
||||
;; Fix random void-variable errors.
|
||||
(require 'autorevert)
|
||||
(dirvish-override-dired-mode 1))
|
||||
|
||||
(provide 'syd-dired)
|
||||
@@ -1,14 +0,0 @@
|
||||
;;; syd-display-startup-time.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun syd-display-startup-time ()
|
||||
(message "Emacs loaded in %s with %d garbage collections."
|
||||
(format "%.3f seconds"
|
||||
(float-time
|
||||
(time-subtract after-init-time before-init-time)))
|
||||
gcs-done))
|
||||
|
||||
(use-package emacs
|
||||
:hook
|
||||
(emacs-startup-hook . syd-display-startup-time))
|
||||
|
||||
(provide 'syd-display-startup-time)
|
||||
@@ -1,19 +0,0 @@
|
||||
;;; syd-ediff.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-prelude)
|
||||
|
||||
(with-eval-after-load 'ediff
|
||||
(setq ediff-diff-options "-w" ; Ignore whitespace
|
||||
ediff-window-setup-function #'ediff-setup-windows-plain)
|
||||
(defvar syd--ediff-saved-wconf nil)
|
||||
|
||||
;; Restore window config after quitting Ediff.
|
||||
(syd-add-hook 'ediff-before-setup-hook
|
||||
(defun syd--ediff-save-wconf-h ()
|
||||
(setq syd--ediff-saved-wconf (current-window-configuration))))
|
||||
(syd-add-hook '(ediff-quit-hook ediff-suspend-hook)
|
||||
(defun syd--ediff-restore-wconf-h ()
|
||||
(when (window-configuration-p syd--ediff-saved-wconf)
|
||||
(set-window-configuration syd--ediff-saved-wconf)))))
|
||||
|
||||
(provide 'syd-ediff)
|
||||
@@ -1,11 +0,0 @@
|
||||
;;; syd-editing.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package emacs
|
||||
:hook ((on-init-ui-hook . whitespace-mode))
|
||||
:custom ((fill-column 80)
|
||||
(indent-tabs-mode nil)
|
||||
(whitespace-style '(face tabs tab-mark))
|
||||
;; Disable synchronization between the kill ring and clipboard.
|
||||
(select-enable-clipboard nil)))
|
||||
|
||||
(provide 'syd-editing)
|
||||
@@ -1,206 +0,0 @@
|
||||
;;; syd-eshell.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'ring)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defvar eshell-buffer-name "*eshell*")
|
||||
|
||||
(defvar syd-eshell-buffers (make-ring 25)
|
||||
"List of open eshell buffers.")
|
||||
|
||||
(defun syd-eshell-buffers ()
|
||||
"TODO"
|
||||
(ring-elements syd-eshell-buffers))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-eshell-run-command (command &optional buffer)
|
||||
"TODO"
|
||||
(let ((buffer
|
||||
(or buffer
|
||||
(if (eq major-mode 'eshell-mode)
|
||||
(current-buffer)
|
||||
(cl-find-if #'buffer-live-p (syd-eshell-buffers))))))
|
||||
(unless buffer
|
||||
(user-error "No living eshell buffers available"))
|
||||
(unless (buffer-live-p buffer)
|
||||
(user-error "Cannot operate on a dead buffer"))
|
||||
(with-current-buffer buffer
|
||||
(goto-char eshell-last-output-end)
|
||||
(goto-char (line-end-position))
|
||||
(insert command)
|
||||
(eshell-send-input nil t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-eshell/toggle (arg &optional command)
|
||||
"Toggle eshell popup window."
|
||||
(interactive "P")
|
||||
(let ((eshell-buffer
|
||||
(get-buffer-create
|
||||
(format "*eshell-popup:%s*"
|
||||
(if (bound-and-true-p persp-mode)
|
||||
(safe-persp-name (get-current-persp))
|
||||
"main"))))
|
||||
confirm-kill-processes
|
||||
current-prefix-arg)
|
||||
(when arg
|
||||
(when-let* ((win (get-buffer-window eshell-buffer)))
|
||||
(delete-window win))
|
||||
(when (buffer-live-p eshell-buffer)
|
||||
(with-current-buffer eshell-buffer
|
||||
(fundamental-mode)
|
||||
(erase-buffer))))
|
||||
(if-let* ((win (get-buffer-window eshell-buffer)))
|
||||
(let (confirm-kill-processes)
|
||||
(delete-window win)
|
||||
(ignore-errors (kill-buffer eshell-buffer)))
|
||||
(with-current-buffer eshell-buffer
|
||||
(syd-mark-buffer-as-real)
|
||||
(if (eq major-mode 'eshell-mode)
|
||||
(run-hooks 'eshell-mode-hook)
|
||||
(eshell-mode))
|
||||
(when command
|
||||
(syd-eshell-run-command command eshell-buffer)))
|
||||
(pop-to-buffer eshell-buffer)
|
||||
(when (bound-and-true-p evil-mode)
|
||||
(call-interactively #'evil-append-line)))))
|
||||
|
||||
(defun syd-eshell-adapt-bash-aliases ()
|
||||
"Very sloppily convert aliases defined in Bash to an Eshell alias file."
|
||||
(interactive)
|
||||
(save-window-excursion
|
||||
(let ((err-buf (generate-new-buffer "*adapt-bash-aliases-err*"))
|
||||
(result-buf (generate-new-buffer "*adapted-bash-aliases*")))
|
||||
(with-current-buffer result-buf
|
||||
(insert "# Automatically generated by syd-eshell-adapt-bash-aliases\n"))
|
||||
(with-temp-buffer
|
||||
;; Aliases are only loaded when bash is in interactive mode.
|
||||
(shell-command "bash -ic alias" (current-buffer) err-buf)
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward
|
||||
(rx bol "alias " (group (+ alphanumeric)) "='"
|
||||
(group (* (not ?\'))) "'")
|
||||
nil t)
|
||||
(let ((eshell-alias (format "alias %s %s $*\n"
|
||||
(match-string 1)
|
||||
(match-string 2))))
|
||||
(with-current-buffer result-buf
|
||||
(insert eshell-alias)))))
|
||||
(unless (= 0 (buffer-size err-buf))
|
||||
(message "Some errors occured whilst fetching Bash's aliases:")
|
||||
(message (with-current-buffer err-buf (buffer-string))))
|
||||
(kill-buffer err-buf)
|
||||
result-buf)))
|
||||
|
||||
(defun syd-eshell-C-d ()
|
||||
"Imitate the typical 'C-d' behaviour in other shells. Quits Eshell when the input is empty."
|
||||
(interactive)
|
||||
(when (and (eolp) (looking-back eshell-prompt-regexp nil))
|
||||
(eshell-life-is-too-much)))
|
||||
|
||||
(defun syd-eshell--init-ui-hacks ()
|
||||
(defun syd-eshell-remove-fringes-h ()
|
||||
(set-window-fringes nil 0 0)
|
||||
(set-window-margins nil 1 nil))
|
||||
(defun syd-eshell-enable-text-wrapping-h ()
|
||||
(visual-line-mode +1)
|
||||
(set-display-table-slot standard-display-table 0 ?\ ))
|
||||
(add-hook 'eshell-mode-hook #'syd-eshell-remove-fringes-h)
|
||||
(add-hook 'eshell-mode-hook #'syd-eshell-enable-text-wrapping-h)
|
||||
|
||||
(with-eval-after-load 'hide-mode-line
|
||||
(add-hook 'eshell-mode-hook #'hide-mode-line-mode))
|
||||
|
||||
;; Remove hscroll-margin in shells, otherwise you get jumpiness when the
|
||||
;; cursor comes close to the left/right edges of the window.
|
||||
(defun syd-eshell-disable-hscroll-margin ()
|
||||
(setq hscroll-margin 0))
|
||||
(add-hook 'eshell-mode-hook #'syd-eshell-disable-hscroll-margin))
|
||||
|
||||
(use-package shrink-path
|
||||
:defer t)
|
||||
|
||||
(defface syd-eshell-local-name '((t (:inherit font-lock-constant-face)))
|
||||
"Face used by the Eshell prompt for the CWD's non-TRAMP part. See
|
||||
`syd-eshell--prompt-fn'"
|
||||
:group 'eshell)
|
||||
|
||||
(defface syd-eshell-tramp-prefix '((t (:inherit font-lock-comment-face)))
|
||||
"Face used by the Eshell prompt for the CWD's TRAMP prefix. See
|
||||
`syd-eshell--prompt-fn'."
|
||||
:group 'eshell)
|
||||
|
||||
(defun syd-eshell--prompt-fn ()
|
||||
"See `eshell-prompt-function'."
|
||||
(require 'shrink-path)
|
||||
(require 'syd-file)
|
||||
(-let (((tramp-prefix . local-name) (syd-split-tramp-file-name (eshell/pwd))))
|
||||
(concat (unless (bobp) "\n")
|
||||
(when tramp-prefix
|
||||
(propertize tramp-prefix 'face 'syd-eshell-tramp-prefix))
|
||||
(propertize (if (equal local-name "~")
|
||||
local-name
|
||||
(abbreviate-file-name (shrink-path-file local-name)))
|
||||
'face 'syd-eshell-local-name)
|
||||
(propertize " $"
|
||||
'face (if (zerop eshell-last-command-status)
|
||||
'success
|
||||
'error))
|
||||
" ")))
|
||||
|
||||
(defvar syd-eshell--prompt-regexp (rx bol (* (not (any "\n$"))) " $ "))
|
||||
|
||||
(set-popup-rule! "^\\*eshell-popup"
|
||||
:vslot -5 :size 13 :select t :modeline nil :quit nil :ttl nil)
|
||||
|
||||
(use-package eshell
|
||||
:init
|
||||
(defvar syd-eshell-data-dir (file-name-concat syd-data-dir
|
||||
"eshell"))
|
||||
(make-directory syd-eshell-data-dir t)
|
||||
:custom
|
||||
((eshell-banner-message
|
||||
'(format "🦌 %s %s }:3\n"
|
||||
(propertize (format " %s " (string-trim (buffer-name)))
|
||||
'face 'mode-line-highlight)
|
||||
(propertize (current-time-string)
|
||||
'face 'font-lock-keyword-face)))
|
||||
(eshell-scroll-to-bottom-on-input 'all)
|
||||
(eshell-scroll-to-bottom-on-output nil)
|
||||
(eshell-kill-processes-on-exit t)
|
||||
(eshell-hist-ignoredups t)
|
||||
(eshell-glob-case-insensitive t)
|
||||
(eshell-error-if-no-glob t)
|
||||
(eshell-history-file-name (file-name-concat
|
||||
syd-eshell-data-dir "history"))
|
||||
(eshell-last-dir-ring-file-name (file-name-concat
|
||||
syd-eshell-data-dir "lastdir"))
|
||||
(eshell-prompt-function #'syd-eshell--prompt-fn)
|
||||
(eshell-prompt-regexp syd-eshell--prompt-regexp))
|
||||
:general
|
||||
(:keymaps 'syd-leader-open-map
|
||||
"e" #'syd-eshell/toggle)
|
||||
(:keymaps 'eshell-mode-map
|
||||
:states 'insert
|
||||
"C-d" #'syd-eshell-C-d)
|
||||
(:keymaps 'eshell-mode-map
|
||||
:states 'motion
|
||||
"[ [" #'eshell-previous-prompt
|
||||
"] ]" #'eshell-next-prompt)
|
||||
(:keymaps 'eshell-mode-map
|
||||
:states '(normal insert)
|
||||
"C-j" #'eshell-next-matching-input-from-input
|
||||
"C-k" #'eshell-previous-matching-input-from-input
|
||||
"C-s" #'consult-history)
|
||||
:config
|
||||
;; When cd'd into a TRAMP remote, automatically expand '/' to the TRAMP
|
||||
;; notation referring to the remote's root.
|
||||
(add-to-list 'eshell-modules-list 'eshell-elecslash)
|
||||
|
||||
(require 'syd-buffers)
|
||||
|
||||
(add-hook 'eshell-mode-hook #'syd-mark-buffer-as-real)
|
||||
|
||||
;; UI enhancements.
|
||||
(syd-eshell--init-ui-hacks))
|
||||
|
||||
(provide 'syd-eshell)
|
||||
@@ -1,365 +0,0 @@
|
||||
;;; syd-evil.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; More sensible undo functionality. Emacs' default is very weird, not
|
||||
;; maintaining a proper history.
|
||||
(use-package undo-fu)
|
||||
|
||||
;; Vim emulation.
|
||||
(use-package evil
|
||||
:preface
|
||||
(setq evil-want-minibuffer t
|
||||
evil-move-beyond-eol t
|
||||
evil-respect-visual-line-mode t
|
||||
evil-vsplit-window-right t
|
||||
evil-ex-search-vim-style-regexp t
|
||||
evil-want-Y-yank-to-eol t
|
||||
evil-want-C-u-scroll t
|
||||
evil-want-C-w-in-emacs-state t
|
||||
;; - If non-nil: When using ex commands on a visual selection, pass the
|
||||
;; precise region selected to the command.
|
||||
;; - If nil: Pass the region of /lines/ spanned by the visual selection.
|
||||
evil-ex-visual-char-range t
|
||||
evil-v$-excludes-newline t
|
||||
;; Don't display the state in the mode line.
|
||||
evil-mode-line-format nil
|
||||
evil-normal-state-cursor 'box
|
||||
evil-emacs-state-cursor 'hbar
|
||||
evil-operator-state-cursor 'evil-half-cursor
|
||||
evil-insert-state-cursor 'bar
|
||||
evil-visual-state-cursor 'hollow
|
||||
;; Only do highlighting in selected window so that Emacs has less work
|
||||
;; to do highlighting them all.
|
||||
evil-ex-interactive-search-highlight 'selected-window
|
||||
;; It's infuriating that innocuous "beginning of line" or "end of line"
|
||||
;; errors will abort macros, so we suppress them:
|
||||
evil-kbd-macro-suppress-motion-error t
|
||||
evil-undo-system (cond ((featurep 'undo-tree) 'undo-tree)
|
||||
((featurep 'undo-fu) 'undo-fu)))
|
||||
;; These two are required for evil-collection.
|
||||
(setq evil-want-keybinding nil
|
||||
evil-want-integration t)
|
||||
|
||||
:config
|
||||
;; 'M-:' starts off in insert mode, yet the normal mode cursor lingers until a
|
||||
;; refresh is forced. Quick fix! }:P
|
||||
(add-hook 'minibuffer-setup-hook #'evil-refresh-cursor)
|
||||
|
||||
;; Unbind 'C-k'. Normally, it inserts digraphs; I have a compose key, and
|
||||
;; it's strictly less useful than Emacs' native input methods. It often gets
|
||||
;; in the way of buffers with navigation, e.g. scrolling through shell/REPL
|
||||
;; history, navigating Vertico completions, etc.
|
||||
(keymap-set evil-insert-state-map "C-k" nil)
|
||||
|
||||
;; In imitation of Vim's :mes[sages] command, define an Evil analogue to show
|
||||
;; the echo area.
|
||||
(defun syd-evil-messages ()
|
||||
(interactive)
|
||||
(view-echo-area-messages)
|
||||
(with-current-buffer messages-buffer-name
|
||||
(evil-motion-state 1)))
|
||||
(evil-ex-define-cmd "mes[sages]" #'syd-evil-messages)
|
||||
|
||||
;; On ESC, remove highlighted search results.
|
||||
(defun syd-evil-nohl-h ()
|
||||
"If any Evil Ex search highlightings are active, remove them and return t.
|
||||
Otherwise, nil."
|
||||
(let ((names '(evil-ex-substitute evil-ex-search)))
|
||||
(when (-any #'evil-ex-hl-active-p names)
|
||||
(prog1 t (evil-ex-nohighlight)))))
|
||||
(add-hook 'syd-escape-hook #'syd-evil-nohl-h)
|
||||
|
||||
(general-def
|
||||
:states 'motion
|
||||
"/" #'evil-ex-search-forward
|
||||
"?" #'evil-ex-search-backward
|
||||
"n" #'evil-ex-search-next
|
||||
"N" #'evil-ex-search-previous
|
||||
"*" #'evil-ex-search-word-forward)
|
||||
|
||||
(evil-mode 1))
|
||||
|
||||
;; A large, community-sourced collection of preconfigured Evil-mode
|
||||
;; integrations.
|
||||
(use-package evil-collection
|
||||
;; :after evil
|
||||
;; :defer t
|
||||
:custom (evil-collection-setup-minibuffer t)
|
||||
:preface
|
||||
(defvar evil-collection-key-blacklist)
|
||||
(unless noninteractive
|
||||
(defvar syd-evil-collection-disabled-list
|
||||
'(anaconda-mode buff-menu calc comint company custom eldoc elisp-mode ert
|
||||
free-keys helm help image indent kmacro kotlin-mode lispy outline
|
||||
replace shortdoc simple slime tab-bar)
|
||||
"A list of `evil-collection' modules to ignore. See
|
||||
`evil-collection-mode-list' for a list of available options.")
|
||||
|
||||
;; We do this ourselves.
|
||||
(defvar evil-collection-want-unimpaired-p nil)
|
||||
;; We binds goto-reference on gD and goto-assignments on gA ourselves
|
||||
(defvar evil-collection-want-find-usages-bindings-p nil)
|
||||
;; Reduces keybind conflicts between outline-mode and org-mode (which is
|
||||
;; derived from outline-mode).
|
||||
(defvar evil-collection-outline-enable-in-minor-mode-p nil)
|
||||
;; We handle loading evil-collection ourselves
|
||||
(defvar evil-collection--supported-modes nil)
|
||||
;; This has to be defined here since evil-collection doesn't autoload its own.
|
||||
;; It must be updated whenever evil-collection updates theirs.
|
||||
(defvar evil-collection-mode-list
|
||||
`(2048-game ag alchemist anaconda-mode apropos arc-mode atomic-chrome
|
||||
auto-package-update beginend bluetooth bm bookmark
|
||||
(buff-menu "buff-menu") bufler calc calendar cider citre cmake-mode
|
||||
color-rg comint company compile consult corfu crdt (csv "csv-mode")
|
||||
(custom cus-edit) cus-theme dape dashboard daemons deadgrep debbugs
|
||||
debug devdocs dictionary diff-hl diff-mode dired dired-sidebar
|
||||
disk-usage distel doc-view docker eat ebib ebuku edbi edebug ediff eglot
|
||||
elpaca ement explain-pause-mode eldoc elfeed elisp-mode elisp-refs
|
||||
elisp-slime-nav embark emms ,@(if (> emacs-major-version 28) '(emoji))
|
||||
epa ert eshell eval-sexp-fu evil-mc eww fanyi finder flycheck flymake
|
||||
forge free-keys geiser ggtags git-timemachine gited gnus go-mode gptel
|
||||
grep guix hackernews helm help helpful hg-histedit hungry-delete hyrolo
|
||||
ibuffer (image image-mode) image-dired image+ imenu imenu-list
|
||||
(indent "indent") indium info ivy js2-mode
|
||||
,@(if (>= emacs-major-version 30) '(kmacro)) leetcode lispy lms log-edit
|
||||
log-view lsp-ui-imenu lua-mode kotlin-mode macrostep man
|
||||
(magit magit-repos magit-submodule) magit-repos magit-section
|
||||
magit-todos markdown-mode monky mpc mpdel mu4e mu4e-conversation neotree
|
||||
newsticker notmuch nov omnisharp org org-present org-roam osx-dictionary
|
||||
outline p4 (package-menu package) pass (pdf pdf-tools) popup proced
|
||||
prodigy profiler p-search python quickrun racer racket-describe realgud
|
||||
reftex replace restclient rg ripgrep rjsx-mode robe rtags ruby-mode
|
||||
scheme scroll-lock selectrum sh-script
|
||||
,@(if (> emacs-major-version 27) '(shortdoc)) simple simple-mpc slime
|
||||
sly smerge-mode snake so-long speedbar tab-bar tablist tar-mode telega
|
||||
(term term ansi-term multi-term) tetris thread tide timer-list
|
||||
transmission trashed tuareg typescript-mode vc-annotate vc-dir vc-git
|
||||
vdiff vertico view vlf vterm vundo w3m wdired wgrep which-key
|
||||
with-editor woman xref xwidget yaml-mode youtube-dl zmusic
|
||||
(ztree ztree-diff)))
|
||||
|
||||
(cl-defun syd-evil-collection-init (module &key disabled-modules)
|
||||
"Initialise evil-collection-MODULE.
|
||||
|
||||
A wrapper for `evil-collection-init' that respects a given list of disabled
|
||||
modules."
|
||||
(let ((module* (or (car-safe module) module)))
|
||||
(unless (memq module* disabled-modules)
|
||||
(message "Loading evil-collection-%s%s"
|
||||
module*
|
||||
(if after-init-time "" " too early! }:("))
|
||||
(with-demoted-errors "error loading evil-collection: %s"
|
||||
(evil-collection-init (list module))))))
|
||||
|
||||
;; Allow binding to ESC.
|
||||
(syd-defadvice syd-evil-collection-disable-blacklist-a (fn)
|
||||
:around #'evil-collection-vterm-toggle-send-escape
|
||||
(let (evil-collection-key-blacklist)
|
||||
(funcall-interactively fn)))
|
||||
|
||||
;; These modes belong to packages that Emacs always loads at startup, causing
|
||||
;; evil-collection and it's co-packages to all load immediately. We avoid
|
||||
;; this by loading them after evil-collection has first loaded...
|
||||
(with-eval-after-load 'evil-collection
|
||||
(require 'syd-prelude)
|
||||
(require 'syd-keybinds)
|
||||
;; Don't let evil-collection interfere with certain keys
|
||||
(setq evil-collection-key-blacklist
|
||||
(append (list syd-leader-key syd-localleader-key
|
||||
syd-alt-leader-key)
|
||||
evil-collection-key-blacklist
|
||||
;; Reserved for goto definition; lookup docs; eval; eval
|
||||
;; buffer; movement prefix; movement prefix; escaping };).
|
||||
'("gd" "K" "gr" "gR" "[" "]" "<escape>")))
|
||||
|
||||
(mapc #'syd-evil-collection-init '(comint custom))
|
||||
|
||||
(with-eval-after-load 'evil
|
||||
;; Emacs loads these two packages immediately, at startup, which needlessly
|
||||
;; convolutes load order for evil-collection-help.
|
||||
(with-transient-after 'help-mode
|
||||
(syd-evil-collection-init 'help))
|
||||
(with-transient-after 'Buffer-menu-mode
|
||||
(syd-evil-collection-init '(buff-menu "buff-menu")))
|
||||
(with-transient-after 'calc-mode
|
||||
(syd-evil-collection-init 'calc))
|
||||
(with-transient-after 'image-mode
|
||||
(syd-evil-collection-init 'image))
|
||||
(with-transient-after 'emacs-lisp-mode
|
||||
(syd-evil-collection-init 'elisp-mode))
|
||||
(with-transient-after 'occur-mode
|
||||
(syd-evil-collection-init 'replace))
|
||||
(with-transient-after 'indent-rigidly
|
||||
(syd-evil-collection-init '(indent "indent")))
|
||||
(when (>= emacs-major-version 30)
|
||||
(with-transient-after 'kmacro-menu-mode
|
||||
(syd-evil-collection-init 'kmacro)))
|
||||
(with-transient-after 'minibuffer-setup-hook
|
||||
(when evil-collection-setup-minibuffer
|
||||
(syd-evil-collection-init 'minibuffer)
|
||||
(evil-collection-minibuffer-insert)))
|
||||
(with-transient-after 'process-menu-mode
|
||||
(syd-evil-collection-init '(process-menu simple)))
|
||||
(with-transient-after 'shortdoc-mode
|
||||
(syd-evil-collection-init 'shortdoc))
|
||||
(with-transient-after 'tabulated-list-mode
|
||||
(syd-evil-collection-init 'tabulated-list))
|
||||
(with-transient-after 'tab-bar-mode
|
||||
(syd-evil-collection-init 'tab-bar))
|
||||
|
||||
;; HACK: Do this ourselves because evil-collection break's
|
||||
;; `eval-after-load' load order by loading their target plugin before
|
||||
;; applying keys. This makes it hard for end-users to overwrite these
|
||||
;; keybinds with a simple `after!' or `with-eval-after-load'.
|
||||
(dolist (mode evil-collection-mode-list)
|
||||
(dolist (req (or (cdr-safe mode) (list mode)))
|
||||
(with-eval-after-load req
|
||||
(syd-evil-collection-init
|
||||
mode
|
||||
:disabled-modules syd-evil-collection-disabled-list))))))))
|
||||
|
||||
;; Tim Pope's famous `surround.vim' for Evil.
|
||||
(use-package evil-surround
|
||||
:commands (global-evil-surround-mode
|
||||
evil-surround-edit
|
||||
evil-Surround-edit
|
||||
evil-surround-region)
|
||||
:hook (on-first-input . global-evil-surround-mode)
|
||||
:config
|
||||
;; In `emacs-lisp-mode', `' is a much more common pair than ``.
|
||||
(add-hook 'emacs-lisp-mode-hook
|
||||
(lambda ()
|
||||
(push '(?` . ("`" . "'")) evil-surround-pairs-alist))))
|
||||
|
||||
;; TODO: I'd like JK to escape visual state. evil-escape only allows defining a
|
||||
;; single key sequence. Perhaps key-chord is capable of this?
|
||||
(use-package evil-escape
|
||||
:hook (on-first-input . evil-escape-mode)
|
||||
:custom ((evil-escape-key-sequence "jk")
|
||||
(evil-escape-excluded-states '(normal visual multiedit emacs motion))
|
||||
(evil-escape-delay 0.15)))
|
||||
|
||||
;; `evil-nerd-commenter' has a bunch of cool functions[1]. Here, only the Evil
|
||||
;; operator is used. }:3
|
||||
;; [1]: https://github.com/redguardtoo/evil-nerd-commenter?tab=readme-ov-file#commands-and-hotkeys
|
||||
(use-package evil-nerd-commenter
|
||||
:commands (evilnc-comment-operator
|
||||
evilnc-inner-comment
|
||||
evilnc-outer-commenter)
|
||||
:defer t
|
||||
:bind (:map evil-normal-state-map ("#" . evilnc-comment-operator)
|
||||
:map evil-visual-state-map ("#" . evilnc-comment-operator)
|
||||
:map evil-inner-text-objects-map ("c" . evilnc-inner-comment)
|
||||
:map evil-outer-text-objects-map ("c" . evilnc-outer-comment)))
|
||||
|
||||
;; Enhance `evil-surround' with integration with `embrace'.
|
||||
(use-package evil-embrace
|
||||
:disabled
|
||||
:after evil-surround
|
||||
:config
|
||||
(evil-embrace-enable-evil-surround-integration))
|
||||
|
||||
;; Provides an Evil operator to swap two spans of text.
|
||||
(use-package evil-exchange
|
||||
:bind (:map evil-normal-state-map ("gX" . evil-exchange)
|
||||
:map evil-visual-state-map ("gX" . evil-exchange)))
|
||||
|
||||
;; Evil doesn't ship with support for Vim's 'g-'/'g+'. `evil-numbers'
|
||||
;; implements this.
|
||||
(use-package evil-numbers
|
||||
;; 'g=' is a bit more comfortable than 'g+', whilst preserving the analogy.
|
||||
;; ('=' is '+' modulo shift)
|
||||
:bind (:map evil-normal-state-map ("g=" . 'evil-numbers/inc-at-pt)
|
||||
:map evil-normal-state-map ("g-" . 'evil-numbers/dec-at-pt))
|
||||
:defer t)
|
||||
|
||||
;; Tree-sitter queries → Evil text objects.
|
||||
(use-package evil-textobj-tree-sitter
|
||||
:defer t)
|
||||
|
||||
;; Visually "flash" the region acted upon by Evil-mode operations.
|
||||
(use-package evil-goggles
|
||||
:hook (on-first-input . evil-goggles-mode)
|
||||
;; The flash animation will delay actions, which can be very annoying for some
|
||||
;; operations. Disable `evil-goggles' for those ones.
|
||||
:custom
|
||||
((evil-goggles-enable-delete nil)
|
||||
(evil-goggles-enable-change nil)
|
||||
(evil-goggles-duration 0.1)))
|
||||
|
||||
;; Change cursor shape and color by evil state in terminal.
|
||||
(use-package evil-terminal-cursor-changer
|
||||
;; This package is only useful in the terminal.
|
||||
:if (not (display-graphic-p))
|
||||
:defer t
|
||||
:hook (on-first-input . evil-terminal-cursor-changer-activate))
|
||||
|
||||
;; Automatic alignment in region, by regexp.
|
||||
(use-package evil-lion
|
||||
:hook (on-first-input . evil-lion-mode))
|
||||
|
||||
;; 'g' text object selecting the entire buffer.
|
||||
(with-eval-after-load 'evil
|
||||
(evil-define-text-object
|
||||
evil-entire-buffer (count &optional beg end type)
|
||||
"Select entire buffer"
|
||||
(evil-range (point-min) (point-max) type))
|
||||
(define-key evil-inner-text-objects-map "g" #'evil-entire-buffer)
|
||||
(define-key evil-outer-text-objects-map "g" #'evil-entire-buffer))
|
||||
|
||||
;; 2-character search.
|
||||
(use-package evil-snipe
|
||||
:commands (evil-snipe-local-mode evil-snipe-override-local-mode)
|
||||
:hook ((on-first-input . evil-snipe-override-mode)
|
||||
;; (on-first-input . evil-snipe-mode)
|
||||
)
|
||||
:custom ((evil-snipe-smart-case t)
|
||||
(evil-snipe-scope 'visible)
|
||||
(evil-snipe-repeat-scope 'visible)
|
||||
(evil-snipe-char-fold t)))
|
||||
|
||||
;; Evil's default behaviour for '#'/'*' in visual state will remain in visual
|
||||
;; mode, and jump to the next occurence of the symbol under point. That is, the
|
||||
;; movement is exactly the same as it is in normal state; if the region is over
|
||||
;; the text `two words`, but the point is over `two`, Evil will search for
|
||||
;; `two`. `evil-visualstar' will instead search for `two words`.
|
||||
(use-package evil-visualstar
|
||||
:defer t
|
||||
:bind (:map evil-visual-state-map
|
||||
("*" . evil-visualstar/begin-search-forward)))
|
||||
|
||||
(defvar syd-evil-last-eval-expression-register ?e
|
||||
"An Evil-mode register in which the last expression evaluated with an
|
||||
interactive call to `eval-expression' is stored.")
|
||||
|
||||
(with-eval-after-load 'evil
|
||||
(defun syd-set-eval-expression-register-a (expr &rest _)
|
||||
"If called interactively, set the register
|
||||
`syd-evil-last-eval-expression-register' to a printed form of EXPR."
|
||||
(when (called-interactively-p 'interactive)
|
||||
(->> (pp-to-string expr)
|
||||
(string-remove-suffix "\n")
|
||||
(evil-set-register syd-evil-last-eval-expression-register))))
|
||||
(advice-add #'eval-expression
|
||||
:after #'syd-set-eval-expression-register-a))
|
||||
|
||||
;; HACK: '=' unpredictably moves the cursor when it really doesn't need to.
|
||||
(defun syd-evil-dont-move-point-a (fn &rest args)
|
||||
"Used as :around advice on Evil operators to avoid moving the point."
|
||||
;; We don't use `save-excursion', as we /only/ want to restore the point.
|
||||
(save-excursion (apply fn args)))
|
||||
|
||||
(with-eval-after-load 'evil
|
||||
(advice-add #'evil-indent
|
||||
:around #'syd-evil-dont-move-point-a))
|
||||
|
||||
(use-package evil-leap
|
||||
:hook (on-first-input . evil-leap-mode)
|
||||
:load-path "/home/crumb/src/evil-leap"
|
||||
:straight nil
|
||||
;; :straight (:type git
|
||||
;; :host gitlab
|
||||
;; :repo "msyds/evil-leap")
|
||||
:config
|
||||
(evil-leap-install-default-keybindings))
|
||||
|
||||
(provide 'syd-evil)
|
||||
@@ -1,176 +0,0 @@
|
||||
;;; syd-keybinds.el -*- lexical-binding: t; -*-
|
||||
;;; Universal keybindings, not /too/ tied to any particular packages.
|
||||
|
||||
(require 'syd-general)
|
||||
|
||||
(defun syd-keybinds-initialise ()
|
||||
(syd-initialise-leader)
|
||||
|
||||
(global-set-key [remap keyboard-quit] #'syd/escape)
|
||||
|
||||
;; Buffer
|
||||
(require 'syd-buffers)
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-buffer-map
|
||||
"k" `("Kill buffer" . ,#'kill-current-buffer)
|
||||
"K" `("Kill all buffers" . ,#'syd/kill-all-buffers)
|
||||
"O" `("Kill other buffers" . ,#'syd/kill-other-buffers)
|
||||
"i" `("IBuffer" . ,#'ibuffer)
|
||||
"Z" `("Kill burried buffers" . ,#'syd/kill-burried-buffers)
|
||||
"C" `("Clone (indirect) buffer O/W" . ,#'clone-indirect-buffer-other-window)
|
||||
"c" `("Clone (indirect) buffer" . ,#'clone-indirect-buffer)
|
||||
"u" `("Save buffer as root" . ,#'syd/save-buffer-as-root)
|
||||
"r" `("Revert buffer" . ,#'revert-buffer))
|
||||
|
||||
;; Search
|
||||
(require 'syd-search)
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-search-map
|
||||
"i" `("IMenu" . ,#'consult-imenu)
|
||||
"b" `("Search buffer" . ,#'syd-search-buffer)
|
||||
"d" `("Search directory" . ,#'syd-search-directory))
|
||||
|
||||
;; File
|
||||
(require 'syd-file)
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-file-map
|
||||
"D" `("Delete file" . ,#'syd/delete-this-file)
|
||||
"R" `("Move file" . ,#'syd/move-this-file)
|
||||
"C" `("Copy file" . ,#'syd/copy-this-file)
|
||||
"F" `("Find file in" . ,#'syd-find-file-in)
|
||||
"P" `("Browse Emacs config" . ,#'syd-switch-to-emacs-user-directory)
|
||||
"u" `("Find file as root" . ,#'syd/find-file-as-root)
|
||||
"U" `("Open this file as root" . ,#'syd/open-this-file-as-root)
|
||||
"y" `("Yank buffer path" . ,#'syd/yank-buffer-path)
|
||||
"r" `("Browse recent file" . ,#'consult-recent-file))
|
||||
|
||||
;; Window
|
||||
(require 'syd-window)
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-window-maximise-map
|
||||
"m" `("Maximise" . ,#'syd/window-maximise))
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-window-map
|
||||
"h" `("Select window left" . ,#'evil-window-left)
|
||||
"j" `("Select window below" . ,#'evil-window-down)
|
||||
"k" `("Select window above" . ,#'evil-window-up)
|
||||
"l" `("Select window right" . ,#'evil-window-right)
|
||||
"H" `("Swap window left" . ,#'syd/window-swap-left)
|
||||
"J" `("Swap window below" . ,#'syd/window-swap-down)
|
||||
"K" `("Swap window above" . ,#'syd/window-swap-up)
|
||||
"L" `("Swap window right" . ,#'syd/window-swap-right)
|
||||
"T" `("Tear off window" . ,#'tear-off-window)
|
||||
"=" `("Balance windows" . ,#'balance-windows)
|
||||
"v" `("Vertical split" . ,#'evil-window-vsplit)
|
||||
"s" `("Horizontal split" . ,#'evil-window-split)
|
||||
"F" `("Fit window to contents" . ,#'fit-window-to-buffer)
|
||||
"r" `("Rotate window downwards" . ,#'evil-window-rotate-downwards)
|
||||
"R" `("Rotate window upwards" . ,#'evil-window-rotate-upwards)
|
||||
"u" `("Undo window change" . ,#'winner-undo)
|
||||
"C-r" `("Redo window change" . ,#'winner-redo)
|
||||
"m" `("Maximise" . ,syd-leader-window-maximise-map))
|
||||
|
||||
;; Open
|
||||
(require 'syd-handle-repl)
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-open-map
|
||||
"r" `("Repl o/w" . ,#'+syd/open-repl-other-window))
|
||||
|
||||
;; Project
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-project-map
|
||||
"C" `("Compile project" . ,#'project-compile)
|
||||
"&" `("Async cmd in project root" . ,#'project-async-shell-command)
|
||||
"p" `("Switch project" . ,#'project-switch-project)
|
||||
"." `("Browse project from root" . ,#'syd-project-root-find-file))
|
||||
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-help-package-map
|
||||
"u" `("Temporarily install package" . ,#'straight-use-package)
|
||||
"v" `("Browse package repo" . ,#'straight-visit-package))
|
||||
|
||||
;; Help
|
||||
(general-def
|
||||
:prefix-map 'help-map
|
||||
"F" #'describe-face
|
||||
"'" #'describe-char
|
||||
"T" #'consult-theme
|
||||
"p" `("Packages" . ,syd-leader-help-package-map))
|
||||
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-notes-map)
|
||||
|
||||
(general-def
|
||||
:keymaps '(evil-ex-completion-map minibuffer-local-map minibuffer-mode-map
|
||||
read--expression-map)
|
||||
"C-k" #'previous-history-element
|
||||
"C-j" #'next-history-element)
|
||||
|
||||
;; Motion
|
||||
(general-def
|
||||
:states 'motion
|
||||
"[ b" #'previous-buffer
|
||||
"] b" #'next-buffer
|
||||
"] SPC" #'syd-insert-newline-below
|
||||
"[ SPC" #'syd-insert-newline-above)
|
||||
|
||||
(general-def
|
||||
:keymaps 'global-map
|
||||
:states 'motion
|
||||
"M-:" #'eval-expression
|
||||
"M-x" #'execute-extended-command)
|
||||
|
||||
(general-def
|
||||
:maps 'help-mode-map
|
||||
"<escape>" #'syd/escape)
|
||||
|
||||
;; Insert
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-insert-map
|
||||
"u" #'insert-char)
|
||||
|
||||
;; Code
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-code-map)
|
||||
|
||||
;; This is necessary to properly rebind `universal-argument'.
|
||||
;; `universal-argument-more' is a command that provides additional prefixes
|
||||
;; after the first. Without it, the first 'C-u' will be interpreted as a
|
||||
;; prefix argument for the second 'C-u'.
|
||||
(general-def
|
||||
:keymaps 'universal-argument-map
|
||||
"SPC u" #'universal-argument-more
|
||||
"u" #'universal-argument-more)
|
||||
|
||||
;; Leader
|
||||
(general-def
|
||||
:keymaps 'syd-leader-map
|
||||
"." #'find-file
|
||||
"SPC" `("Find file in project" . ,#'project-find-file)
|
||||
"x" `("Open scratch buffer" . ,#'scratch-buffer)
|
||||
"u" `("Universal argument" . ,#'universal-argument)
|
||||
"b" `("Buffer" . ,syd-leader-buffer-map)
|
||||
"o" `("Open" . ,syd-leader-open-map)
|
||||
"p" `("Project" . ,syd-leader-project-map)
|
||||
"w" `("Window" . ,syd-leader-window-map)
|
||||
"f" `("File" . ,syd-leader-file-map)
|
||||
"s" `("Search" . ,syd-leader-search-map)
|
||||
"h" `("Help" . ,help-map)
|
||||
"n" `("Notes" . ,syd-leader-notes-map)
|
||||
"i" `("Insert" . ,syd-leader-insert-map)
|
||||
"c" `("Code" . ,syd-leader-code-map)
|
||||
"," `("Switch buffer in project" . ,#'consult-project-buffer)
|
||||
"<" `("Switch buffer" . ,#'consult-buffer)
|
||||
"/" `("Search project" . ,#'syd-project-search)))
|
||||
|
||||
(syd-keybinds-initialise)
|
||||
|
||||
;; Show possible completions for a partially-entered key sequence.
|
||||
(use-package which-key
|
||||
;; BUG: (#4) If the first input is a prefix key, `which-key-mode' won't be
|
||||
;; activated in time.
|
||||
:hook (on-first-input . which-key-mode)
|
||||
:custom ((which-key-allow-evil-operators t)
|
||||
(which-key-show-operator-state-maps t)))
|
||||
|
||||
(provide 'syd-keybinds)
|
||||
@@ -1,11 +0,0 @@
|
||||
(add-to-list 'load-path
|
||||
(file-name-concat user-emacs-directory "modules" "lang"))
|
||||
|
||||
(require 'syd-lang-agda)
|
||||
(require 'syd-lang-emacs-lisp)
|
||||
(require 'syd-lang-clojure)
|
||||
(require 'syd-lang-nix)
|
||||
(require 'syd-lang-haskell)
|
||||
(require 'syd-lang-sql)
|
||||
|
||||
(provide 'syd-lang)
|
||||
@@ -1,536 +0,0 @@
|
||||
;;; syd-org.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Optional Org-mode dependency used for highlighting source code in HTML
|
||||
;; exports.
|
||||
(use-package htmlize)
|
||||
|
||||
(with-eval-after-load 'org
|
||||
(syd-add-hook 'org-tab-first-hook
|
||||
(defun syd-org-cycle-only-current-subtree-h (&optional arg)
|
||||
"Toggle the local fold at the point, and no deeper.
|
||||
`org-cycle's standard behavior is to cycle between three levels: collapsed,
|
||||
subtree and whole document. This is slow, especially in larger org buffer. Most
|
||||
of the time I just want to peek into the current subtree -- at most, expand
|
||||
*only* the current subtree.
|
||||
|
||||
All my (performant) foldings needs are met between this and `org-show-subtree'
|
||||
(on zO for evil users), and `org-cycle' on shift-TAB if I need it."
|
||||
(interactive "P")
|
||||
(unless (or (eq this-command 'org-shifttab)
|
||||
(and (bound-and-true-p org-cdlatex-mode)
|
||||
(or (org-inside-LaTeX-fragment-p)
|
||||
(org-inside-latex-macro-p))))
|
||||
(save-excursion
|
||||
(org-beginning-of-line)
|
||||
(let (invisible-p)
|
||||
(when (and (org-at-heading-p)
|
||||
(or org-cycle-open-archived-trees
|
||||
(not (member org-archive-tag (org-get-tags))))
|
||||
(or (not arg)
|
||||
(setq invisible-p
|
||||
(memq (get-char-property (line-end-position)
|
||||
'invisible)
|
||||
'(outline org-fold-outline)))))
|
||||
(unless invisible-p
|
||||
(setq org-cycle-subtree-status 'subtree))
|
||||
(org-cycle-internal-local)
|
||||
t)))))))
|
||||
|
||||
(defun syd-org--init-hacks-h ()
|
||||
;; Open file links in current window, rather than new ones
|
||||
(setf (alist-get 'file org-link-frame-setup) #'find-file)
|
||||
;; Open directory links in dired
|
||||
(add-to-list 'org-file-apps '(directory . emacs))
|
||||
(add-to-list 'org-file-apps '(remote . emacs))
|
||||
|
||||
(defun syd-org--restart-mode-h ()
|
||||
"Restart `org-mode', but only once."
|
||||
(syd-quietly (org-mode-restart))
|
||||
(setq org-agenda-new-buffers
|
||||
(delq (current-buffer)
|
||||
org-agenda-new-buffers))
|
||||
(run-hooks 'find-file-hook))
|
||||
|
||||
(syd-add-hook 'org-agenda-finalize-hook
|
||||
(defun syd-org-exclude-agenda-buffers-from-workspace-h ()
|
||||
"Don't associate temporary agenda buffers with current workspace."
|
||||
(when (and org-agenda-new-buffers
|
||||
(bound-and-true-p persp-mode)
|
||||
(not org-agenda-sticky))
|
||||
(let (persp-autokill-buffer-on-remove)
|
||||
(persp-remove-buffer org-agenda-new-buffers
|
||||
(get-current-persp)
|
||||
nil)))))
|
||||
|
||||
(syd-defadvice syd-org--restart-mode-before-indirect-buffer-a (&optional buffer _)
|
||||
"Restart `org-mode' in buffers in which the mode has been deferred (see
|
||||
`syd-org-defer-mode-in-agenda-buffers-h') before they become the base buffer for an
|
||||
indirect org-cpature buffer. This ensures that the buffer is fully functional
|
||||
not only when the *user* visits it, but also when org-capture interacts with it
|
||||
via an indirect buffer."
|
||||
:before #'org-capture-get-indirect-buffer
|
||||
(with-current-buffer (or buffer (current-buffer))
|
||||
(when (memq #'syd-org--restart-mode-h on-switch-buffer-hook)
|
||||
(syd-org--restart-mode-h))))
|
||||
|
||||
(defvar recentf-exclude)
|
||||
|
||||
(syd-defadvice syd-org--optimise-backgrounded-agenda-buffers-a (fn file)
|
||||
"Disable `org-mode's startup processes for temporary agenda buffers.
|
||||
|
||||
Prevents recentf pollution as well. However, if the user tries to visit one of
|
||||
these buffers they'll see a gimped, half-broken org buffer, so to avoid that,
|
||||
install a hook to restart `org-mode' when they're switched to so they can grow
|
||||
up to be fully-fledged org-mode buffers."
|
||||
:around #'org-get-agenda-file-buffer
|
||||
(if-let* ((buf (org-find-base-buffer-visiting file)))
|
||||
buf
|
||||
(let ((recentf-exclude '(always))
|
||||
;; (doom-inhibit-large-file-detection t)
|
||||
;; (doom-inhibit-local-var-hooks t)
|
||||
(org-inhibit-startup t)
|
||||
vc-handled-backends
|
||||
enable-local-variables
|
||||
find-file-hook)
|
||||
(when-let ((buf (delay-mode-hooks (funcall fn file))))
|
||||
(with-current-buffer buf
|
||||
(add-hook 'on-switch-buffer-hook #'syd-org--restart-mode-h
|
||||
nil 'local))
|
||||
buf))))
|
||||
|
||||
(syd-defadvice syd-org--fix-inconsistent-uuidgen-case-a (uuid)
|
||||
"Ensure uuidgen is always lowercase (consistent) regardless of system.
|
||||
See https://lists.gnu.org/archive/html/emacs-orgmode/2019-07/msg00081.html."
|
||||
:filter-return #'org-id-new
|
||||
(if (eq org-id-method 'uuid)
|
||||
(downcase uuid)
|
||||
uuid)))
|
||||
|
||||
(defun syd-org-init-theme ()
|
||||
(require 'syd-kanagawa)
|
||||
(let* ((hl `(:weight bold))
|
||||
(fg (lambda (c) `(:foreground ,(syd-kanagawa-get c))))
|
||||
(bg (lambda (c) `(:background ,(syd-kanagawa-get c))))
|
||||
(block-delim `(:foreground unspecified
|
||||
:inherit font-lock-comment-face
|
||||
:extend t
|
||||
,@(funcall bg 'sumi-ink-0)
|
||||
:height 0.75))
|
||||
(keyword '(:background unspecified :foreground unspecified
|
||||
:inherit (fixed-pitch font-lock-comment-face)
|
||||
:height 0.9)))
|
||||
(setq org-src-block-faces
|
||||
`(("jupyter-apl" syd-apl)))
|
||||
(custom-theme-set-faces
|
||||
'user
|
||||
`(org-document-title ((t (,@hl :height 1.60))))
|
||||
`(org-document-info ((t (,@hl :height 1.0))))
|
||||
`(org-document-info-keyword ((t ,keyword)))
|
||||
`(org-meta-line ((t ,keyword)))
|
||||
`(org-level-1 ((t (,@hl :height 1.40 ,@(funcall fg 'oni-violet)))))
|
||||
`(org-level-2 ((t (,@hl :height 1.35 ,@(funcall fg 'crystal-blue)))))
|
||||
`(org-level-3 ((t (,@hl :height 1.30 ,@(funcall fg 'spring-violet-2)))))
|
||||
`(org-level-4 ((t (,@hl :height 1.25 ,@(funcall fg 'light-blue)))))
|
||||
`(org-level-5 ((t (,@hl :height 1.20 ,@(funcall fg 'wave-aqua-2)))))
|
||||
`(org-level-6 ((t (,@hl :height 1.15 ,@(funcall fg 'spring-green)))))
|
||||
`(org-level-7 ((t (,@hl :height 1.10 ,@(funcall fg 'boat-yellow-1)))))
|
||||
`(org-level-8 ((t (,@hl :height 1.05 ,@(funcall fg 'boat-yellow-2)))))
|
||||
`(org-block-begin-line ((t ,block-delim)))
|
||||
`(org-block-end-line ((t ,block-delim)))
|
||||
'(org-ellipsis ((t (:height 1.0))))
|
||||
;; It is important that the `org-indent' face uses a fixed-pitch font, lest
|
||||
;; e.g. multi-line bullets appear misaligned.
|
||||
'(org-indent ((t (:inherit (org-hide syd-alt-fixed-pitch)))))
|
||||
;; Must be fixed-pitch; `[ ]` and `[X]' should be the same width.
|
||||
'(org-checkbox ((t (:inherit fixed-pitch))))
|
||||
`(org-drawer ((t ,block-delim)))
|
||||
'(org-property-value ((t (:inherit fixed-pitch))))
|
||||
'(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
|
||||
`(org-block ((t (:inherit fixed-pitch
|
||||
,@(funcall bg 'sumi-ink-2)))))
|
||||
'(org-code ((t (:inherit (shadow fixed-pitch))))))))
|
||||
|
||||
(evil-define-command syd-org-yank-link (register)
|
||||
(interactive "<x>")
|
||||
(if-let* ((url (thing-at-point 'url)))
|
||||
(progn (evil-set-register (or register ?\") url)
|
||||
(message "Yanked link: %s" url))
|
||||
(message "No URL at point")))
|
||||
|
||||
(defun syd-org-init-keybinds ()
|
||||
(general-def
|
||||
:keymaps 'org-mode-map
|
||||
:states '(insert emacs)
|
||||
[tab] #'org-cycle
|
||||
[C-M-return] #'org-insert-subheading)
|
||||
(general-def
|
||||
:prefix-map 'syd-org-mode-links-map
|
||||
"l" #'org-insert-link
|
||||
"y" #'syd-org-yank-link)
|
||||
(general-define-key
|
||||
:keymaps 'org-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"." #'consult-org-heading
|
||||
"/" #'consult-org-agenda
|
||||
"@" #'org-cite-insert
|
||||
"e" #'org-export-dispatch
|
||||
"f" #'org-footnote-action
|
||||
"h" #'org-toggle-heading
|
||||
"i" #'org-toggle-item
|
||||
"I" #'org-id-get-create
|
||||
"k" #'org-babel-remove-result
|
||||
"l" `("Links" . ,syd-org-mode-links-map)
|
||||
"t" #'org-todo
|
||||
"L" #'org-latex-preview
|
||||
"s t" #'org-set-tags-command
|
||||
"s p" #'org-set-property
|
||||
"s d" #'org-deadline
|
||||
"s s" #'org-schedule
|
||||
"d t" #'org-timestamp
|
||||
"d T" #'org-timestamp-inactive
|
||||
"x" #'org-toggle-checkbox)
|
||||
(general-define-key
|
||||
:keymaps 'org-agenda-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"t" #'org-agenda-todo
|
||||
"r" #'org-agenda-refile
|
||||
"q" #'org-agenda-set-tags
|
||||
"p p" #'org-agenda-priority
|
||||
"p u" #'org-agenda-priority-up
|
||||
"p d" #'org-agenda-priority-down
|
||||
"p k" #'org-agenda-priority-up
|
||||
"p j" #'org-agenda-priority-down
|
||||
"d d" #'org-agenda-deadline
|
||||
"d s" #'org-agenda-schedule))
|
||||
|
||||
(defun syd-org-init-popup-rules-h ()
|
||||
(set-popup-rules!
|
||||
'(("^\\*Org Links" :slot -1 :vslot -1 :size 2 :ttl 0)
|
||||
("^ ?\\*\\(?:Agenda Com\\|Calendar\\|Org Export Dispatcher\\)"
|
||||
:slot -1 :vslot -1 :size #'+popup-shrink-to-fit :ttl 0)
|
||||
("^\\*Org \\(?:Select\\|Attach\\|Table Edit\\)" :slot -1 :vslot -2 :ttl 0 :size 0.25)
|
||||
("^\\*Edit Formulas\\*$" :slot -1 :vslot -2 :ttl 0 :size 0.25)
|
||||
("^\\*Org Agenda" :ignore t)
|
||||
("^\\*Org Src" :size 0.42 :quit nil :select t :autosave t :modeline t :ttl nil)
|
||||
("^\\*Org-Babel")
|
||||
("^\\*Capture\\*$\\|CAPTURE-.*$" :size 0.42 :quit nil :select t :autosave ignore))))
|
||||
|
||||
(defun syd-org-init-appearance-h ()
|
||||
;; Larger LaTeX previews.
|
||||
(plist-put org-format-latex-options :scale 1.4))
|
||||
|
||||
(defun syd-org-init-agenda-h ()
|
||||
(setq
|
||||
;; The lengths of these leaders take account for our added
|
||||
;; `syd-org--agenda-repeater'.
|
||||
org-agenda-scheduled-leaders '("Sched" "S.%2dx")
|
||||
org-agenda-deadline-leaders '("Deadl" "In%2dd" "D.%2dx")
|
||||
org-agenda-timerange-leaders '("" ; Range within a single day.
|
||||
"%2d/%2d") ; Range spanning many days.
|
||||
;; Hide "upcoming deadlines" until the scheduled date.
|
||||
org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled
|
||||
;; Hide completed tasks.
|
||||
org-agenda-skip-scheduled-if-done t)
|
||||
|
||||
;; Show the repeater (the repeat interval, e.g. +1d) in repeating agenda
|
||||
;; entries.
|
||||
(defun syd-org--agenda-repeater ()
|
||||
"The repeater information (e.g. +1w) in the agenda."
|
||||
(let ((pom (org-get-at-bol 'org-marker)))
|
||||
(if (or (org-get-scheduled-time pom) (org-get-deadline-time pom))
|
||||
(format "%5s: " (or (org-get-repeat) ""))
|
||||
"┄┄┄┄┄┄┄┄┄┄┄┄")))
|
||||
|
||||
;; Add `syd-org--agenda-repeater' to the agenda prefix.
|
||||
(setcdr (assoc 'agenda org-agenda-prefix-format)
|
||||
" %i %-12:c%?-12t%s%(syd-org--agenda-repeater)")
|
||||
|
||||
(setq org-agenda-custom-commands
|
||||
'(("k" "My agenda for today"
|
||||
((agenda
|
||||
""
|
||||
((org-agenda-span 1)
|
||||
(org-deadline-warning-days 0)))
|
||||
(agenda
|
||||
""
|
||||
((org-agenda-span 7)
|
||||
(org-agenda-start-day "+1d")
|
||||
(org-deadline-warning-days 0)
|
||||
(org-agenda-time-grid nil)
|
||||
(org-agenda-entry-types '(:deadline))
|
||||
(org-agenda-overriding-header "Upcoming deadlines"))))))))
|
||||
|
||||
(defvar syd-org-default-css "
|
||||
<style>
|
||||
html
|
||||
{ height: 100%;
|
||||
}
|
||||
|
||||
body
|
||||
{ height: 100%
|
||||
; padding: 0 10px
|
||||
; line-height: 1.6
|
||||
; font-size: 18px
|
||||
; margin: 40px auto
|
||||
; max-width: 650px
|
||||
; color: #444
|
||||
}
|
||||
|
||||
h1, h2, h3
|
||||
{ line-height: 1.2
|
||||
}
|
||||
|
||||
pre
|
||||
{ line-height: normal
|
||||
}
|
||||
|
||||
.org-svg
|
||||
{ max-height: 100%
|
||||
; max-width: 100%
|
||||
}
|
||||
|
||||
.figure img
|
||||
{ max-height: 100%
|
||||
; max-width: 100%
|
||||
}
|
||||
</style>"
|
||||
"A default style for Org HTML exports.")
|
||||
|
||||
(use-package org
|
||||
:defer-incrementally
|
||||
calendar find-func format-spec org-macs org-compat org-faces org-entities
|
||||
org-list org-pcomplete org-src org-footnote org-macro ob org org-agenda
|
||||
org-capture
|
||||
:init
|
||||
;; HACK: Face specs fed directly to `org-todo-keyword-faces' don't respect
|
||||
;; underlying faces like the `org-todo' face does, so we define our own
|
||||
;; intermediary faces that extend from org-todo.
|
||||
(with-no-warnings
|
||||
(custom-declare-face 'syd-org-todo-active
|
||||
'((t (:inherit (bold font-lock-constant-face org-todo)))) "")
|
||||
(custom-declare-face 'syd-org-todo-project
|
||||
'((t (:inherit (bold font-lock-doc-face org-todo)))) "")
|
||||
(custom-declare-face 'syd-org-todo-onhold
|
||||
'((t (:inherit (bold warning org-todo)))) "")
|
||||
(custom-declare-face 'syd-org-todo-cancel
|
||||
'((t (:inherit (bold error org-todo)))) ""))
|
||||
:custom ((org-startup-folded 'content)
|
||||
(org-directory "~/org")
|
||||
;; Let the agenda be comfortably mutable by storing the list of
|
||||
;; agenda files in a file.
|
||||
(org-agenda-files "~/org/agenda-files")
|
||||
(org-agenda-deadline-faces '((1.001 . error)
|
||||
(1.0 . org-warning)
|
||||
(0.5 . org-upcoming-deadline)
|
||||
(0.0 . org-upcoming-distant-deadline)))
|
||||
(org-agenda-window-setup 'current-window)
|
||||
(org-refile-use-outline-path t)
|
||||
(org-tag-persistent-alist `(("orgmode" . ?o)
|
||||
("hrt" . ?h)))
|
||||
(org-agenda-skip-unavailable-files t)
|
||||
;; Shift the agenda to show the previous 3 days and the next 7 days
|
||||
;; for better context on your week. The past is less important than
|
||||
;; the future.
|
||||
(org-agenda-span 10)
|
||||
(org-agenda-start-on-weekday nil)
|
||||
(org-agenda-start-day "-3d")
|
||||
;; Optimize `org-agenda' by inhibiting extra work while opening
|
||||
;; agenda buffers in the background. They'll be "restarted" if the
|
||||
;; user switches to them anyway (see
|
||||
;; `syd-org-exclude-agenda-buffers-from-workspace-h')
|
||||
(org-agenda-inhibit-startup t)
|
||||
;; Upon finishing a task, leave a timestamp.
|
||||
(org-log-done 'time)
|
||||
(org-indirect-buffer-display 'current-window)
|
||||
;; Force a TeX-like syntax for {sub,super}-scripts. x^{blah blah}
|
||||
(org-use-sub-superscripts '{})
|
||||
(org-fontify-quote-and-verse-blocks t)
|
||||
(org-enforce-todo-dependencies t)
|
||||
(org-image-actual-width nil)
|
||||
(org-imenu-depth 6)
|
||||
;; Include some sane default CSS declarations when exporting to HTML.
|
||||
(org-html-head syd-org-default-css)
|
||||
;; Don't right-align tags.
|
||||
(org-tags-column 0)
|
||||
(org-priority-faces '((?A . error)
|
||||
(?B . warning)
|
||||
(?C . success)))
|
||||
;; Stay out of my config dir!
|
||||
(org-id-locations-file (file-name-concat syd-cache-dir
|
||||
"org-id-locations"))
|
||||
;; New headings should be inserted /after/ the heading's contents.
|
||||
(org-insert-heading-respect-content t)
|
||||
;; Hide markup syntax and leave the markup.
|
||||
(org-hide-emphasis-markers t)
|
||||
(org-ellipsis " […]")
|
||||
(org-todo-keywords
|
||||
'((sequence
|
||||
"TODO(t)" ; A task that needs doing & is ready to do
|
||||
"PROJ(p)" ; A project, which usually contains other tasks
|
||||
"STRT(s)" ; A task that is in progress
|
||||
"WAIT(w)" ; Something external is holding up this task
|
||||
"HOLD(h)" ; This task is paused/on hold because of me
|
||||
"IDEA(i)" ; An unconfirmed and unapproved task or notion
|
||||
"|"
|
||||
"DONE(d)" ; Task successfully completed
|
||||
"KILL(k)"))) ; Task was cancelled, aborted, or is no longer
|
||||
; applicable
|
||||
(org-todo-keyword-faces
|
||||
'(("[-]" . syd-org-todo-active)
|
||||
("STRT" . syd-org-todo-active)
|
||||
("WAIT" . syd-org-todo-onhold)
|
||||
("HOLD" . syd-org-todo-onhold)
|
||||
("PROJ" . syd-org-todo-project)
|
||||
("KILL" . syd-org-todo-cancel))))
|
||||
:preface
|
||||
;; Speed up initialisation by disabling modules we don't need.
|
||||
(defvar org-modules
|
||||
'(;; ol-w3m
|
||||
;; ol-bbdb
|
||||
ol-bibtex
|
||||
;; ol-docview
|
||||
;; ol-gnus
|
||||
;; ol-info
|
||||
;; ol-irc
|
||||
;; ol-mhe
|
||||
;; ol-rmail
|
||||
;; ol-eww
|
||||
))
|
||||
(syd-add-hook 'org-load-hook
|
||||
#'syd-org-init-popup-rules-h
|
||||
#'syd-org-init-appearance-h)
|
||||
(with-eval-after-load 'org-agenda
|
||||
(syd-org-init-agenda-h))
|
||||
:config
|
||||
(require 'syd-prose)
|
||||
(syd-add-hook 'org-mode-hook
|
||||
#'org-indent-mode
|
||||
#'syd-prose-mode)
|
||||
(syd-org-init-theme)
|
||||
(syd-org-init-keybinds))
|
||||
|
||||
(use-package org-appear
|
||||
:hook (org-mode . org-appear-mode)
|
||||
:custom (org-appear-autoemphasis t))
|
||||
|
||||
;; Unlike those appearing in `syd-org--init-roam-keybinds', these should be
|
||||
;; available even outside of Org-mode.
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-notes-roam-map
|
||||
"f" #'org-roam-node-find
|
||||
"d t" #'org-roam-dailies-capture-today
|
||||
"d T" #'org-roam-dailies-goto-today)
|
||||
|
||||
(general-def
|
||||
:keymaps 'syd-leader-open-map
|
||||
"A" #'org-agenda)
|
||||
|
||||
(defun syd-org--init-roam-keybinds ()
|
||||
(general-def
|
||||
:prefix-map 'syd-org-roam-mode-map)
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-notes-map
|
||||
"r" `("Org-roam" . ,syd-leader-notes-roam-map))
|
||||
;; Rebind Imenu keybind to `consult-org-heading'. It's similar enough in
|
||||
;; appearance and functionality, but more reliable and "correct."
|
||||
;; REVIEW: Perhaps it would be best to implement `imenu-create-index-function'
|
||||
;; using `consult-org-heading'?
|
||||
(general-def
|
||||
:keymaps 'org-mode-map
|
||||
[remap consult-imenu] #'consult-org-heading
|
||||
[remap imenu] #'consult-org-heading)
|
||||
(general-define-key
|
||||
:keymaps 'org-mode-map
|
||||
:states '(normal visual motion emacs insert)
|
||||
:major-modes t
|
||||
:prefix syd-localleader-key
|
||||
:non-normal-prefix syd-alt-localleader-key
|
||||
"m" `("Org-roam" . ,syd-org-roam-mode-map)))
|
||||
|
||||
(use-package org-roam
|
||||
:hook (org-load . syd-org-init-roam-h)
|
||||
:commands (org-roam-buffer-toggle-display
|
||||
org-roam-dailies-capture-today
|
||||
org-roam-dailies-goto-date
|
||||
org-roam-dailies-goto-today
|
||||
org-roam-dailies-goto-tomorrow
|
||||
org-roam-dailies-goto-yesterday)
|
||||
:init (progn (syd-org--init-roam-keybinds)
|
||||
(syd-load-packages-incrementally
|
||||
'(ansi-color dash f rx seq magit-section emacsql)))
|
||||
:custom ((org-roam-directory org-directory)
|
||||
(org-roam-db-location (file-name-concat syd-data-dir
|
||||
"org-roam.db"))
|
||||
;; Make org-roam buffer sticky; i.e. don't replace it when opening a
|
||||
;; file with an *-other-window command.
|
||||
(org-roam-buffer-window-parameters '((no-delete-other-windows . t)))
|
||||
(org-roam-completion-everywhere t)
|
||||
(org-roam-dailies-capture-templates
|
||||
`(("d" "default" entry "* %?\n%U"
|
||||
:target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>")
|
||||
:empty-lines 1))))
|
||||
:config
|
||||
(defun syd-org-init-roam-h ()
|
||||
"Setup `org-roam' but don't immediately initialize its database. Instead,
|
||||
initialize it when it will be actually needed."
|
||||
(cl-letf (((symbol-function #'org-roam-db-sync) #'ignore))
|
||||
(org-roam-db-autosync-enable)))
|
||||
|
||||
(syd-org--init-roam-keybinds)
|
||||
|
||||
(syd-defadvice syd-org-roam-try-init-db-a (&rest _)
|
||||
"Try to initialize org-roam database at the last possible safe moment.
|
||||
In case of failure, fail gracefully."
|
||||
:before #'org-roam-db-query
|
||||
(message "Initializing org-roam database...")
|
||||
(advice-remove 'org-roam-db-query #'syd-org-roam-try-init-db-a)
|
||||
(org-roam-db-sync)))
|
||||
|
||||
(use-package evil-org
|
||||
:hook ((org-mode . evil-org-mode)
|
||||
(org-capture-mode . evil-insert-state))
|
||||
:straight (:type git :host github :repo "doomelpa/evil-org-mode")
|
||||
:init
|
||||
(defvar evil-org-retain-visual-state-on-shift t)
|
||||
(defvar evil-org-special-o/O '(table-row))
|
||||
(defvar evil-org-use-additional-insert t)
|
||||
:config
|
||||
(add-hook 'evil-org-mode-hook #'evil-normalize-keymaps)
|
||||
(evil-org-set-key-theme))
|
||||
|
||||
(use-package evil-org-agenda
|
||||
:hook (org-agenda-mode . evil-org-agenda-mode)
|
||||
:straight nil
|
||||
:config
|
||||
(evil-org-agenda-set-keys)
|
||||
;; Stay away from my leader key!
|
||||
(evil-define-key* 'motion evil-org-agenda-mode-map
|
||||
(kbd syd-leader-key) nil))
|
||||
|
||||
(use-package hide-mode-line
|
||||
:hook (org-mode . hide-mode-line-mode))
|
||||
|
||||
(use-package org-superstar
|
||||
:hook (org-mode . org-superstar-mode)
|
||||
:custom ((org-superstar-headline-bullets-list '(9675))
|
||||
(org-superstar-item-bullet-alist '((?- . ?•)
|
||||
(?+ . ?➤)
|
||||
(?* . ?⋆))))
|
||||
:config
|
||||
;; Stars should use fixed-pitch font to align w/ `org-indent'.
|
||||
(custom-theme-set-faces
|
||||
'user
|
||||
`(org-superstar-header-bullet ((t (:font ,syd-alt-fixed-pitch-font))))
|
||||
`(org-superstar-item ((t (:font ,syd-alt-fixed-pitch-font))))))
|
||||
|
||||
(use-package org-fragtog
|
||||
:hook (org-mode . org-fragtog-mode))
|
||||
|
||||
(provide 'syd-org)
|
||||
;;; syd-org.el ends here
|
||||
@@ -1,66 +0,0 @@
|
||||
;;; syd-pdfs.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; A better PDF reader for Emacs.
|
||||
(use-package pdf-tools
|
||||
;; Managed by Nix: pdf-tools depends on a standalone compiled binary.
|
||||
:straight nil
|
||||
:mode ("\\.pdf\\'" . pdf-view-mode)
|
||||
:magic ("%PDF" . pdf-view-mode)
|
||||
:general (:keymaps 'pdf-view-mode-map
|
||||
:states 'motion
|
||||
"q" #'kill-current-buffer)
|
||||
:custom ((pdf-view-display-size 'fit-page))
|
||||
:config
|
||||
;; HACK: Fix "Symbol's function definition is void:
|
||||
;; pdf-occur-global-minor-mode" errors on load.
|
||||
;; https://github.com/politza/pdf-tools/issues/206#issuecomment-614885793
|
||||
(use-package pdf-occur
|
||||
:straight nil
|
||||
:commands (pdf-occur-global-minor-mode))
|
||||
(use-package pdf-history
|
||||
:straight nil
|
||||
:commands (pdf-history-minor-mode))
|
||||
(use-package pdf-links
|
||||
:straight nil
|
||||
:commands (pdf-links-minor-mode))
|
||||
(use-package pdf-outline
|
||||
:straight nil
|
||||
:commands (pdf-outline-minor-mode))
|
||||
(use-package pdf-annot
|
||||
:straight nil
|
||||
:commands (pdf-annot-minor-mode))
|
||||
(use-package pdf-sync
|
||||
:straight nil
|
||||
:commands (pdf-sync-minor-mode))
|
||||
;; Despite its namesake, this does not call `pdf-tools-install', it only sets
|
||||
;; up hooks, auto-mode-alist/magic-mode-alist entries, global modes, and
|
||||
;; refreshes pdf-view-mode buffers, if any.
|
||||
;;
|
||||
;; I avoid calling `pdf-tools-install' directly because `pdf-tools' is easy to
|
||||
;; prematurely load in the background (e.g. when exporting an org file or by
|
||||
;; packages like org-pdftools). And I don't want pdf-tools to suddenly block
|
||||
;; Emacs and spew out compiler output for a few minutes in those cases. It's
|
||||
;; abysmal UX. The `pdf-view-mode' advice above works around this with a less
|
||||
;; cryptic failure message, at least.
|
||||
(pdf-tools-install-noverify)
|
||||
(syd-add-hook 'pdf-view-mode-hook
|
||||
#'pdf-view-themed-minor-mode
|
||||
#'hide-mode-line-mode
|
||||
(defun syd-pdf--init-ui-h ()
|
||||
;; HACK: Flickering pdfs when evil-mode is enabled.
|
||||
(setq-local evil-normal-state-cursor (list nil))))
|
||||
(set-popup-rules!
|
||||
'(("^\\*Outline*" :side right :size 40 :select nil)
|
||||
("^\\*Edit Annotation " :quit nil)
|
||||
("\\(?:^\\*Contents\\|'s annots\\*$\\)" :ignore t)))
|
||||
;; Silence "File *.pdf is large (X MiB), really open?" prompts for PDFs.
|
||||
(syd-defadvice syd-pdf--suppress-large-file-prompts-a
|
||||
(fn size op-type filename &optional offer-raw)
|
||||
:around #'abort-if-file-too-large
|
||||
(unless (string-match-p "\\.pdf\\'" filename)
|
||||
(funcall fn size op-type filename offer-raw))))
|
||||
|
||||
(use-package saveplace-pdf-view
|
||||
:after pdf-view)
|
||||
|
||||
(provide 'syd-pdfs)
|
||||
@@ -1,30 +0,0 @@
|
||||
;; syd-popups.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package popper
|
||||
:hook (on-init-ui-hook)
|
||||
:init
|
||||
(setq popper-display-control nil
|
||||
popper-reference-buffers
|
||||
(list (lambda (buf)
|
||||
(with-current-buffer buf
|
||||
(bound-and-true-p doom-popup-buffer-mode)))))
|
||||
:config
|
||||
(popper-mode 1))
|
||||
|
||||
;; An optional dependency of `doom-popup'. As the name suggests, it provides a
|
||||
;; minor mode that hides the mode-line. `doom-popup' will automatically enable
|
||||
;; it in popup windowss.
|
||||
(use-package hide-mode-line
|
||||
:commands hide-mode-line-mode
|
||||
:preface
|
||||
;; `doom-popup' tests (boundp 'hide-mode-line-mode) before it tries enabling
|
||||
;; or disabling the mode. We must define this because `hide-mode-line' does
|
||||
;; not autoload it.
|
||||
(defvar hide-mode-line-mode nil))
|
||||
|
||||
(use-package doom-popup
|
||||
:straight (:type git
|
||||
:host gitlab
|
||||
:repo "crumbtoo/doom-popup"))
|
||||
|
||||
(provide 'syd-popups)
|
||||
@@ -1,91 +0,0 @@
|
||||
;;; syd-projects.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-constants)
|
||||
|
||||
(with-eval-after-load 'project ; Built-in
|
||||
;; Stay out of my config directory!
|
||||
(setq project-list-file (file-name-concat syd-cache-dir "known-projects"))
|
||||
;; For each command in `project-switch-commands' will assign it the key found
|
||||
;; in `project-prefix-map'. We emulate that behaviour but for our own
|
||||
;; `syd-leader-project-map'.
|
||||
(let* ((project-key
|
||||
(lambda (f)
|
||||
(key-description
|
||||
(where-is-internal
|
||||
f
|
||||
;; If the keymap is not wrapped in a list,
|
||||
;; `where-is-internal' will also search the
|
||||
;; global ;; keymaps
|
||||
(list syd-leader-project-map)
|
||||
;; First result only.
|
||||
t))))
|
||||
(switch-cmd (lambda (command name &optional key)
|
||||
(append (list command name)
|
||||
(list (or key (funcall project-key command)))))))
|
||||
(add-to-list 'project-switch-commands
|
||||
(funcall switch-cmd #'syd-project-root-find-file "Browse"))))
|
||||
|
||||
;; Projection provides a Projectile-like project management library atop
|
||||
;; Emacs built-in project.el. It's more lightweight, while still featureful.
|
||||
(use-package projection
|
||||
;; Enable the `projection-hook' feature.
|
||||
:hook (after-init . global-projection-hook-mode)
|
||||
:general (:keymaps 'syd-leader-project-map
|
||||
"R" #'projection-commands-run-project)
|
||||
;; Require projections immediately after project.el.
|
||||
:config
|
||||
(with-eval-after-load 'project
|
||||
(require 'projection)))
|
||||
|
||||
;; Allow interactively selecting available compilation targets from the
|
||||
;; current project type.
|
||||
(use-package projection-multi
|
||||
:after projection
|
||||
:general (:keymaps 'syd-leader-project-map
|
||||
"M" #'projection-multi-projection))
|
||||
|
||||
;; Embark integration for projection-multi.
|
||||
(use-package projection-multi-embark
|
||||
:after (embark projection-multi)
|
||||
;; Add the projection set-command bindings to
|
||||
;; `compile-multi-embark-command-map'.
|
||||
:config (projection-multi-embark-setup-command-map))
|
||||
|
||||
(use-package skeletor
|
||||
:commands (skeletor-create-project-at skeletor-create-project)
|
||||
:custom ((skeletor-project-directory (expand-file-name "~/src"))
|
||||
(skeletor-completing-read-function #'completing-read))
|
||||
:general (:keymaps 'syd-leader-project-map
|
||||
"n" #'skeletor-create-project
|
||||
"N" #'skeletor-create-project-at)
|
||||
:config
|
||||
;; TODO: Fix the `ns' form in Clojure files.
|
||||
(defun syd-fix-clojure-file-name! (file-name)
|
||||
(let ((new-file-name (->> file-name
|
||||
(string-replace "-" "_")
|
||||
;; NOTE: Will cause fuckiness if file-name starts
|
||||
;; with a dot.
|
||||
(string-replace "." "/"))))
|
||||
(make-directory (file-name-directory new-file-name) t)
|
||||
(rename-file file-name new-file-name)))
|
||||
(defun syd-fix-clojure-file-names! (directory)
|
||||
(let ((default-directory (file-name-concat directory "src")))
|
||||
(dolist (file-name (directory-files "." nil "-" t))
|
||||
(syd-fix-clojure-file-name! file-name))))
|
||||
(skeletor-define-template "clj-nix"
|
||||
:substitutions
|
||||
'(("__PROJECT-OWNER__" . (lambda ()
|
||||
(read-no-blanks-input "Project owner: "))))
|
||||
:before-git
|
||||
(lambda (dir)
|
||||
;; Use underscores instead of hyphens in clj file names.
|
||||
(syd-fix-clojure-file-names! dir)
|
||||
;; REVIEW: Is it safe to make this be async? We require that the command
|
||||
;; has finished before Git initialises.
|
||||
(skeletor-shell-command "nix run github:jlesquembre/clj-nix#deps-lock"
|
||||
dir)))
|
||||
(skeletor-define-template "haskell-flake"
|
||||
:title "Haskell (Flake)"
|
||||
:license-file-name "LICENSE"))
|
||||
|
||||
(provide 'syd-projects)
|
||||
@@ -1,44 +0,0 @@
|
||||
;;; syd-scratch.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-prelude)
|
||||
|
||||
;; Persist the scratch buffer between sessions. Note that it is not persisted
|
||||
;; between boots.
|
||||
;; TODO: This could be better deferred.
|
||||
(use-package persistent-scratch
|
||||
:hook (after-init)
|
||||
:custom (persistent-scratch-save-file
|
||||
(file-name-concat syd-data-dir "scratch"))
|
||||
:config
|
||||
;; The default warning message is a bit too error-looking for my tastes. This
|
||||
;; is the same function, but with a tamer warning message.
|
||||
(defun syd--persistent-scratch--auto-restore-a ()
|
||||
"Automatically restore the scratch buffer once per session."
|
||||
(unless persistent-scratch--auto-restored
|
||||
(condition-case err
|
||||
(persistent-scratch-restore)
|
||||
(error
|
||||
(message "No previous scratch buffer to restore")))
|
||||
(setq persistent-scratch--auto-restored t)))
|
||||
(advice-add #'persistent-scratch--auto-restore
|
||||
:override #'syd--persistent-scratch--auto-restore-a)
|
||||
|
||||
;; Arrange the activation of autosave and auto-restore (if applicable) on
|
||||
;; Emacs start.
|
||||
(persistent-scratch-setup-default))
|
||||
|
||||
(use-package emacs
|
||||
:custom ((initial-scratch-message
|
||||
(with-temp-buffer
|
||||
(insert-file-contents "/persist/vault/crumb/cool-deer.org")
|
||||
(buffer-string)))
|
||||
;; Initial major mode for scratch buffer.
|
||||
(initial-major-mode 'fundamental-mode)
|
||||
;; Disable the initial "help" screen, in favour of starting off in
|
||||
;; the scratch buffer.
|
||||
(inhibit-splash-screen t)
|
||||
(inhibit-startup-screen t)
|
||||
(inhibit-startup-message t)))
|
||||
|
||||
(provide 'syd-scratch)
|
||||
;;; syd-scratch.el ends here
|
||||
@@ -1,54 +0,0 @@
|
||||
;;; syd-smartparens.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Smartparens, most importantly to me, automatically closes opened delimiters.
|
||||
;; It additionally offers a lot of Paredit-like functionality, but we do not yet
|
||||
;; use any of it.
|
||||
;; FIXME: If the first buffer visited is the eval minibuffer, smartparens is not
|
||||
;; activated.
|
||||
(use-package smartparens
|
||||
:hook (on-first-buffer . smartparens-global-mode)
|
||||
:commands (sp-pair sp-local-pair sp-with-modes sp-point-in-comment
|
||||
sp-point-in-string)
|
||||
:custom
|
||||
;; Overlays are too distracting and not terribly helpful. show-parens does
|
||||
;; this for us already (and is faster), so...
|
||||
((sp-highlight-pair-overlay nil)
|
||||
(sp-highlight-wrap-overlay nil)
|
||||
(sp-highlight-wrap-tag-overlay nil)
|
||||
|
||||
;; The default is 100. because smartparen's scans are relatively expensive
|
||||
;; (especially with large pair lists for some modes), we reduce it, as a
|
||||
;; better compromise between performance and accuracy.
|
||||
(sp-max-prefix-length 25)
|
||||
|
||||
;; No pair has any business being longer than 4 characters; if they must, set
|
||||
;; it buffer-locally. It's less work for smartparens.
|
||||
(sp-max-pair-length 4))
|
||||
:config
|
||||
;; Load default config.
|
||||
(require 'smartparens-config)
|
||||
;; Silence some harmless but annoying echo-area spam
|
||||
(dolist (key '(:unmatched-expression :no-matching-tag))
|
||||
(setf (alist-get key sp-message-alist) nil))
|
||||
|
||||
(syd-add-hook 'eval-expression-minibuffer-setup-hook
|
||||
(defun syd-init-smartparens-in-eval-expression-h ()
|
||||
"Enable `smartparens-mode' in the minibuffer for `eval-expression'. This
|
||||
includes everything that calls `read--expression', e.g. `edebug-eval-expression'
|
||||
It is only enabled it if `smartparens-global-mode' is on."
|
||||
(when smartparens-global-mode
|
||||
(smartparens-mode 1))))
|
||||
|
||||
(syd-add-hook 'minibuffer-setup-hook
|
||||
(defun syd-init-smartparens-in-minibuffer-maybe-h ()
|
||||
"Enable `smartparens' for non-`eval-expression' commands. Only enable
|
||||
`smartparens-mode' if `smartparens-global-mode' is on."
|
||||
(when (and smartparens-global-mode (memq this-command '(evil-ex)))
|
||||
(smartparens-mode 1))))
|
||||
|
||||
;; You're likely writing lisp in the minibuffer, therefore, disable these
|
||||
;; quote pairs, which lisps doesn't use for strings:
|
||||
(sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "'" nil :actions nil)
|
||||
(sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "`" nil :actions nil))
|
||||
|
||||
(provide 'syd-smartparens)
|
||||
@@ -1,79 +0,0 @@
|
||||
;;; syd-tabs.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Many themes neglect tab-bar customisation, leaving it completely unstyled.
|
||||
;; `vim-tab-bar' will style it to look like Vim's tab-bar, but more importantly,
|
||||
;; it will colour it to match the current theme.
|
||||
(use-package vim-tab-bar
|
||||
:commands vim-tab-bar-mode)
|
||||
|
||||
(with-eval-after-load 'tab-bar
|
||||
(setq tab-bar-new-tab-to 'rightmost)
|
||||
|
||||
(defun syd-tab-bar-make-free-name ()
|
||||
(cl-loop for i from 1
|
||||
with candidate = nil
|
||||
do (setq candidate (format "#%d" i))
|
||||
while (tab-bar--tab-index-by-name candidate)
|
||||
finally return candidate))
|
||||
|
||||
(defun syd-tab-bar-rename-tab (tab new-name)
|
||||
;; HACK: Using `tab-bar-rename-tab' doesn't work, for some reason. This
|
||||
;; relies on the internal representation of tabs.
|
||||
(setf (alist-get 'name tab) new-name
|
||||
(alist-get 'explicit-name tab) t))
|
||||
|
||||
(defvar syd-tab-bar-name-function #'syd-tab-bar-make-free-name
|
||||
"Nullary function expected to return the name for a new tab.")
|
||||
|
||||
(defvar syd-tab-bar-default-buffer-function #'scratch-buffer)
|
||||
|
||||
(syd-add-hook 'tab-bar-tab-post-open-functions
|
||||
(defun syd-tab-bar--name-new-tab-h (tab)
|
||||
"Hooks to `tab-bar-tab-post-open-functions' such that new tabs will be
|
||||
given \"explicit names\" that are static."
|
||||
(syd-tab-bar-rename-tab tab (funcall syd-tab-bar-name-function))))
|
||||
|
||||
(defun syd-tab-bar--show-tab-bar-h (_tab)
|
||||
"Show the tab-bar if it is not already visible. See
|
||||
`syd-tab-bar-hide-tab-bar-h'."
|
||||
(unless vim-tab-bar-mode
|
||||
(vim-tab-bar-mode 1)))
|
||||
|
||||
(defun syd-tab-bar-new-tab ()
|
||||
(interactive)
|
||||
(let ((tab-bar-tab-post-open-functions
|
||||
(-cons* (lambda (_tab)
|
||||
(switch-to-buffer
|
||||
(funcall syd-tab-bar-default-buffer-function)))
|
||||
#'syd-tab-bar--show-tab-bar-h
|
||||
tab-bar-tab-post-open-functions)))
|
||||
(tab-bar-new-tab)))
|
||||
|
||||
(syd-add-hook 'tab-bar-tab-pre-close-functions
|
||||
(defun syd-tab-bar-hide-tab-bar-h (_tab _final-tab-p)
|
||||
"Hide the tab-bar when there is only a single tab to show. See
|
||||
`syd-tab-bar--show-tab-bar-h'."
|
||||
(when (<= (length (tab-bar-tabs)) 2) ; The tab hasn't yet been removed.
|
||||
(tab-bar-mode -1))))
|
||||
|
||||
(defun syd-tab-bar-new-named-tab (name)
|
||||
(interactive (list (read-string "Tab name: ")))
|
||||
;; Relies on `syd-tab-bar--name-new-tab-h'.
|
||||
(let ((syd-tab-bar-name-function (lambda () name)))
|
||||
(syd-tab-bar-new-tab)))
|
||||
|
||||
(general-def
|
||||
:prefix-map 'syd-leader-tab-map
|
||||
"[" #'tab-previous
|
||||
"]" #'tab-next
|
||||
"r" #'tab-rename
|
||||
"R" #'tab-rename
|
||||
"n" #'syd-tab-bar-new-tab
|
||||
"N" #'syd-tab-bar-new-named-tab
|
||||
"d" #'tab-close)
|
||||
(general-def
|
||||
:keymaps 'syd-leader-map
|
||||
"TAB" `("Tabs" . ,syd-leader-tab-map)
|
||||
"<tab>" `("Tabs" . ,syd-leader-tab-map)))
|
||||
|
||||
(provide 'syd-tabs)
|
||||
@@ -1,66 +0,0 @@
|
||||
;;; syd-tooling.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun syd-lsp-lookup-documentation ()
|
||||
(interactive)
|
||||
(when-let* ((buf (get-buffer "*lsp-help*")))
|
||||
(kill-buffer buf))
|
||||
(call-interactively #'lsp-describe-thing-at-point)
|
||||
(when-let* ((buf (get-buffer "*lsp-help*")))
|
||||
(when (get-buffer-window-list buf)
|
||||
;; Bury the buffer so the popup system has full control over how it's
|
||||
;; selected.
|
||||
(bury-buffer buf)
|
||||
buf)))
|
||||
|
||||
(use-package lsp-mode
|
||||
:init
|
||||
;; We'll bind things ourselves.
|
||||
(setq lsp-keymap-prefix nil)
|
||||
;; Keep state out of my config dir.
|
||||
(setq lsp-session-file (file-name-concat syd-data-dir "lsp-session")
|
||||
;; We disable `lsp-install-server', but I don't want this to be nil.
|
||||
lsp-server-install-dir (file-name-concat syd-data-dir "lsp"))
|
||||
;; Disable features that have great potential to be slow. LSPs tend to be
|
||||
;; quite slow compared to non-LSP equivalents.
|
||||
(setq lsp-enable-folding nil
|
||||
lsp-enable-text-document-color nil)
|
||||
;; Reduce unexpected modifications to code
|
||||
(setq lsp-enable-on-type-formatting nil)
|
||||
;; Make breadcrumbs opt-in; they're redundant with the modeline and imenu
|
||||
(setq lsp-headerline-breadcrumb-enable nil)
|
||||
:hook (lsp-mode . lsp-enable-which-key-integration)
|
||||
:commands lsp
|
||||
:general (:keymaps 'syd-leader-code-map
|
||||
"a" #'lsp-execute-code-action
|
||||
"r" #'lsp-rename)
|
||||
:custom (; Fixes type error when using rename.
|
||||
(lsp-rename-use-prepare nil))
|
||||
:config
|
||||
(syd-defadvice syd-lsp-install-server-a ()
|
||||
"Override and disbale `lsp-install-server'"
|
||||
:override #'lsp-install-server
|
||||
(user-error (concat "Ignoring a call to `lsp-install-server'"
|
||||
" — tell the caller to use Nix!")))
|
||||
(set-popup-rule! (rx line-start "*lsp-" (or "help" "install"))
|
||||
:size 13 :quit t :select nil)
|
||||
|
||||
;; DEPRECATED: Remove once syd-strategies is working.
|
||||
(syd-add-hook 'lsp-mode-hook
|
||||
(defun syd-lsp-set-handlers-h ()
|
||||
(setq-local syd-lookup-documentation-handlers
|
||||
(list #'syd-lsp-lookup-documentation)))))
|
||||
|
||||
(use-package envrc
|
||||
;; REVIEW: Can we load this any later/better?
|
||||
:hook (on-first-file . envrc-global-mode)
|
||||
:general
|
||||
(:prefix-map 'syd-leader-file-env-map
|
||||
"a" #'envrc-allow
|
||||
"r" #'envrc-reload)
|
||||
(:keymaps 'syd-leader-file-map
|
||||
"e" `("Environment" . ,syd-leader-file-env-map))
|
||||
:config
|
||||
(set-popup-rule! (rx "*envrc*")
|
||||
:quit t :ttl 0))
|
||||
|
||||
(provide 'syd-tooling)
|
||||
@@ -1,10 +0,0 @@
|
||||
;;; syd-tramp.el -*- lexical-binding: t; -*-
|
||||
|
||||
(with-eval-after-load 'tramp
|
||||
(setq tramp-persistency-file-name
|
||||
(file-name-concat syd-cache-dir "tramp"))
|
||||
(setq tramp-auto-save-directory
|
||||
(file-name-concat syd-cache-dir "tramp-autosave/"))
|
||||
(add-to-list 'tramp-remote-path 'tramp-own-remote-path))
|
||||
|
||||
(provide 'syd-tramp)
|
||||
@@ -1,180 +0,0 @@
|
||||
;;; syd-ui.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'syd-prelude)
|
||||
|
||||
(defvar syd-fixed-pitch-font
|
||||
(font-spec :family "VictorMono Nerd Font" :size 13)
|
||||
"Default fixed-pitch (monospace) font.")
|
||||
|
||||
(defvar syd-variable-pitch-font
|
||||
(font-spec :family "IBM Plex Serif" :size 15)
|
||||
"Default variable-pitch font.")
|
||||
|
||||
(defvar syd-alt-fixed-pitch-font
|
||||
(font-spec :family "JuliaMono" :size 16)
|
||||
"A monospace font secondary to `syd-fixed-pitch-font'.")
|
||||
|
||||
(defface syd-alt-fixed-pitch
|
||||
`((t (:inherit fixed-pitch :font ,syd-alt-fixed-pitch-font)))
|
||||
"TODO")
|
||||
|
||||
(defface syd-apl
|
||||
`((t (:inherit syd-alt-fixed-pitch)))
|
||||
"Face for APL code")
|
||||
|
||||
;; Beautiful theme in dark and light.
|
||||
(use-package kanagawa-themes
|
||||
:config
|
||||
(load-theme 'kanagawa-wave t))
|
||||
|
||||
(defun syd-init-fonts-h ()
|
||||
"Loads `syd-fixed-pitch-font' and `syd-variable-pitch-font'."
|
||||
(dolist (map `((default . ,syd-fixed-pitch-font)
|
||||
(fixed-pitch . ,syd-fixed-pitch-font)
|
||||
(variable-pitch . ,syd-variable-pitch-font)))
|
||||
(pcase-let ((`(,face . ,font) map))
|
||||
(set-face-attribute face nil
|
||||
:width 'normal :weight 'normal
|
||||
:slant 'normal :font font))))
|
||||
|
||||
(defun syd-configure-default-frame-h ()
|
||||
"Customise the default frame, primarily by adding to `default-frame-alist'."
|
||||
;; Maximise the frame.
|
||||
;; (add-to-list 'default-frame-alist '(fullscreen . maximized))
|
||||
;; Disable the titlebar and borders (decorations).
|
||||
(add-to-list 'default-frame-alist '(undecorated . t)))
|
||||
|
||||
(let ((hook (if (daemonp)
|
||||
'server-after-make-frame-hook
|
||||
'after-init-hook)))
|
||||
(add-hook hook #'syd-init-fonts-h)
|
||||
(add-hook hook #'syd-configure-default-frame-h))
|
||||
|
||||
;; Use JuliaMono as a fallback for some glyphs that VictorMono does not cover.
|
||||
(dolist (char-range '((#x0250 . #x02af) ; IPA extensions
|
||||
(#x2200 . #x22FF))) ; Mathematical operators
|
||||
(set-fontset-font "fontset-default" char-range "JuliaMono"))
|
||||
|
||||
(use-package emacs
|
||||
;; Display (relative) line numbers only in prog-mode derivatives.
|
||||
:hook ((prog-mode-hook . display-line-numbers-mode)
|
||||
;; (on-init-ui-hook . syd-configure-default-frame-h)
|
||||
;; (on-init-ui-hook . syd-init-fonts-h)
|
||||
)
|
||||
:custom ((display-line-numbers-type 'relative)
|
||||
;; Always ask "y/n"; never "yes/no".
|
||||
(use-short-answers t)
|
||||
;; Scroll compilation buffer to follow output.
|
||||
(compilation-scroll-output t)
|
||||
;; Allow `fit-window-to-buffer' to make horizontal adjustments.
|
||||
(fit-window-to-buffer-horizontally t)
|
||||
;; I don't like that `grep' asks me to save unsaved files. It makes
|
||||
;; me think it's about to kill my buffers.
|
||||
(grep-save-buffers nil)
|
||||
;; The default value is `ask', meaning that Emacs will ask for
|
||||
;; confirmation any time you follow a symlink to a file under version
|
||||
;; control. The documentation claims this is "dangerous, and
|
||||
;; probably not what you want;" I personally don't see it, and it's
|
||||
;; usually what I want.
|
||||
(vc-follow-symlinks t)
|
||||
;; Log native-compiler warnings, but don't display the
|
||||
;; buffer. Most of the warnings are "`X' is not known to
|
||||
;; be defined" which are typically nothing worth concerning.
|
||||
(native-comp-async-report-warnings-errors 'silent)
|
||||
;; Don't recenter the view unless >10 lines are scrolled off-screen
|
||||
;; in a single movement.
|
||||
(scroll-conservatively 10)
|
||||
;; In modes making use of `recenter-top-bottom' (e.g. Comint,
|
||||
;; Eshell), this will make the command behave more like a plain old
|
||||
;; `clear` invocation.
|
||||
(recenter-positions '(top)))
|
||||
:config
|
||||
;; Disable the menu bar, scroll bar, and tool bar.
|
||||
(menu-bar-mode -1)
|
||||
(scroll-bar-mode -1)
|
||||
(tool-bar-mode -1))
|
||||
|
||||
(defun syd-init-kill-process-buffer-on-exit ()
|
||||
(defun syd-comint--kill-buffer-sentinel (process _output)
|
||||
"Process sentinel to auto kill associated buffer once PROCESS dies."
|
||||
;; Note that `process-exit-status' returns zero when the process has not yet
|
||||
;; died.
|
||||
(unless (and process (zerop (process-exit-status process)))
|
||||
(let ((buffer (process-buffer process)))
|
||||
(with-current-buffer buffer
|
||||
(goto-char (point-max))
|
||||
(insert (format "\n[Process exited with exit status %d]"
|
||||
(process-exit-status process))))
|
||||
(kill-buffer (process-buffer process)))))
|
||||
|
||||
(defun syd-comint--add-kill-on-exit-sentinel ()
|
||||
"Replace current process sentinel with a new sentinel composed of the
|
||||
current one and `syd-comint--kill-buffer-sentinel'."
|
||||
(let* ((process (get-buffer-process (current-buffer)))
|
||||
(original-sentinel (process-sentinel process))
|
||||
(sentinel-list
|
||||
(-remove #'null
|
||||
(list original-sentinel #'syd-comint--kill-buffer-sentinel)))
|
||||
(combined-sentinel
|
||||
(lambda (process line)
|
||||
(--each sentinel-list
|
||||
(funcall it process line)))))
|
||||
(setf (process-sentinel process) combined-sentinel)))
|
||||
|
||||
(defvar syd-comint--kill-on-exit-h-has-run nil
|
||||
"Whether or not `syd-comint--kill-on-exit-h' has run or not. We need this
|
||||
buffer-local var to prevent the hook from running several times, as can happen
|
||||
for example when calling `shell'.")
|
||||
|
||||
(defun syd-comint--async-funcall (fn &optional buffer args delay)
|
||||
"Run FUNCTION with ARGS in the buffer after a short DELAY."
|
||||
(run-at-time (or delay 0.2) nil
|
||||
`(lambda ()
|
||||
(with-current-buffer ,buffer ,(cons fn args)))))
|
||||
|
||||
(syd-add-hook 'comint-mode-hook
|
||||
(defun syd-comint--kill-on-exit-h ()
|
||||
(unless syd-comint--kill-on-exit-h-has-run
|
||||
(setq-local syd-comint--kill-on-exit-h-has-run t)
|
||||
(syd-comint--async-funcall
|
||||
#'syd-comint--add-kill-on-exit-sentinel
|
||||
(current-buffer))))))
|
||||
|
||||
(with-eval-after-load 'comint
|
||||
(require 'syd-kanagawa)
|
||||
(custom-theme-set-faces
|
||||
'user
|
||||
;; Default prompt face is very ugly. Give it a more subtle look.
|
||||
`(comint-highlight-prompt
|
||||
((t :foreground ,(syd-kanagawa-get 'old-white)
|
||||
:background unspecified
|
||||
:weight bold))))
|
||||
|
||||
(general-def
|
||||
:keymaps 'comint-mode-map
|
||||
:states '(normal insert)
|
||||
"C-k" #'comint-previous-input
|
||||
"C-j" #'comint-next-input
|
||||
"C-s" #'consult-history)
|
||||
(general-def
|
||||
:keymaps 'comint-mode-map
|
||||
:states 'insert
|
||||
"C-d" #'comint-delchar-or-maybe-eof))
|
||||
|
||||
(syd-add-hook 'on-init-ui-hook
|
||||
(defun syd-init-ui-hacks ()
|
||||
(set-popup-rule! "*Backtrace*"
|
||||
:size #'doom-popup-shrink-to-fit)
|
||||
(set-popup-rule! "*Messages*"
|
||||
:ttl nil
|
||||
:quit t)
|
||||
(syd-init-kill-process-buffer-on-exit)
|
||||
;; Required for :quit t to do anything.
|
||||
(evil-set-initial-state 'messages-buffer-mode 'motion)
|
||||
(evil-set-initial-state 'debugger-mode 'normal)
|
||||
(set-popup-rule! shell-command-buffer-name-async
|
||||
:slot -2
|
||||
:modeline nil
|
||||
:ttl nil)))
|
||||
|
||||
(provide 'syd-ui)
|
||||
@@ -1,105 +0,0 @@
|
||||
;;; syd-use-package.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar syd-incremental-idle-timer 0.75
|
||||
"How long (in idle seconds) in between incrementally loading packages.")
|
||||
|
||||
(defvar syd-incremental-first-idle-timer (if (daemonp) 0 2.0)
|
||||
"How long (in idle seconds) until incremental loading starts.
|
||||
|
||||
Set this to nil to disable incremental loading at startup.
|
||||
Set this to 0 to load all incrementally deferred packages immediately at
|
||||
`after-init-hook'.")
|
||||
|
||||
(defvar syd-incremental-packages '(t)
|
||||
"A list of packages to load incrementally after startup. Any large packages
|
||||
here may cause noticeable pauses, so it's recommended you break them up into
|
||||
sub-packages. For example, `org' is comprised of many packages, and might be
|
||||
broken up into:
|
||||
|
||||
(syd-load-packages-incrementally
|
||||
'(calendar find-func format-spec org-macs org-compat
|
||||
org-faces org-entities org-list org-pcomplete org-src
|
||||
org-footnote org-macro ob org org-clock org-agenda
|
||||
org-capture))
|
||||
|
||||
This is already done by the lang/org module, however.
|
||||
|
||||
If you want to disable incremental loading altogether, either remove
|
||||
`syd-load-packages-incrementally-h' from `after-init-hook' or set
|
||||
`syd-incremental-first-idle-timer' to nil. Incremental loading does not occur
|
||||
in daemon sessions (they are loaded immediately at startup).")
|
||||
|
||||
(defun syd-load-packages-incrementally (packages &optional now)
|
||||
"Registers PACKAGES to be loaded incrementally.
|
||||
|
||||
If NOW is non-nil, PACKAGES will be marked for incremental loading next time
|
||||
Emacs is idle for `syd-incremental-first-idle-timer' seconds (falls back to
|
||||
`syd-incremental-idle-timer'), then in `syd-incremental-idle-timer' intervals
|
||||
afterwards."
|
||||
(let* ((gc-cons-threshold most-positive-fixnum)
|
||||
(first-idle-timer (or syd-incremental-first-idle-timer
|
||||
syd-incremental-idle-timer)))
|
||||
(if (not now)
|
||||
(cl-callf append syd-incremental-packages packages)
|
||||
(while packages
|
||||
(let ((req (pop packages))
|
||||
idle-time)
|
||||
(unless (featurep req)
|
||||
(condition-case-unless-debug e
|
||||
(and
|
||||
(or (null (setq idle-time (current-idle-time)))
|
||||
(< (float-time idle-time) first-idle-timer)
|
||||
(not
|
||||
(while-no-input
|
||||
;; If `default-directory' doesn't exist or is
|
||||
;; unreadable, Emacs throws file errors.
|
||||
(let ((default-directory user-emacs-directory)
|
||||
(inhibit-message t)
|
||||
(file-name-handler-alist
|
||||
(list (rassq 'jka-compr-handler file-name-handler-alist))))
|
||||
(message "loading %s" req)
|
||||
(require req nil t)
|
||||
t))))
|
||||
(push req packages))
|
||||
(error
|
||||
(message "Error: failed to incrementally load %S because: %s" req e)
|
||||
(setq packages nil)))
|
||||
(unless (null packages)
|
||||
(run-at-time (if idle-time
|
||||
syd-incremental-idle-timer
|
||||
first-idle-timer)
|
||||
nil #'syd-load-packages-incrementally
|
||||
packages t)
|
||||
(setq packages nil))))))))
|
||||
|
||||
(defun syd-load-packages-incrementally-h ()
|
||||
"Begin incrementally loading packages in `syd-incremental-packages'.
|
||||
|
||||
If this is a daemon session, load them all immediately instead."
|
||||
(when (numberp syd-incremental-first-idle-timer)
|
||||
(if (zerop syd-incremental-first-idle-timer)
|
||||
(mapc #'require (cdr syd-incremental-packages))
|
||||
(run-with-idle-timer syd-incremental-first-idle-timer
|
||||
nil #'syd-load-packages-incrementally
|
||||
(cdr syd-incremental-packages) t))))
|
||||
|
||||
(unless noninteractive
|
||||
(add-hook 'after-init-hook #'syd-load-packages-incrementally-h 100))
|
||||
|
||||
(with-eval-after-load 'use-package-core
|
||||
(push :defer-incrementally use-package-deferring-keywords)
|
||||
(setq use-package-keywords (use-package-list-insert
|
||||
:defer-incrementally use-package-keywords :after))
|
||||
(defalias 'use-package-normalize/:defer-incrementally
|
||||
#'use-package-normalize-symlist)
|
||||
(defun use-package-handler/:defer-incrementally
|
||||
(name _keyword targets rest state)
|
||||
(use-package-concat
|
||||
`((syd-load-packages-incrementally
|
||||
',(if (equal targets '(t))
|
||||
(list name)
|
||||
(append targets (list name)))))
|
||||
(use-package-process-keywords name rest state))))
|
||||
|
||||
(provide 'syd-use-package)
|
||||
;;; syd-use-package.el ends here
|
||||
Reference in New Issue
Block a user