#+begin_src emacs-lisp :comments no ;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- #+end_src * Personal information #+begin_src emacs-lisp (setq user-full-name "Óscar Nájera" user-mail-address "hi@oscarnajera.com") #+end_src * Editor ** Theme #+begin_src emacs-lisp (setq doom-font (font-spec :family "DejaVu Sans Mono" :size 18 :weight 'semi-light)) (setq doom-theme 'doom-gruvbox) (add-hook 'prog-mode-hook 'prettify-symbols-mode) (defun on/prettify-symbols () "Common added symbols." (mapc (lambda (p) (cl-pushnew p prettify-symbols-alist :test #'equal)) '(("<=" . ?≤) (">=" . ?≥) ("->" . ?→) ("->>" . ?↠) ("=>" . ?⇒) ("/=" . ?≠) ("!=" . ?≠) ("::" . ?∷) ("lambda" . ?λ)))) (add-hook 'prog-mode-hook 'on/prettify-symbols) #+end_src This determines the style of line numbers in effect. If set to `nil', line numbers are disabled. For relative line numbers, set this to `relative'. #+begin_src emacs-lisp ;(setq display-line-numbers-type 'relative) #+end_src ** Frame title includes visited file #+BEGIN_SRC emacs-lisp ;;http://emacs-fu.blogspot.fr/2011/01/setting-frame-title.html (setq frame-title-format '("" invocation-name ": "(:eval (if (buffer-file-name) (abbreviate-file-name (buffer-file-name)) "%b")))) #+END_SRC ** Keybindings #+begin_src emacs-lisp (map! :leader :desc "M-x" "x" #'execute-extended-command ) (after! evil (setq evil-default-state 'emacs) (set-evil-initial-state! '(prog-mode text-mode fundamental-mode conf-mode pass-view-mode) 'normal)) #+end_src ** Package Manager Doom manages packages separately. Keep that file separate #+begin_src emacs-lisp :tangle "packages.el" ;; -*- no-byte-compile: t; -*- ;;; $DOOMDIR/packages.el #+end_src ** SSH agent #+begin_src emacs-lisp (setenv "SSH_AUTH_SOCK" (concat (getenv "XDG_RUNTIME_DIR")"/gnupg/S.gpg-agent.ssh")) #+end_src ** Avy This allows me to jump to buffer positions using my home row ordering #+begin_src emacs-lisp (after! avy (setq avy-all-windows t avy-all-windows-alt nil) (setq avy-keys '(?r ?t ?i ?e ?a ?o ?n ?s))) #+end_src ** Ace window #+begin_src emacs-lisp (after! ace-window (global-set-key (kbd "s-w") 'evil-window-map) (setq aw-keys '(?r ?t ?i ?e ?a ?o ?n ?s))) #+end_src ** Which-key Because I always need help and it should come up quickly #+begin_src emacs-lisp (setq which-key-idle-delay 0.1) #+end_src ** Smartparens #+begin_src emacs-lisp (after! smartparens (map! :map smartparens-mode-map :nvie "C-)" #'sp-forward-slurp-sexp :nvie "C-}" #'sp-forward-barf-sexp :nvie "C-(" #'sp-backward-slurp-sexp :nvie "C-{" #'sp-backward-barf-sexp :nie "M-s" #'sp-split-sexp :nie "M-j" #'sp-join-sexp) (map! :map (emacs-lisp-mode-map scheme-mode-map lisp-mode-map clojure-mode-map) :nv ")" #'sp-next-sexp :nv "(" #'sp-backward-sexp)) #+end_src ** View emacs structures #+begin_src emacs-lisp (defun on/display-obj (obj) "Display in new buffer the given OBJ pretty printed." (with-current-buffer (get-buffer-create "*Lisp Display*") (erase-buffer) (pp obj (current-buffer)) (emacs-lisp-mode) (display-buffer (current-buffer)))) #+end_src #+begin_src emacs-lisp (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) #+end_src * Dictionary #+begin_src emacs-lisp :tangle "packages.el" (package! lexic) #+end_src Shamelessly copied from https://tecosaur.github.io/emacs-config/#dictionary #+begin_src emacs-lisp (use-package! lexic :commands lexic-search lexic-list-dictionary) #+end_src #+begin_src emacs-lisp (defadvice! +lookup/dictionary-definition-lexic (identifier &optional arg) "Look up the definition of the word at point (or selection) using `lexic-search'." :override #'+lookup/dictionary-definition (interactive (list (or (doom-thing-at-point-or-region 'word) (read-string "Look up in dictionary: ")) current-prefix-arg)) (lexic-search identifier nil nil t)) #+end_src * Orgmode #+begin_src emacs-lisp (after! org (setq org-tags-column (- fill-column)) (setcdr (assoc "j" org-capture-templates) '("Journal" entry (file+olp+datetree +org-capture-journal-file) "* %(format-time-string \"%H:%M\") %?\n%a\n%i" :clock-in t :clock-resume t)) (add-to-list 'org-capture-templates `("e" "Event" entry (file ,(expand-file-name "caldav.org" org-directory)) "* %?\n%^T\n%i\n%a")) (setq org-roam-capture-templates '(("d" "default" plain "%i\n%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}") :unnarrowed t)) org-roam-capture-ref-templates org-roam-capture-templates)) (use-package! semantic-search :after org :load-path "~/dev/dotfiles/scratch/semgrep" :commands (semantic-search) :config (setq semantic-server-url "http://localhost:8080")) #+end_src ** Alerts This is to set the reminders of calendar events. Using appt is quite fine. I get a remainder just above the minibuffer There is no loud sound or anything disturbing, just the appearance of this new window. #+BEGIN_SRC emacs-lisp (after! org-agenda (setq appt-display-mode-line t ;; show in the modeline appt-display-format 'echo) ;; use our func (run-at-time "5 minutes" (* 3600 2) 'org-agenda-to-appt) (appt-activate 1) ;; active appt (appointment notification) (display-time) ;; time display is required for this... ;; update appt each time agenda opened (add-hook 'org-agenda-finalize-hook 'org-agenda-to-appt)) #+END_SRC ** Calendar sync #+begin_src emacs-lisp (use-package! cal-sync :load-path "~/dev/org-caldav" :commands (cal-sync-push cal-sync-import-file cal-sync-delete on/calendar-fetch) :init (map! :leader (:prefix-map "mc" "p" #'cal-sync-push "f" #'cal-sync-import-file)) :config (defun on/calendar-fetch () (interactive) (call-process "org_agenda_sync" nil (list :file (expand-file-name "~/org/caldav.org")) nil "--format" "org")) (setq cal-sync-url "https://oscar@cloud.oscarnajera.com/remote.php/dav/calendars/oscar" cal-sync-calendar-id "personal-1" org-icalendar-date-time-format ":%Y%m%dT%H%M%SZ")) #+end_src ** References #+begin_src emacs-lisp :tangle "packages.el" (package! helm-bibtex) (package! org-ref) #+end_src #+begin_src emacs-lisp (use-package! helm-bibtex :commands helm-bibtex :after org :init (setq bibtex-completion-bibliography (expand-file-name "biblio.bib" org-directory) bibtex-completion-pdf-field "file" bibtex-completion-library-path (expand-file-name "bibtex-pdf/" org-directory) bibtex-completion-notes-path (expand-file-name "roam/" org-directory) bibtex-completion-notes-template-multiple-files "#+TITLE: ${title} (${year})\n#+author: ${author-or-editor}\n") :config (defun bibtex-completion-open-notes-and-pdf (keys) (bibtex-completion-open-pdf keys) (bibtex-completion-edit-notes keys)) (helm-bibtex-helmify-action bibtex-completion-open-notes-and-pdf helm-bibtex-open-notes-and-pdf) ;(helm-delete-action-from-source "Edit notes with PDF" helm-source-bibtex) (helm-add-action-to-source "Edit notes with PDF" 'helm-bibtex-open-notes-and-pdf helm-source-bibtex 1)) (use-package! org-ref :after helm-bibtex) #+end_src ** Letters #+BEGIN_SRC emacs-lisp (use-package ox-latex :ensure org :after org :config ;; APS journals (add-to-list 'org-latex-classes '("revtex4-1" "\\documentclass{revtex4-1} [PACKAGES] [EXTRA]" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) (eval-after-load 'ox '(require 'ox-koma-letter)) (add-to-list 'org-latex-packages-alist '("AUTO" "babel" nil)) ) #+END_SRC ** Feeds #+begin_src emacs-lisp (after! elfeed (setq elfeed-feeds '("http://feeds.feedburner.com/MeltingAsphalt" "http://feeds.feedburner.com/TroyHunt" "http://kitchingroup.cheme.cmu.edu/blog/feed/index.xml" "http://www.howardism.org/index.xml" "https://ag91.github.io/rss.xml" "https://architectelevator.com/feed.xml" "https://bitcoinops.org/feed.xml" "https://cyberwardog.blogspot.com/feeds/posts/default" "https://daryl.wakatara.com/rss.xml" "https://guix.gnu.org/feeds/blog.atom" "https://hboeck.de/rss.xml" "https://jackrusher.com/feed.xml" "https://nullprogram.com/feed/" "https://oscarnajera.com/post/index.xml" "https://paulstamatiou.com/posts.xml" "https://planet.archlinux.org/atom.xml" "https://reyify.com/api/rss" "https://sachachua.com/blog/feed" "https://serokell.io/blog.rss.xml" "https://stevelosh.com/rss.xml" "https://www.archlinux.org/feeds/news/" "https://www.n16f.net/blog/index.xml" "https://www.schneier.com/feed/atom" "https://www.tweag.io/rss.xml"))) #+end_src * Email ** Notmuch #+begin_src emacs-lisp :tangle "packages.el" (package! notmuch :pin "c769658360e10a6d01a4134e680e2f498741bc5c") (package! org-mime :pin "cc00afcf0291633324364c1c83bfe2833cfdc1bf") (package! ol-notmuch :pin "781c3518a537da2a8b5e8a4424f9441df463a147") #+end_src #+BEGIN_SRC emacs-lisp (use-package! notmuch :init (after! org (add-to-list 'org-modules 'ol-notmuch)) (map! :leader (:prefix-map ("o" . "open") :desc "notmuch" "m" #'notmuch)) :commands notmuch :bind (:map notmuch-hello-mode-map ("l" . notmuch-jump-search) ("/" . notmuch-tree) :map notmuch-search-mode-map ("f" . notmuch-search-filter-by-tag) ("/" . notmuch-tree) ("d" . notmuch-search-delete-thread) ("D" . notmuch-search-delete-all) :map notmuch-show-mode-map ("d" . notmuch-show-delete-message) ("D" . notmuch-show-delete-thread-then-exit) ("i" . notmuch-show-tag-spam) ("cb" . on/notmuch-spam-test) ("cr" . org-store-link) ) :config (set-company-backend! 'notmuch-message-mode 'notmuch-company '(company-ispell company-yasnippet)) (setq-default notmuch-search-oldest-first nil) (setq message-directory "~/.mail/" message-auto-save-directory "/tmp/" org-email-link-description-format "%c: %s") (setq notmuch-saved-searches '((:name "inbox" :query "tag:inbox" :key "i" :sort-order newest-first) (:name "Isar-Speak" :query "(tag:Isar-Speak or tag:lists/isar-speak-officers) and tag:unread" :key "t") (:name "flagged" :query "tag:flagged" :key "f") (:name "sent" :query "tag:sent" :key "s") (:name "unread" :query "tag:unread" :key "u") (:name "drafts" :query "tag:draft" :key "d"))) (setq notmuch-show-all-tags-list t notmuch-hello-tag-list-make-query "tag:unread and not tag:killed") (setq notmuch-fcc-dirs '((".*@oscarnajera.com" . "hi_pers/Sent") ;;(".*@gmail.com" . "\"gmail/[Gmail]/.Sent Mail\"") )) (setq notmuch-crypto-process-mime t) (setq message-kill-buffer-on-exit t) (setq notmuch-archive-tags '("-inbox" "-unread")) (setq notmuch-search-line-faces `(("deleted" . (:strike-through "red")) ("flagged" . notmuch-search-flagged-face) ("unread" . notmuch-search-unread-face))) (add-hook! 'doom-real-buffer-functions (defun notmuch-interesting-buffer (b) "Whether the current buffer's major-mode is a notmuch mode." (with-current-buffer b (memq major-mode '(notmuch-show-mode notmuch-search-mode notmuch-tree-mode notmuch-hello-mode notmuch-message-mode))))) (defun notmuch-toggle-tag (tag tags-present) (concat (if (member tag tags-present) "-" "+") tag)) (defun notmuch-show-delete-message () "Delete current message if already marked as deleted undo." (interactive) (notmuch-show-tag-message (notmuch-toggle-tag "deleted" (notmuch-show-get-tags)))) (defun on/bogofilter (&rest args) "Call bogofilter on current notmuch-show-file with ARGS." (let ((msg-file (notmuch-show-get-filename))) (with-temp-buffer (apply #'call-process "bogofilter" msg-file t nil args) (message (string-trim (buffer-string)))))) (defun on/notmuch-spam-test () "Evaluate spaminess of message." (interactive) (on/bogofilter "-v")) (defun on/bogofilter-set-spam (spam-p) "Set spam or ham depending according to SPAM-P." (on/bogofilter "-v" (if spam-p "-s" "-n"))) (defun notmuch-show-tag-spam () "Tag spam on current message if already marked as spam undo." (interactive) (let ((tag (notmuch-toggle-tag "spam" (notmuch-show-get-tags)))) (notmuch-show-tag-message tag) (on/bogofilter-set-spam (string-prefix-p "+" tag)))) (defun notmuch-show-delete-thread-then-exit () "Delete all messages in the current buffer, then exit back to search results." (interactive) (notmuch-show-tag-all '("+deleted")) (notmuch-show-next-thread)) (defun notmuch-search-delete-thread() "Delete all messages in the current thread or undelete" (interactive) (notmuch-search-tag (list (notmuch-toggle-tag "deleted" (notmuch-search-get-tags))))) (defun notmuch-search-delete-all() "Delete all messages in the current buffer" (interactive) (notmuch-search-tag-all '("+deleted" "-inbox" "-unread"))) (define-key notmuch-tree-mode-map "d" (lambda () "delete message" (interactive) (notmuch-tree-tag (list (notmuch-toggle-tag "deleted" (notmuch-tree-get-tags))))))) (use-package! org-mime :after (org notmuch) :config (setq org-mime-library 'mml)) (require 'comint) (require 'ansi-color) (defun on/registered-mail-accounts () "Read mbsync config to extract IMAPAccounts." (with-temp-buffer (insert-file-contents (expand-file-name "~/.mbsyncrc")) (let ((pick (thread-last (cl-loop while (search-forward-regexp (rx bol "IMAPAccount " (group (+ any)) eol) nil t) collect (match-string 1)) (cons "all") (completing-read "Which mailbox")))) (if (string= pick "all") nil (list pick))))) (define-derived-mode mail-sync-log-mode comint-mode "mail-sync-log" "Major mode for reading mail sync." ;; code for syntax highlighting (setq font-lock-defaults `(((,(rx bol "[" (1+ (or letter space)) "]") . font-lock-warning-face) (,(rx bol " [mv]") . font-lock-constant-face) (,(rx bol " [rm]") . font-lock-keyword-face))))) (defun on/fetch-all-email () "Start tagmail fetch on a subprocess." (interactive) (with-current-buffer (get-buffer-create "*E-mail fetch*") (pop-to-buffer (current-buffer)) (mail-sync-log-mode) (make-process :name "E-mail fetch" :buffer (current-buffer) :command (cons "tagmail" (on/registered-mail-accounts)) :filter #'comint-output-filter))) #+END_SRC ** Sending email #+begin_src emacs-lisp (after! notmuch (setq send-mail-function 'smtpmail-send-it message-send-mail-function 'message-smtpmail-send-it smtpmail-local-domain "oscarnajera.com") (defun set-smtp-server () (-let* (((user host) (thread-first (message-field-value "from" ) (mail-extract-address-components) (cadr) (string-split "@"))) (smtp-servers '("oscarnajera.com" "mail.oscarnajera.com" "gmail.com" "smtp.googlemail.com" "byteplant.com" "smtp.byteplant.com")) ((&plist :host :user :port :secret) (car (auth-source-search :host (or (plist-get smtp-servers host #'string=) "mail.oscarnajera.com") :user user :max 1)))) (setq smtpmail-smtp-server host smtpmail-smtp-service (string-to-number port) smtpmail-stream-type 'starttls smtpmail-smtp-user user) (message "SMTP server changed to %s %s %s" host port user))) (add-hook 'message-send-mail-hook 'set-smtp-server)) #+end_src ** Contacts #+begin_src emacs-lisp :tangle "packages.el" (package! khardel) #+end_src #+begin_src emacs-lisp (use-package! khardel) #+end_src * IRC #+begin_src emacs-lisp (set-irc-server! "irc.libera.chat" `(:tls t :port 6697 :nick "titan-c" :sasl-username ,(+pass-get-user "Social/freenode/titan-c") :sasl-password (lambda (&rest _) (+pass-get-secret "Social/freenode/titan-c")) :channels ("#emacs" "#guix"))) #+end_src #+RESULTS: * Ledger Emacs mode for managing ledger text files #+BEGIN_SRC emacs-lisp (after! ledger-mode (setq ledger-default-date-format ledger-iso-date-format) (defun on/ledger-link-invoice () "Attach an invoice file to this posting." (interactive) (ledger-navigate-beginning-of-xact) (end-of-line) (when-let* ((date (ledger-xact-date)) (payee (thread-last (ledger-xact-payee) (string-trim) (replace-regexp-in-string (rx (+ (or space punctuation))) "_"))) (src-file (read-file-name "Attach: ")) (file-name (concat "Empresa_DE/" date "_" payee "." (file-name-extension src-file)))) (insert "\n ; Invoice: " file-name) (rename-file src-file (expand-file-name file-name))))) #+end_src ** CSV #+begin_src emacs-lisp :tangle "packages.el" (package! parse-csv) #+end_src ** Crypto #+begin_src emacs-lisp (use-package! cardano-tx :commands (cardano-tx-new cardano-tx-cli-tip) :load-path "~/dev/cardano/emacs-wallet" :init (defun on/cardano-set-network () (interactive) (let* ((networks '((:mainnet "/run/cardano-node-mainnet/socket" "http://localhost:8090" "--mainnet") (:preview "/run/cardano-node-preview/socket" "http://localhost:8091" "--testnet-magic" "2"))) (pick (alist-get (completing-read "Pick network" networks) networks nil nil #'string=))) (setq cardano-tx-cli-node-socket (expand-file-name (car pick)) cardano-wallet-url (cadr pick) cardano-tx-cli-network-args (cddr pick)))) :config (add-hook! 'doom-real-buffer-functions (defun cardano-interesting-buffer (b) "Whether the current buffer's major-mode is a cardano mode." (with-current-buffer b (memq major-mode '(cardano-tx-db-addresses-mode cardano-tx-db-files-mode cardano-tx-mode cardano-wallet-tx-log-mode))))) (setq cardano-tx-log-level 'debug) ;; (setq cardano-cli-command (expand-file-name "~/dev/cardano/cardano-node/cli")) (setq cardano-tx-cli-command "/usr/bin/cardano-cli") (setq cardano-tx-db-keyring-dir "~/dev/cardano/emacs-wallet/keys/demo")) (use-package! cardano-wallet :commands (cardano-wallet-balances) :load-path "~/dev/cardano/emacs-wallet") #+end_src #+RESULTS: * Books #+begin_src emacs-lisp :tangle "packages.el" (package! nov) (package! calibredb) #+end_src #+begin_src emacs-lisp (use-package! nov :mode (("\\.epub\\'" . nov-mode))) (use-package! calibredb :commands calibredb :config (setq calibredb-root-dir "/run/media/titan/ext_backup/personal/Libros/CalibreManaged") (setq calibredb-db-dir (expand-file-name "metadata.db" calibredb-root-dir))) #+end_src * Programming languages ** YAML #+begin_src emacs-lisp :tangle "packages.el" (package! yaml) #+end_src #+begin_src emacs-lisp (use-package! libyaml :commands yaml-read-file :load-path "~/dev/emacs-lisp/emacs-libyaml/") (use-package! yaml) #+end_src ** Databases #+begin_src emacs-lisp :tangle "packages.el" (package! emacsql-psql) #+end_src #+begin_src emacs-lisp (after! format-all (define-format-all-formatter sqlformat (:executable "pg_format") (:install) (:modes sql-mode) (:format (format-all--buffer-easy executable "-s2" "-g" "-U2" "-")))) #+end_src ** WEB #+begin_src emacs-lisp :tangle "packages.el" (package! impatient-mode) #+end_src #+begin_src emacs-lisp (after! skewer-mode (setq httpd-port 8095)) (use-package! impatient-mode :commands impatient-mode) (use-package! trident-mode :commands trident-mode :load-path "~/dev/emacs-lisp/trident-mode.el/") #+end_src ** Haskell #+begin_src emacs-lisp (after! haskell-mode (setq-hook! 'haskell-mode-hook +format-with :none) (setq haskell-stylish-on-save t lsp-haskell-formatting-provider "stylish-haskell")) #+end_src ** Clojure #+begin_src emacs-lisp (setq-hook! 'clojure-mode-hook +format-with :none) #+end_src ** Common Lisp #+begin_src emacs-lisp (after! sly (setq sly-lisp-implementations '((sbcl-large ("sbcl" "--dynamic-space-size" "2048")) (sbcl ("sbcl"))))) #+end_src ** C #+begin_src emacs-lisp (after! lsp-clangd (setq lsp-clients-clangd-args '("-j=3" "--background-index" "--clang-tidy" "--completion-style=detailed" "--header-insertion=never" "--header-insertion-decorators=0")) (set-lsp-priority! 'clangd 2)) #+end_src * Video Editing #+begin_src emacs-lisp :tangle "packages.el" (package! subed :recipe (:host github :repo "sachac/subed" :files ("subed/*.el"))) #+end_src #+begin_src emacs-lisp (use-package! subed) #+end_src * Admin #+begin_src emacs-lisp :tangle "packages.el" (package! guix) #+end_src #+begin_src emacs-lisp (use-package! guix) #+end_src #+begin_src emacs-lisp :tangle "packages.el" (package! json-rpc) #+end_src #+begin_src emacs-lisp (use-package! btc-explorer :load-path "~/dev/emacs-lisp/btc-explorer/" :commands (on/bitcoin-rpc-connect) :config (use-package json-rpc) (defun on/bitcoin-rpc-connect () (interactive) (let* ((networks '(:mainnet 8332 :mainnet-r 8335 :testnet 18332 :testnet-r 18335 :regtest 18443)) (host "localhost") (user "crazy") (port (plist-get networks (intern (completing-read "Pick network: " networks)))) (secret (-some-> (auth-source-search :host host) (car) (plist-get :secret)))) (when (and btc-explorer-bitcoind (json-rpc-live-p btc-explorer-bitcoind)) (json-rpc-close btc-explorer-bitcoind)) (setq btc-explorer-bitcoind (json-rpc-connect host port user (funcall secret)))))) (use-package! lnd :load-path "~/dev/emacs-lisp/btc-explorer/" :commands (lnd-pick-node) :config (setq lnd-nodes '(("local" "https://localhost:8480/v1/" "/run/media/titan/ext_backup/personal/bitcoin/lnd/data/chain/bitcoin/testnet/admin.macaroon") ("remote" "https://localhost:8481/v1/" "~/dev/emacs-lisp/btc-explorer/admin.macaroon")))) #+end_src #+begin_src emacs-lisp (use-package! shepherd :load-path "~/dev/dotfiles/elisp/" :commands (shepherd)) #+end_src #+begin_src emacs-lisp (use-package! mpc) #+end_src #+begin_src emacs-lisp (use-package! journalctl :load-path "~/dev/dotfiles/elisp" :commands (journalctl)) #+end_src #+begin_src emacs-lisp (setq netstat-program-options '("-aptu")) #+end_src