summaryrefslogtreecommitdiff
path: root/config/emacs.scm
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2026-04-05 12:52:04 -0400
committerRobby Zambito <contact@robbyzambito.me>2026-04-05 12:55:17 -0400
commit75a24d542a2f358eec68d98f3c65d32437bf0c8e (patch)
tree13a90980d1c4149fb596b8cbf171621f44a0ca08 /config/emacs.scm
parent8cc138dfbbb13fad87acea77abfc085f3a73fc63 (diff)
refactor: move emacs config to separate package
Diffstat (limited to 'config/emacs.scm')
-rw-r--r--config/emacs.scm433
1 files changed, 433 insertions, 0 deletions
diff --git a/config/emacs.scm b/config/emacs.scm
new file mode 100644
index 0000000..13e5773
--- /dev/null
+++ b/config/emacs.scm
@@ -0,0 +1,433 @@
+(define-library (config emacs)
+ (export emacs-config)
+ (import (scheme base)
+ (scheme write)
+ (gnu packages)
+ (guix packages)
+ (guix derivations)
+ (guix store)
+ (guix transformations)
+ (config-generation sexp)))
+
+(begin
+ (define emacs-config
+ (string-append
+ ";; See /home/robby/.config/guix-home/home-configuration.scm\n"
+ (scm->string
+ ;; Load the secrets file
+ `((when (not (load "/home/robby/.config/emacs/secrets.el"))
+ (message "could not load secrets!"))
+
+ ;; Load the Nord theme when launching an emacsclient GUI
+ (if (daemonp)
+ (add-hook 'after-make-frame-functions
+ (lambda (frame)
+ (with-selected-frame
+ frame
+ (load-theme 'nord t))))
+ (load-theme 'nord t))
+
+ ;; Safe variables
+ (custom-set-variables
+ ;; custom-set-variables was added by Custom.
+ ;; If you edit it by hand, you could mess it up, so be careful.
+ ;; Your init file should contain only one such instance.
+ ;; If there is more than one, they won't work right.
+ '(safe-local-variable-values
+ '((auto-save-default)
+ (org-download-image-dir . "~/org/pictures")
+ (eval progn
+ (require 'lisp-mode)
+ (defun emacs27-lisp-fill-paragraph
+ (&optional justify)
+ (interactive "P")
+ (or
+ (fill-comment-paragraph justify)
+ (let
+ ((paragraph-start
+ (concat paragraph-start "\\|\\s-*\\([(;\"]\\|\\s-:\\|`(\\|#'(\\)"))
+ (paragraph-separate
+ (concat paragraph-separate "\\|\\s-*\".*[,\\.]$"))
+ (fill-column
+ (if
+ (and
+ (integerp emacs-lisp-docstring-fill-column)
+ (derived-mode-p 'emacs-lisp-mode))
+ emacs-lisp-docstring-fill-column fill-column)))
+ (fill-paragraph justify))
+ t))
+ (setq-local fill-paragraph-function
+ (syntax emacs27-lisp-fill-paragraph)))
+ (eval modify-syntax-entry 43 "'")
+ (eval modify-syntax-entry 36 "'")
+ (eval modify-syntax-entry 126 "'")
+ (eval let
+ ((root-dir-unexpanded
+ (locate-dominating-file default-directory ".dir-locals.el")))
+ (when root-dir-unexpanded
+ (let*
+ ((root-dir
+ (file-local-name
+ (expand-file-name root-dir-unexpanded)))
+ (root-dir*
+ (directory-file-name root-dir)))
+ (unless
+ (boundp 'geiser-guile-load-path)
+ (defvar geiser-guile-load-path 'nil))
+ (make-local-variable 'geiser-guile-load-path)
+ (require 'cl-lib)
+ (cl-pushnew root-dir* geiser-guile-load-path :test
+ (syntax string-equal)))))
+ (eval with-eval-after-load 'yasnippet
+ (let
+ ((guix-yasnippets
+ (expand-file-name "etc/snippets/yas"
+ (locate-dominating-file default-directory ".dir-locals.el"))))
+ (unless
+ (member guix-yasnippets yas-snippet-dirs)
+ (add-to-list 'yas-snippet-dirs guix-yasnippets)
+ (yas-reload-all))))
+ (eval setq-local guix-directory
+ (locate-dominating-file default-directory ".dir-locals.el"))
+ (eval add-to-list 'completion-ignored-extensions ".go"))))
+
+ ;; Do not open windows in the same Emacs frame.
+ ;; (setq pop-up-frames 'graphic-only)
+
+ (setq inferior-lisp-program "/home/robby/.guix-home/profile/bin/sbcl")
+
+ ;; Enable which-key mode
+ (which-key-mode)
+
+ ;; Automatically create closing pairs
+ (electric-pair-mode 1)
+
+ ;; Show matching parenthesis
+ (show-paren-mode 1)
+ (setq show-paren-delay 0)
+
+ ;; Hide the tool bar
+ (tool-bar-mode -1)
+
+ ;; Hide the menu bar
+ (menu-bar-mode -1)
+
+ ;; Hide the scroll bar
+ (scroll-bar-mode -1)
+
+ ;; Highlight the current line
+ (global-hl-line-mode 1)
+
+ ;; Enable line numbers
+ (global-display-line-numbers-mode)
+ (setq display-line-numbers-type 'relative)
+
+ ;; Disable line numbers for certain modes
+ (add-hook 'eshell-mode-hook (lambda () (display-line-numbers-mode -1)))
+
+ ;; Show the column number
+ (setq column-number-mode t)
+
+ ;; Add e as an alias for find-file. Useful for eshell.
+ (defalias 'e (function find-file))
+
+ ;; Eshell visual commands
+ (setq eshell-visual-subcommands '(("guix" "search")
+ ("pipe-viewer")
+ ("keepassxc-cli" "open")))
+
+ ;; Open init file
+ (defun open-init-file ()
+ "Open the init file."
+ (interactive)
+ (find-file "~/src/guix-dotfiles/home.scm"))
+
+ (global-set-key (kbd "C-x i") 'open-init-file)
+
+ ;; Function to create a new eshell. Used for Sway binding.
+ (defvar next-eshell -1)
+ (defun new-eshell ()
+ (setq next-eshell (+ 1 next-eshell))
+ (eshell next-eshell))
+
+ ;; Power
+ (defun eshell/poweroff ()
+ "Shutdown the computer."
+ (call-process "loginctl" null-device nil nil "poweroff"))
+
+ (defun eshell/reboot ()
+ "Reboot the computer."
+ (call-process "loginctl" null-device nil nil "reboot"))
+
+ ;; For using tramp guix->guix
+ (require 'tramp)
+ ;; (setq tramp-remote-path
+ ;; (append tramp-remote-path
+ ;; '(tramp-own-remote-path)))
+
+ ;; Scheme extra file extensions
+ (setq auto-mode-alist (append '(("\\.sld\\'" . scheme-mode)) auto-mode-alist))
+
+ ;; Code folding
+ ;; (require 'origami)
+ ;; Add mode hooks
+ ;; (dolist (mode '(nxml-mode-hook csharp-mode-hook c-mode-hook scheme-mode-hook emacs-lisp-mode-hook))
+ ;; (add-hook mode 'origami-mode))
+ ;; Specify extra parsers
+ ;; (dolist (parser-pair '((scheme-mode . origami-elisp-parser) (csharp-mode . origami-c-style-parser)))
+ ;; (add-to-list 'origami-parser-alist parser-pair))
+ ;; (define-key origami-mode-map (kbd "<C-tab>") 'origami-recursively-toggle-node)
+
+ ;;; Org mode config
+ (require 'org-download)
+ (setq org-startup-with-inline-images t)
+ (add-hook 'org-mode-hook 'org-indent-mode)
+ (add-hook 'org-mode-hook 'toc-org-mode)
+
+ ;; Org bullets
+ (require 'org-bullets)
+ (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
+
+ ;; Org babel language support
+ (org-babel-do-load-languages
+ 'org-babel-load-languages
+ '((emacs-lisp . t)
+ (eshell . t)
+ (C . t)
+ (scheme . t)))
+
+ ;; Org link abbreviations
+ (setq org-link-abbrev-alist
+ '(("wikipedia" . "https://en.wikipedia.org/wiki/")
+ ("wiki" . "https://wiki.zambito.xyz/index.php?title=")
+ ("gh" . "https://github.com/")
+ ("guix" . "elisp:(guix-packages-by-name \"%s\")")
+ ("isbn" . "https://www.bookfinder.com/isbn/")
+ ("man" . "elisp:(man \"%s\")")))
+
+ ;; Org roam
+ (require 'org-roam)
+ (setq org-roam-directory "~/org"
+ org-roam-capture-templates '(("d" "default" plain
+ "%?"
+ :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}")
+ :unnarrowed t)
+ ("p" "person" plain
+ (file "~/org/templates/person.org")
+ :target (file "%<%Y%m%d%H%M%S>-${slug}.org")
+ :unnarrowed t)
+ ("b" "book" plain
+ (file "~/org/templates/book.org")
+ :target (file "%<%Y%m%d%H%M%S>-${slug}.org")
+ :unnarrowed t))
+ org-roam-dailies-capture-templates '(("d" "default" entry "* %?"
+ :target (file+head "%<%Y-%m-%d>.org"
+ "#+title: %<%Y-%m-%d>\n"))
+ ("v" "Value" entry "* %?"
+ :target (file+head+olp "%<%Y-%m-%d>.org"
+ "#+title: %<%Y-%m-%d>\n"
+ ("What do I value?")))
+ ("t" "Trajectory" entry "* %?"
+ :target (file+head+olp "%<%Y-%m-%d>.org"
+ "#+title: %<%Y-%m-%d>\n"
+ ("What is my trajectory today?")))))
+ (add-to-list 'org-roam-file-exclude-regexp "par/")
+ (org-roam-db-autosync-enable)
+ (global-set-key (kbd "C-c n i") 'org-roam-node-insert)
+ (global-set-key (kbd "C-c n f") 'org-roam-node-find)
+ (global-set-key (kbd "C-c n r") 'org-roam-node-random)
+ (global-set-key (kbd "C-c n t") 'org-roam-buffer-toggle)
+ (global-set-key (kbd "C-c d c t") 'org-roam-dailies-capture-today)
+ (global-set-key (kbd "C-c d c n") 'org-roam-dailies-capture-tomorrow)
+ (global-set-key (kbd "C-c d c p") 'org-roam-dailies-capture-yesterday)
+ (global-set-key (kbd "C-c d c d") 'org-roam-dailies-capture-date)
+ (global-set-key (kbd "C-c d f t") 'org-roam-dailies-goto-today)
+ (global-set-key (kbd "C-c d f n") 'org-roam-dailies-goto-next-note)
+ (global-set-key (kbd "C-c d f p") 'org-roam-dailies-goto-previous-note)
+ (global-set-key (kbd "C-c d f d") 'org-roam-dailies-goto-date)
+
+ (add-to-list 'load-path "~/src/org-roam-ui/")
+ (require 'org-roam-ui)
+ (setq org-roam-ui-sync-theme t
+ org-roam-ui-follow t
+ org-roam-ui-update-on-save t
+ org-roam-ui-open-on-start nil)
+ (org-roam-ui-mode 1)
+
+ ;; Emojify
+ (global-emojify-mode 1)
+
+ ;; ERC
+ ;; See: https://gist.github.com/chumpage/1243771
+ (require 'erc-services)
+ (erc-services-mode 1)
+
+ (setq erc-server "irc.libera.chat"
+ erc-nick "Zambyte"
+ erc-port 6697
+ erc-prompt-for-nickserv-password nil
+ erc-prompt-for-password t
+ erc-nickserv-passwords (list (list 'Libera.Chat (list (cons "Zambyte" (cdr (assoc 'libera secrets))))))
+ erc-autojoin-channels-alist '((Libera.Chat "#archlinux"
+ "#c"
+ "#emacs"
+ "#fsf"
+ "#gnu"
+ "#guile"
+ "#guix"
+ "#hurd"
+ "#lisp"
+ "#mastodon"
+ "#pleroma"
+ "#pleroma-dev"
+ "#scheme"
+ "#sway"
+ "#minetest"
+ "#lojban"
+ "#ckule"
+ "#jbosnu"
+ "#proga"
+ "#lowellmakes")))
+
+ ;; Email
+ (require 'mu4e)
+ (setq mu4e-get-mail-command "SSL_CERT_DIR=/home/robby/.guix-profile/etc/ssl/certs mbsync personal")
+ (setq user-full-name "Robby Zambito"
+ user-mail-address "contact@robbyzambito.me"
+ send-mail-function (function smtpmail-send-it)
+ smtpmail-smtp-server "mail.gandi.net"
+ smtpmail-stream-type 'starttls
+ smtpmail-smtp-service 587)
+ (global-set-key (kbd "C-x C-m") 'mu4e)
+
+ ;; Music
+ (emms-all)
+ (setq emms-player-list '(emms-player-mpv)
+ emms-info-functions '(emms-info-native)
+ ;; emms-player-mpv-parameters '("--ao=pipewire")
+ )
+
+ ;; RSS
+ (require 'elfeed)
+ (require 'elfeed-show)
+ (require 'elfeed-org)
+ (elfeed-org)
+ (setq rmh-elfeed-org-files (list "~/org/20230517231456-elfeed.org")
+ elfeed-search-filter "@6-months-ago +unread -reddit -hn -politics")
+
+ ;; TODO: this doesn't work
+ ;; Fixed? TODO: Check if it works
+ (add-hook 'elfeed-mode-hook
+ (lambda ()
+ (define-key elfeed-mode-map "C-c C-u"
+ 'elfeed-update)))
+
+ ;; Source https://github.com/skeeto/elfeed/issues/267
+ (defun elfeed-play-with-mpv ()
+ "Play entry link with mpv."
+ (interactive)
+ (let ((entry (if (eq major-mode 'elfeed-show-mode) elfeed-show-entry (elfeed-search-selected :single)))
+ (quality-arg "")
+ (quality-val (completing-read "Max height resolution (0 for unlimited): " '("0" "480" "720") nil nil)))
+ (setq quality-val (string-to-number quality-val))
+ (message "Opening %s with height≤%s with mpv..." (elfeed-entry-link entry) quality-val)
+ (when (< 0 quality-val)
+ (setq quality-arg (format "--ytdl-format=[height<=?%s]" quality-val)))
+ (start-process "elfeed-mpv" nil "mpv" quality-arg (elfeed-entry-link entry))))
+
+ (defun elfeed-open-with-eww ()
+ "Open in eww with `eww-readable'."
+ (interactive)
+ (let ((entry (if (eq major-mode 'elfeed-show-mode) elfeed-show-entry (elfeed-search-selected :single))))
+ (eww (elfeed-entry-link entry))
+ (add-hook 'eww-after-render-hook 'eww-readable nil t)))
+
+ (defvar elfeed-visit-patterns
+ '(("youtu\\.?be" . elfeed-play-with-mpv)
+ ("v\\.redd\\.it" . elfeed-play-with-mpv)
+ ("reddit" . elfeed-play-with-mpv)
+ ("phoronix" . elfeed-open-with-eww)
+ ("jcs\\.org" . elfeed-play-with-mpv))
+ "List of (regexps . function) to match against elfeed entry link to know
+whether how to visit the link.")
+
+ (defun elfeed-visit-maybe-external ()
+ "Visit with external function if entry link matches `elfeed-visit-patterns',
+visit otherwise."
+ (interactive)
+ (let ((entry (if (eq major-mode 'elfeed-show-mode)
+ elfeed-show-entry
+ (elfeed-search-selected :single)))
+ (patterns elfeed-visit-patterns))
+ (while (and patterns (not (string-match (caar patterns) (elfeed-entry-link entry))))
+ (setq patterns (cdr patterns)))
+ (cond
+ (patterns
+ (elfeed-untag entry 'unread)
+ (elfeed-search-update-entry entry)
+ (funcall (cdar patterns)))
+ ((eq major-mode 'elfeed-search-mode)
+ (call-interactively 'elfeed-search-show-entry))
+ (t (elfeed-show-visit)))))
+
+ ;; https://github.com/skeeto/elfeed/issues/317 and
+ ;; https://github.com/skeeto/elfeed/pull/448#issuecomment-1120336279
+ ;; Speeds up getting elfeed feeds
+ (setq flycheck-global-modes '(not . (elfeed-search-mode)))
+
+ (define-key elfeed-show-mode-map (kbd "<C-return>") 'elfeed-visit-maybe-external)
+ (define-key elfeed-search-mode-map (kbd "<C-return>") 'elfeed-visit-maybe-external)
+ (global-set-key (kbd "C-x w") 'elfeed)
+
+ ;; Pleroma
+ (add-to-list 'load-path "/home/robby/src/mastodon.el/lisp/")
+ (require 'mastodon)
+ (setq mastodon-instance-url "https://zoinks.one"
+ mastodon-active-user "robby")
+
+ ;; Programming
+
+ ;; https://www.youtube.com/watch?v=Vx0bSKF4y78
+ ;; https://github.com/minad/corfu
+ ;; (require 'corfu)
+ ;; (setq corfu-cycle t
+ ;; corfu-auto t
+ ;; corfu-auto-delay 0
+ ;; corfu-quit-no-match 'separator
+ ;; corfu-echo-documentation 0.25
+ ;; corfu-preselect-first nil)
+ ;; (global-corfu-mode)
+ ;; (corfu-history-mode)
+
+ ;; ;; https://github.com/minad/cape
+ ;; (require 'cape)
+ ;; (add-to-list 'completion-at-point-functions (function cape-dabbrev))
+ ;; (add-to-list 'completion-at-point-functions (function cape-file))
+
+ ;; (("C-c p p" . completion-at-point) ;; capf
+ ;; ("C-c p t" . complete-tag) ;; etags
+ ;; ("C-c p d" . cape-dabbrev) ;; or dabbrev-completion
+ ;; ("C-c p h" . cape-history)
+ ;; ("C-c p f" . cape-file)
+ ;; ("C-c p k" . cape-keyword)
+ ;; ("C-c p s" . cape-symbol)
+ ;; ("C-c p a" . cape-abbrev)
+ ;; ("C-c p i" . cape-ispell)
+ ;; ("C-c p l" . cape-line)
+ ;; ("C-c p w" . cape-dict)
+ ;; ("C-c p \\" . cape-tex)
+ ;; ("C-c p _" . cape-tex)
+ ;; ("C-c p ^" . cape-tex)
+ ;; ("C-c p &" . cape-sgml)
+ ;; ("C-c p r" . cape-rfc1345))
+
+ ;; (require 'gptel)
+ ;; (setq gptel-default-mode 'org-mode)
+ ;; (setq gptel-default-mode 'text-mode) ; I cannot use org-mode, as there is a bug: https://github.com/karthink/gptel/issues/81
+ ;; (define-key gptel-mode-map (kbd "C-c RET") 'gptel-send)
+ ;; (define-key gptel-mode-map (kbd "C-c C-<return>") 'gptel-send)
+ ;; (define-key gptel-mode-map (kbd "C-c C-m") 'gptel-menu)
+
+ ))))
+
+ )