From 1623630a7d1f092635142e7602790994008fa0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madeleine=20Sydney=20=C5=9Alaga?= Date: Thu, 19 Jun 2025 10:51:42 -0600 Subject: [PATCH] wip: new emacs --- hosts/sydpc/configuration.nix | 2 + modules/home/emacs.nix | 6 +- modules/home/openutau.nix | 18 + modules/home/users/msyds/emacs.nix | 6 + modules/home/users/msyds/emacs/early-init.el | 16 + modules/home/users/msyds/emacs/init.el | 5 + .../syd/early-init/00-define-constants.el | 15 + .../lisp/syd/early-init/01-disable-package.el | 5 + .../msyds/emacs/lisp/syd/init/10-elpaca.el | 58 +++ .../emacs/lisp/syd/init/10-use-package.el | 108 ++++++ .../msyds/emacs/lisp/syd/init/15-general.el | 111 ++++++ .../msyds/emacs/lisp/syd/init/20-prelude.el | 176 +++++++++ .../msyds/emacs/lisp/syd/init/40-evil.el | 358 ++++++++++++++++++ .../msyds/emacs/lisp/syd/init/50-comint.el | 24 ++ .../emacs/lisp/syd/init/50-default-frame.el | 15 + .../emacs/lisp/syd/init/50-emacs-lisp-mode.el | 5 + .../msyds/emacs/lisp/syd/init/50-fonts.el | 35 ++ .../msyds/emacs/lisp/syd/init/50-kanagawa.el | 7 + .../users/msyds/emacs/lisp/syd/init/50-ui.el | 44 +++ .../users/msyds/emacs/lisp/syd/kanagawa.el | 133 +++++++ users/crumb/default.nix | 1 + 21 files changed, 1144 insertions(+), 4 deletions(-) create mode 100644 modules/home/openutau.nix create mode 100644 modules/home/users/msyds/emacs/early-init.el create mode 100644 modules/home/users/msyds/emacs/init.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/early-init/00-define-constants.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/early-init/01-disable-package.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/10-elpaca.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/10-use-package.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/15-general.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/20-prelude.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/40-evil.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/50-comint.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/50-default-frame.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/50-emacs-lisp-mode.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/50-fonts.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/50-kanagawa.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/init/50-ui.el create mode 100644 modules/home/users/msyds/emacs/lisp/syd/kanagawa.el diff --git a/hosts/sydpc/configuration.nix b/hosts/sydpc/configuration.nix index ceaa5b6..2306423 100644 --- a/hosts/sydpc/configuration.nix +++ b/hosts/sydpc/configuration.nix @@ -154,10 +154,12 @@ "https://cache.deertopia.net" "https://nix-community.cachix.org" "https://cache.nixos.org" + "https://cache.iog.io" ]; trusted-public-keys = [ (builtins.readFile ../../public-keys/deertopia-cache.pub.pem) "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" ]; }; }; diff --git a/modules/home/emacs.nix b/modules/home/emacs.nix index bb15252..efa5ba0 100644 --- a/modules/home/emacs.nix +++ b/modules/home/emacs.nix @@ -33,8 +33,6 @@ in { type = lib.types.listOf lib.types.package; default = []; }; - files = [ - ]; tex = { enable = lib.mkEnableOption "TexLive"; extraTexPackages = lib.mkOption { @@ -88,7 +86,7 @@ in { my-texlive = pkgs.texlive.combine (essentialTexPackages ++ cfg.tex.extraTexPackages); - emacs-final = + sydmacs = let ewp = (pkgs.emacsPackagesFor cfg.package).emacsWithPackages cfg.emacsPackages; in pkgs.symlinkJoin { @@ -114,7 +112,7 @@ in { in { programs.emacs = { enable = true; - package = emacs-final; + package = sydmacs; }; sydnix.impermanence.cache.directories = [ diff --git a/modules/home/openutau.nix b/modules/home/openutau.nix new file mode 100644 index 0000000..c061d7d --- /dev/null +++ b/modules/home/openutau.nix @@ -0,0 +1,18 @@ +{ config, lib, pkgs, ... }: + +let cfg = config.sydnix.openutau; +in { + options.sydnix.openutau = { + enable = lib.mkEnableOption "OpenUTAU"; + }; + + config = lib.mkIf cfg.enable { + home.packages = [ + pkgs.openutau + ]; + + sydnix.impermanence.directories = [ + ".local/share/OpenUtau" + ]; + }; +} diff --git a/modules/home/users/msyds/emacs.nix b/modules/home/users/msyds/emacs.nix index fd9f6f4..9fe5725 100644 --- a/modules/home/users/msyds/emacs.nix +++ b/modules/home/users/msyds/emacs.nix @@ -19,6 +19,12 @@ in { config = lib.mkIf cfg.enable { sydnix.emacs = { enable = true; + inherit (cfg) userDir; + fontPackages = [ + pkgs.julia-mono + pkgs.nerd-fonts.victor-mono + pkgs.ibm-plex + ]; }; }; } diff --git a/modules/home/users/msyds/emacs/early-init.el b/modules/home/users/msyds/emacs/early-init.el new file mode 100644 index 0000000..dbec714 --- /dev/null +++ b/modules/home/users/msyds/emacs/early-init.el @@ -0,0 +1,16 @@ +;;; early-init.el -*- lexical-binding: t -*- + +(add-to-list 'load-path + (file-name-concat user-emacs-directory "lisp")) + +(defun syd-load-directory (dir) + "Load each file matching DIR/*.el in lexicographical order." + (dolist (file + ;; The returned list is sorted, which is what we want. The files are + ;; named with a two-digit prefix defining its load order. + (directory-files dir 'full "\\.el$")) + (load file))) + +;; Load each file matching lisp/syd/early-init/*.el. +(syd-load-directory + (file-name-concat user-emacs-directory "lisp/syd/early-init")) diff --git a/modules/home/users/msyds/emacs/init.el b/modules/home/users/msyds/emacs/init.el new file mode 100644 index 0000000..2ce9a20 --- /dev/null +++ b/modules/home/users/msyds/emacs/init.el @@ -0,0 +1,5 @@ +;;; init.el -*- lexical-binding: t -*- + +;; Load each file matching lisp/syd/init/*.el. +(syd-load-directory + (file-name-concat user-emacs-directory "lisp/syd/init")) diff --git a/modules/home/users/msyds/emacs/lisp/syd/early-init/00-define-constants.el b/modules/home/users/msyds/emacs/lisp/syd/early-init/00-define-constants.el new file mode 100644 index 0000000..f89b4de --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/early-init/00-define-constants.el @@ -0,0 +1,15 @@ +;;; -*- lexical-binding: t -*- + +(defvar syd-data-dir + (or (getenv "EMACS_DATA_DIR") + (file-name-concat (or (getenv "XDG_DATA_HOME") + (expand-file-name "~/.local/share")) + "emacs"))) + +(defvar syd-cache-dir + (or (getenv "EMACS_CACHE_DIR") + (file-name-concat (or (getenv "XDG_CACHE_HOME") + (expand-file-name "~/.cache")) + "emacs"))) + +(provide 'syd/early-init/define-constants) diff --git a/modules/home/users/msyds/emacs/lisp/syd/early-init/01-disable-package.el b/modules/home/users/msyds/emacs/lisp/syd/early-init/01-disable-package.el new file mode 100644 index 0000000..e1a39ce --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/early-init/01-disable-package.el @@ -0,0 +1,5 @@ +;;; -*- lexical-binding: t -*- + +(setq package-enable-at-startup nil) + +(provide 'syd/early-init/disable-package) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/10-elpaca.el b/modules/home/users/msyds/emacs/lisp/syd/init/10-elpaca.el new file mode 100644 index 0000000..ccc2c9f --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/10-elpaca.el @@ -0,0 +1,58 @@ +;;; -*- lexical-binding: t -*- + + +;;; Installation + +;; Code per Elpaca's installation instructions available at +;; https://github.com/progfolio/elpaca?tab=readme-ov-file#installer. +;; Modified to avoid polluting the Emacs user directory. + +(defvar elpaca-installer-version 0.11) +(defvar elpaca-directory (expand-file-name "elpaca/" syd-data-dir)) +(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) +(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) +(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" + :ref nil :depth 1 :inherit ignore + :files (:defaults "elpaca-test.el" (:exclude "extensions")) + :build (:not elpaca--activate-package))) +(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) + (build (expand-file-name "elpaca/" elpaca-builds-directory)) + (order (cdr elpaca-order)) + (default-directory repo)) + (add-to-list 'load-path (if (file-exists-p build) build repo)) + (unless (file-exists-p repo) + (make-directory repo t) + (when (<= emacs-major-version 28) (require 'subr-x)) + (condition-case-unless-debug err + (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) + ((zerop (apply #'call-process `("git" nil ,buffer t "clone" + ,@(when-let* ((depth (plist-get order :depth))) + (list (format "--depth=%d" depth) "--no-single-branch")) + ,(plist-get order :repo) ,repo)))) + ((zerop (call-process "git" nil buffer t "checkout" + (or (plist-get order :ref) "--")))) + (emacs (concat invocation-directory invocation-name)) + ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" + "--eval" "(byte-recompile-directory \".\" 0 'force)"))) + ((require 'elpaca)) + ((elpaca-generate-autoloads "elpaca" repo))) + (progn (message "%s" (buffer-string)) (kill-buffer buffer)) + (error "%s" (with-current-buffer buffer (buffer-string)))) + ((error) (warn "%s" err) (delete-directory repo 'recursive)))) + (unless (require 'elpaca-autoloads nil t) + (require 'elpaca) + (elpaca-generate-autoloads "elpaca" repo) + (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) +(add-hook 'after-init-hook #'elpaca-process-queues) +(elpaca `(,@elpaca-order)) + + +;;; Use-package support + +;; Install use-package support. +(elpaca elpaca-use-package + (elpaca-use-package-mode)) + + + +(provide 'syd/init/elpaca) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/10-use-package.el b/modules/home/users/msyds/emacs/lisp/syd/init/10-use-package.el new file mode 100644 index 0000000..4f30712 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/10-use-package.el @@ -0,0 +1,108 @@ +;;; -*- 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)))) + +;; Set `:ensure t` by default. +(require 'use-package-ensure) +(setq use-package-always-ensure t) + +(provide 'syd/init/use-package) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/15-general.el b/modules/home/users/msyds/emacs/lisp/syd/init/15-general.el new file mode 100644 index 0000000..b54c968 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/15-general.el @@ -0,0 +1,111 @@ +;;; -*- lexical-binding: t; -*- + +(use-package general + :custom (general-use-package-emit-autoloads t) + :ensure (:wait t)) + +(require 'general) + +(defvar syd-leader-key "SPC" + "A prefix key akin to Vim's .") + +(defvar syd-localleader-key "SPC m" + "A prefix key akin to Vim's .") + +(defvar syd-alt-leader-key "M-SPC" + "`syd-leader', but for the states specified in `syd-alt-leader-key-states'. + +Often, your \"usual\" leader key will be something unavailable in the Insert +state. This key exists as a fallback for when you need your Leader, but must +remain in the Insert state. Substitute \"Insert state\" for your states of +choice with `syd-alt-leader-key-states'.") + +(defvar syd-alt-localleader-key "M-SPC m" + "`syd-localleader', but for the states specified in `syd-alt-leader-key-states'. + +See `syd-alt-leader-key' for rationale.") + +(defvar syd-leader-key-states '(normal visual motion) + "States for which the Leader keys (`syd-leader-key', `syd-localleader-key') +are active.") + +(defvar syd-alt-leader-key-states '(emacs insert) + "States for which the alternative Leader keys are active. See +`syd-alt-leader-key' and `syd-alt-localleader-key'.") + +(defvar-keymap syd-leader-map + :doc "Leader-prefixed commands") + +(defun syd-initialise-leader () + "Set up the (empty) keymap associated with `syd-leader-key', +`syd-localleader-key', `syd-alt-leader-key', and `syd-alt-localleader-key'." + (require 'evil) + ;; Define `syd/leader' as a command corresponding to the prefix map + ;; `syd-leader-map'. + (define-prefix-command 'syd/leader 'syd-leader-map) + ;; This should help make the Leader key close to universally available. + ;; Ideally, *nothing* takes precedence over Leader — it's an incredibly + ;; important key! + ;; https://github.com/noctuid/evil-guide?tab=readme-ov-file#undoprevent-overridingintercept-maps + ;; See `evil-make-overriding-map'. + (define-key syd-leader-map [override-state] 'all) + ;; Finally, we shall bind the damned keys. }:) + (let ((map general-override-mode-map)) + (evil-define-key* syd-leader-key-states map (kbd syd-leader-key) 'syd/leader) + (evil-define-key* syd-alt-leader-key-states map (kbd syd-alt-leader-key) 'syd/leader)) + (general-override-mode 1)) + +(defvar syd-escape-hook nil + "A hook run when C-g is pressed (or ESC in Evil's normal state). + +More specifically, when `syd/escape' is pressed. If any hook returns non-nil, +all hooks after it are ignored.") + +;; +;;; Universal, non-nuclear escape + +;; `keyboard-quit' is too much of a nuclear option. I want ESC/C-g to +;; do-what-I-mean. It serves four purposes (in order): +;; +;; 1. Quit active states; e.g. highlights, searches, snippets, iedit, +;; multiple-cursors, recording macros, etc. +;; 2. Close popup windows remotely (if it is allowed to) +;; 3. Refresh buffer indicators, like diff-hl and flycheck +;; 4. Or fall back to `keyboard-quit' +;; +;; And it should do these things incrementally, rather than all at once. And it +;; shouldn't interfere with recording macros or the minibuffer. This may +;; require you press ESC/C-g two or three times on some occasions to reach +;; `keyboard-quit', but this is much more intuitive. + +(defun syd/escape (&optional interactive) + "Run `syd-escape-hook'." + (interactive (list 'interactive)) + (let ((inhibit-quit t)) + (cond ((minibuffer-window-active-p (minibuffer-window)) + ;; quit the minibuffer if open. + (when interactive + (setq this-command 'abort-recursive-edit)) + (abort-recursive-edit)) + ;; Run all escape hooks. If any returns non-nil, then stop there. + ((run-hook-with-args-until-success 'syd-escape-hook)) + ;; don't abort macros + ((or defining-kbd-macro executing-kbd-macro) nil) + ;; Back to the default + ((unwind-protect (keyboard-quit) + (when interactive + (setq this-command 'keyboard-quit))))))) + +(with-eval-after-load 'eldoc + (eldoc-add-command 'syd/escape)) + +;; In normal state, pressing escape should run `syd-escape-hook'. +(with-eval-after-load 'evil + (defun evil-syd/escape-a (&rest _) + "Call `syd/escape' if `evil-force-normal-state' is called interactively." + (when (called-interactively-p 'any) + (call-interactively #'syd/escape))) + (advice-add #'evil-force-normal-state + :after #'evil-syd/escape-a)) + +(provide 'syd/init/general) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/20-prelude.el b/modules/home/users/msyds/emacs/lisp/syd/init/20-prelude.el new file mode 100644 index 0000000..80ed273 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/20-prelude.el @@ -0,0 +1,176 @@ +;;; -*- lexical-binding: t; -*- + +(eval-when-compile (require 'cl-lib)) +(use-package dash :ensure (:wait t)) +(require 'dash) + +(cl-defmacro syd-define-stub + (name &key (desc "implement me!") interactive) + (let ((todo (format "%s: TODO: %s" name desc))) + `(defun ,name (&rest _) + ,@(if interactive (list '(interactive)) nil) + ,todo + (error ,todo)))) + +;; FIXME: When `arg-list' contains nils, things break. +(cl-defun syd-parse-rest-and-keys (arg-list) + "The default behaviour of `cl-defun' makes combining &rest with &keys pretty +useless. This function will partition ARG-LIST by returning a pair (REST +. KEYS), where REST is the list of ARGS that belong to no key-value pair, and +KEYS is an alist of the parsed keywords." + ;; Ugh. + (let (parsed-rest parsed-keys) + (cl-loop for (lead lag) on arg-list by (lambda (x) (-drop 2 x)) + do (if (keywordp lead) + (push (cons lead lag) parsed-keys) + ;; Push in reverse order; we reverse the whole list as a + ;; post-processing step. + (push lead parsed-rest) + (when lag + (push lag parsed-rest)))) + (cons (reverse parsed-rest) parsed-keys))) + +(cl-defun syd-lift-lambdas (&key with-each with-all forms) + ;; Call the continuation if non-nil. Wraps the return value in a singleton + ;; list for "affine" use with unquote-splicing. + (-let ((call-cont (lambda (cont arg) + (if cont + (list (funcall cont arg)) + nil))) + names) + `(progn + ,@(cl-loop + for form in forms + appending (cond ((syd-hform-symbol form) + (let ((name (nth 1 form))) + (push name names) + (funcall call-cont with-each name))) + ((syd-hform-defun form) + (let ((name (nth 1 form))) + (push name names) + `(,form + ,@(funcall call-cont with-each name)))) + ((syd-hform-lambda form) + (let ((name (gensym "lifted-lambda"))) + (push name names) + `((defun ,name (&rest args) + (,form args)) + ,@(funcall call-cont with-each name)))) + (t (error "IDK!")))) + ,@(funcall call-cont with-all names)))) + +(defun syd-hform-symbol (hform) + (and (listp hform) + (= 2 (length hform)) + (symbolp (nth 1 hform)) + (memq (nth 0 hform) '(quote function)))) + +(defun syd-hform-defun (hform) + "If HFORM is a defun form, return the defun's name. Otherwise, return nil" + (when-let* ((sym (car-safe hform))) + (and (symbolp sym) + (eq sym 'defun) + (nth 1 hform)))) + +(defun syd-hform-lambda (hform) + "If HFORM is a lambda, return non-nil." + (when-let* ((sym (car-safe hform))) + (and (symbolp sym) + (eq sym 'lambda)))) + +(defmacro comment (&rest _) + "Ignore each argument, and expand to nil." + nil) + +(defmacro with-transient-after (hook-or-function &rest forms) + (declare (indent defun)) + (let ((hook-name (gensym "transient-hook")) + (hook-or-function* (gensym "hook-or-function"))) + `(let* ((,hook-or-function* ,hook-or-function)) + (defun ,hook-name (&rest _) + "Transient hook defined by `with-transient-after'." + (cond ((functionp ,hook-or-function*) + (advice-remove ,hook-or-function* #',hook-name)) + ((symbolp ,hook-or-function*) + (remove-hook ,hook-or-function* #',hook-name))) + ,@forms) + (cond ((functionp ,hook-or-function*) + (advice-add ,hook-or-function* :before #',hook-name)) + ((symbolp ,hook-or-function*) + ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Setting-Hooks.html#Setting-Hooks-1 + (put ',hook-name 'permanent-local-hook t) + (add-hook ,hook-or-function* #',hook-name)))))) + +(defun syd-plist-put (plist prop new-val) + "Immutably update a single property of PLIST. Like `plist-put', but PLIST is +not mutated; a new plist is returned." + (cl-loop for (prop* old-val) on plist by #'cddr + appending (if (eq prop prop*) + (list prop* new-val) + (list prop* old-val)))) + +(defmacro syd-add-hook (hooks &rest hforms) + (declare (indent defun)) + (syd-lift-lambdas + :forms hforms + :with-all (lambda (fns) + (let ((fn* (gensym "fn")) + (fns* (gensym "fns")) + (hook* (gensym "hook"))) + `(let ((,fns* (list ,@(--map `(function ,it) + fns)))) + (dolist (,hook* (ensure-list ,hooks)) + (dolist (,fn* ,fns*) + (add-hook ,hook* ,fn*)))))))) + +(defmacro syd-silently (&rest body) + `(error "TODO: syd-silently")) + +(defmacro syd-quietly (&rest body) + "Evaluate BODY without generating any output. + +This silences calls to `message', `load', `write-region' and anything that +writes to `standard-output'. In interactive sessions this inhibits output to +the echo-area, but not to *Messages*. Return value is that of BODY's final +form." + `(if init-file-debug + (progn ,@body) + ,(if noninteractive + `(syd-silently ,@body) + `(let ((inhibit-message t) + (save-silently t)) + (prog1 (progn ,@body) + (message "")))))) + +(defun syd--parse-defadvice-args (arg-list) + "Parses the docstring and keywords provided to `syd-defadvice'." + (let (docstring + advice) + (when (stringp (car-safe arg-list)) + (setq docstring (pop arg-list))) + (while (and (length> arg-list 2) + (keywordp (car arg-list))) + (let ((how (pop arg-list)) + (sym (pop arg-list))) + (push (cons how sym) advice))) + ;; What's left of `arg-list' is the body of the defun. + (list docstring advice arg-list))) + +(defmacro syd-defadvice (name params &rest args) + "Define a function and add it as advice." + (declare (indent defun)) + (-let (((docstring advice body) (syd--parse-defadvice-args args))) + `(progn (defun ,name ,params + ,@(-some-> docstring list) + ,@body) + ,@(-map (lambda (arg) + (-let (((how . sym) arg)) + `(advice-add ,sym ,how #',name))) + advice)))) + +;; (syd-defadvice syd-lsp-install-server-a () +;; :override #'lsp-install-server +;; (user-error (concat "Ignoring a call to `lsp-install-server'" +;; " — tell the caller to use Nix!"))) + +(provide 'syd/init/prelude) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/40-evil.el b/modules/home/users/msyds/emacs/lisp/syd/init/40-evil.el new file mode 100644 index 0000000..cd5d138 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/40-evil.el @@ -0,0 +1,358 @@ +;;; -*- lexical-binding: t; -*- + +;;; 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 + :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 + ;; 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" "[" "]" ""))) + + (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)) + +;; 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/init/evil) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/50-comint.el b/modules/home/users/msyds/emacs/lisp/syd/init/50-comint.el new file mode 100644 index 0000000..a3168f0 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/50-comint.el @@ -0,0 +1,24 @@ +;;; -*- lexical-binding: t; -*- + +(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)) + +(provide 'syd/init/comint) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/50-default-frame.el b/modules/home/users/msyds/emacs/lisp/syd/init/50-default-frame.el new file mode 100644 index 0000000..53c445d --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/50-default-frame.el @@ -0,0 +1,15 @@ +;;; -*- lexical-binding: t; -*- + +(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-configure-default-frame-h)) + +(provide 'syd/init/default-frame) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/50-emacs-lisp-mode.el b/modules/home/users/msyds/emacs/lisp/syd/init/50-emacs-lisp-mode.el new file mode 100644 index 0000000..413d908 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/50-emacs-lisp-mode.el @@ -0,0 +1,5 @@ +(with-eval-after-load 'evil-surround + ;; In Elisp, `' is a much more common pair than ``. + (add-hook 'emacs-lisp-mode-hook + (lambda () + (push '(?` . ("`" . "'")) evil-surround-pairs-alist)))) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/50-fonts.el b/modules/home/users/msyds/emacs/lisp/syd/init/50-fonts.el new file mode 100644 index 0000000..61932d5 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/50-fonts.el @@ -0,0 +1,35 @@ +;;; -*- lexical-binding: t; -*- + +(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'.") + +(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)))) + +(let ((hook (if (daemonp) + 'server-after-make-frame-hook + 'after-init-hook))) + (add-hook hook #'syd-init-fonts-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")) + +(provide 'syd/init/fonts) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/50-kanagawa.el b/modules/home/users/msyds/emacs/lisp/syd/init/50-kanagawa.el new file mode 100644 index 0000000..290ad75 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/50-kanagawa.el @@ -0,0 +1,7 @@ +;;; syd-ui.el -*- lexical-binding: t; -*- + +(use-package kanagawa-themes + :config + (load-theme 'kanagawa-wave t)) + +(provide 'syd/init/kanagawa) diff --git a/modules/home/users/msyds/emacs/lisp/syd/init/50-ui.el b/modules/home/users/msyds/emacs/lisp/syd/init/50-ui.el new file mode 100644 index 0000000..a05285c --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/init/50-ui.el @@ -0,0 +1,44 @@ +;;; -*- lexical-binding: t; -*- + +(syd-add-hook 'prog-mode-hook + ;; Display (relative) line numbers only in prog-mode derivatives. + (defun syd-prog-mode-line-numbers-h () + (display-line-numbers-mode 1))) + +(setq 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)) + +;; Disable the menu bar, scroll bar, and tool bar. +(menu-bar-mode -1) +(scroll-bar-mode -1) +(tool-bar-mode -1) + +;; Remember allowed risky variabled. +(advice-add 'risky-local-variable-p :override #'ignore) + +(provide 'syd/init/ui) diff --git a/modules/home/users/msyds/emacs/lisp/syd/kanagawa.el b/modules/home/users/msyds/emacs/lisp/syd/kanagawa.el new file mode 100644 index 0000000..94a1514 --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/kanagawa.el @@ -0,0 +1,133 @@ +;;; -*- lexical-binding: t; -*- + +;;; Rationale: I need direct access to the Kanagawa palette, which kanagawa.el +;;; does not provide. + +(defvar syd-kanagawa-palette (make-hash-table :test 'eq :size 130)) + +(defvar syd-kanagawa-palette-list + '((sumi-ink-0 "#16161D") + (sumi-ink-1 "#181820") + (sumi-ink-2 "#1a1a22") + (sumi-ink-3 "#1F1F28") + (sumi-ink-4 "#2A2A37") + (sumi-ink-5 "#363646") + (sumi-ink-6 "#54546D") ; fg + + ;; Popup and Floats + (wave-blue-1 "#223249") + (wave-blue-2 "#2D4F67") + + ;; Diff and Git + (winter-green "#2B3328") + (winter-yellow "#49443C") + (winter-red "#43242B") + (winter-blue "#252535") + (autumn-green "#76946A") + (autumn-red "#C34043") + (autumn-yellow "#DCA561") + + ;; Diag + (samurai-red "#E82424") + (ronin-yellow "#FF9E3B") + (wave-aqua-1 "#6A9589") + (dragon-blue "#658594") + + ;; Fg and Comments + (old-white "#C8C093") + (fuji-white "#DCD7BA") + (fuji-gray "#727169") + + (oni-violet "#957FB8") + (oni-violet-2 "#b8b4d0") + (crystal-blue "#7E9CD8") + (spring-violet-1 "#938AA9") + (spring-violet-2 "#9CABCA") + (spring-blue "#7FB4CA") + (light-blue "#A3D4D5") + (wave-aqua-2 "#7AA89F") ;; improve lightness: desaturated greenish Aqua + + (spring-green "#98BB6C") + (boat-yellow-1 "#938056") + (boat-yellow-2 "#C0A36E") + (carp-yellow "#E6C384") + + (sakura-pink "#D27E99") + (wave-red "#E46876") + (peach-red "#FF5D62") + (surimi-orange "#FFA066") + (katana-gray "#717C7C") + + (dragon-black-0 "#0d0c0c") + (dragon-black-1 "#12120f") + (dragon-black-2 "#1D1C19") + (dragon-black-3 "#181616") + (dragon-black-4 "#282727") + (dragon-black-5 "#393836") + (dragon-black-6 "#625e5a") + + (dragon-white "#c5c9c5") + (dragon-green "#87a987") + (dragon-green-2 "#8a9a7b") + (dragon-pink "#a292a3") + (dragon-orange "#b6927b") + (dragon-orange-2 "#b98d7b") + (dragon-gray "#a6a69c") + (dragon-gray1 "#9e9b93") + (dragon-gray-3 "#7a8382") + (dragon-blue-2 "#8ba4b0") + (dragon-violet "#8992a7") + (dragon-red "#c4746e") + (dragon-aqua "#8ea4a2") + (dragon-ash "#737c73") + (dragon-teal "#949fb5") + (dragon-yellow "#c4b28a") + + (lotus-ink-1 "#545464") + (lotus-ink-2 "#43436c") + (lotus-gray "#dcd7ba") + (lotus-gray-2 "#716e61") + (lotus-gray-3 "#8a8980") + (lotus-white-0 "#d5cea3") + (lotus-white-1 "#dcd5ac") + (lotus-white-2 "#e5ddb0") + (lotus-white-3 "#f2ecbc") + (lotus-white-4 "#e7dba0") + (lotus-white-5 "#e4d794") + (lotus-violet-1 "#a09cac") + (lotus-violet-2 "#766b90") + (lotus-violet-3 "#c9cbd1") + (lotus-violet-4 "#624c83") + (lotus-blue-1 "#c7d7e0") + (lotus-blue-2 "#b5cbd2") + (lotus-blue-3 "#9fb5c9") + (lotus-blue-4 "#4d699b") + (lotus-blue-5 "#5d57a3") + (lotus-green "#6f894e") + (lotus-green-2 "#6e915f") + (lotus-green-3 "#b7d0ae") + (lotus-pink "#b35b79") + (lotus-orange "#cc6d00") + (lotus-orange2 "#e98a00") + (lotus-yellow "#77713f") + (lotus-yellow-2 "#836f4a") + (lotus-yellow-3 "#de9800") + (lotus-yellow-4 "#f9d791") + (lotus-red "#c84053") + (lotus-red-2 "#d7474b") + (lotus-red-3 "#e82424") + (lotus-red-4 "#d9a594") + (lotus-aqua "#597b75") + (lotus-aqua-2 "#5e857a") + (lotus-teal-1 "#4e8ca2") + (lotus-teal-2 "#6693bf") + (lotus-teal-3 "#5a7785") + (lotus-cyan "#d7e3d8"))) + +(cl-loop for (k v) in syd-kanagawa-palette-list + do (puthash k v syd-kanagawa-palette)) + +(defun syd-kanagawa-get (k) + (gethash k syd-kanagawa-palette nil)) + +(provide 'syd/kanagawa) diff --git a/users/crumb/default.nix b/users/crumb/default.nix index 1ce1e66..948b5f0 100755 --- a/users/crumb/default.nix +++ b/users/crumb/default.nix @@ -21,6 +21,7 @@ gpg.enable = true; xdg.enable = true; slippi.enable = true; + openutau.enable = true; sops = { enable = true; keyFile = "/persist/private-keys/age/${config.home.username}";