Created: July 17, 2018

Last modified: September 16, 2024

emacs configuration

I was using this block to add block to library of babel

(defun my-tangle-init ()
  (mapcar 'org-babel-lob-ingest (directory-files "~/org/config" nil ".*.org"))
  (org-babel-tangle-file "~/org/config/emacs.org"))

But I think this is better:

And really I should see if org upstream would just let file references in non-called noweb references

early-init.el

Take a look at https://github.com/hlissner/doom-emacs/blob/develop/early-init.el

;;; early-init.el -*- lexical-binding: t; -*-

;; A big contributor to startup times is garbage collection. We up the gc
;; threshold to temporarily prevent it from running, then reset it later by
;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
; (setq gc-cons-threshold most-positive-fixnum)

(setq package-enable-at-startup nil)

;(push '(undecorated-round . t) default-frame-alist)
(push '(undecorated . t) default-frame-alist)
(push '(fullscreen . maximized) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
(push '(font . "Menlo 12") default-frame-alist)
  • DejaVu Sans Mono is also a nice font on which Menlo is based

.emacs

header

;; -*- mode: emacs-lisp; lexical-binding: t; -*-
; Do not edit this file directly!
; This file was generated by running ~org-babel-tangle~ on dotfiles.org

elpaca

(setq gc-cons-threshold #x8000000) ;; speed up init load, reset by gmch-mode below

(defvar elpaca-installer-version 0.6)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(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
                              :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 (call-process "git" nil buffer t "clone"
                                       (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)
    (load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))

;; Install use-package support
(elpaca elpaca-use-package
  ;; Enable :elpaca use-package keyword.
  (elpaca-use-package-mode)
  ;; Assume :elpaca t unless otherwise specified.
  (setq elpaca-use-package-by-default t))

;; remove org from ignored-dependencies
(setq elpaca-ignored-dependencies '(emacs cl-lib cl-generic nadvice map seq json project auth-source-pass let-alist flymake jsonrpc eldoc erc ntlm python so-long soap-client svg ruby-mode verilog-mode xref transient external-completion use-package bind-key eglot))

(elpaca-wait) ;; Block until current queue processed.

;; https://github.com/progfolio/elpaca/issues/181
(use-package auctex
  :elpaca (auctex :pre-build (("./autogen.sh")
                              ("./configure"
                               "--without-texmf-dir")
                              ("make"))))
(elpaca-wait) ;; esure auctex is installed properly

exec-path-from-shell

(use-package exec-path-from-shell
  :config
  (when (memq window-system '(mac ns x))
    (exec-path-from-shell-initialize)))

better-defaults

;(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)

(setq frame-resize-pixelwise t)

(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

(require 'saveplace)
(setq-default save-place t)

(show-paren-mode 1)
(setq-default indent-tabs-mode nil)
(setq apropos-do-all t
      require-final-newline t
      load-prefer-newer t
      ediff-window-setup-function 'ediff-setup-windows-plain
      save-place-file (concat user-emacs-directory "places")
      backup-directory-alist `(("." . ,(concat user-emacs-directory
                                               "backups"))))

;; Speed up tramp
;; https://www.gnu.org/software/emacs/manual/html_node/tramp/Frequently-Asked-Questions.html
(setq vc-ignore-dir-regexp
      (format "\\(%s\\)\\|\\(%s\\)"
              vc-ignore-dir-regexp
              tramp-file-name-regexp))

;; Ensure tramp works on guix remotes
;; https://lists.gnu.org/archive/html/help-guix/2016-10/msg00049.html
(require 'tramp)
(setq tramp-remote-path
      (append tramp-remote-path
              '(tramp-own-remote-path
                "~/.guix-profile/bin" "~/.guix-profile/sbin"
                "/run/current-system/profile/bin" 
                "/run/current-system/profile/sbin")))

(blink-cursor-mode 0)
;; When emacs asks for "yes" or "no", let "y" or "n" suffice
(fset 'yes-or-no-p 'y-or-n-p)
(setq inhibit-startup-message t)
(setq ring-bell-function 'ignore)
(setq confirm-kill-emacs 'yes-or-no-p)
(setq-default fill-column 80)

(setq auth-source-save-behavior nil)
(setq custom-file (concat user-emacs-directory "custom.el"))
(setq woman-fill-frame t)
(load custom-file)

(setq user-full-name "Akira Kyle"
      user-mail-address "akira@akirakyle.com")

eww

(use-package eww
  :elpaca nil
  ;:ensure nil
  :custom
  (eww-auto-rename-buffer 'title)
  ;; https://github.com/alphapapa/unpackaged.el#eww-imenu-support
  :config
  (defun unpackaged/imenu-eww-headings ()
    "Return alist of HTML headings in current EWW buffer for Imenu.
Suitable for `imenu-create-index-function'."
    (let ((faces '(shr-h1 shr-h2 shr-h3 shr-h4 shr-h5 shr-h6 shr-heading)))
      (save-excursion
        (save-restriction
          (widen)
          (goto-char (point-min))
          (cl-loop for next-pos = (next-single-property-change (point) 'face)
                   while next-pos
                   do (goto-char next-pos)
                   for face = (get-text-property (point) 'face)
                   when (cl-typecase face
                          (list (cl-intersection face faces))
                          (symbol (member face faces)))
                   collect (cons (buffer-substring (point-at-bol) (point-at-eol)) (point))
                   and do (forward-line 1))))))

  (add-hook 'eww-mode-hook
            (lambda ()
              (setq-local imenu-create-index-function #'unpackaged/imenu-eww-headings)))
  )

theme

(use-package doom-themes
  :config
  (load-theme 'doom-one t)
  (doom-themes-org-config))

(use-package all-the-icons)

doom-modeline

M-x all-the-icons-install-fonts

(use-package doom-modeline
  :init
  (setq doom-modeline-icon t);(display-graphic-p)
  (column-number-mode 1)
  (doom-modeline-mode 1)
  ;;(setq doom-modeline-window-width-limit 80);;fill-column
  ;;(setq doom-modeline-minor-modes nil)
  )

hidden-mode-line

https://emacs-doctor.com/emacs-hide-mode-line.html

(defvar-local hidden-mode-line-mode nil)

(define-minor-mode hidden-mode-line-mode
  "Minor mode to hide the mode-line in the current buffer."
  :init-value nil
  :global t
  :variable hidden-mode-line-mode
  :group 'editing-basics
  (if hidden-mode-line-mode
      (setq hide-mode-line mode-line-format
            mode-line-format nil)
    (setq mode-line-format hide-mode-line
          hide-mode-line nil))
  (force-mode-line-update)
  ;; Apparently force-mode-line-update is not always enough to
  ;; redisplay the mode-line
  (redraw-display)
  (when (and (called-interactively-p 'interactive)
             hidden-mode-line-mode)
    (run-with-idle-timer
     0 nil 'message
     (concat "Hidden Mode Line Mode enabled.  "
             "Use M-x hidden-mode-line-mode to make the mode-line appear."))))

;; If you want to hide the mode-line in every buffer by default
;; (add-hook 'after-change-major-mode-hook 'hidden-mode-line-mode)

minibuffer-statusbar

(use-package minibuffer-statusbar
  :straight (minibuffer-statusbar :type git :host github 
                                  :repo "akirakyle/minibuffer-statusbar")
  :config
  (minibuffer-statusbar-mode t)
  (global-eldoc-mode -1))

frames and windows

(setq split-height-threshold nil) ;40)
(setq split-width-threshold 160) ;100) ;nil) 

hl-line-mode

;(use-package hl-line-mode
;  :no-require t
;  :config
  (global-hl-line-mode t)
  (make-variable-buffer-local 'global-hl-line-mode)
  (add-hook 'vterm-mode-hook (lambda () (setq global-hl-line-mode nil)))
;)

highlight column 80

(use-package whitespace
  :ensure nil
  :elpaca nil
  :config
  (setq whitespace-style '(face lines-char))
  (add-hook 'prog-mode-hook 'whitespace-mode))

general

(use-package general
  :demand t
  :config
  ;;(define-key key-translation-map (kbd "C-h") (kbd "<DEL>"))
  (general-define-key
    ;;:keymaps 'override
   "C-h" (general-simulate-key "<backspace>"))

  (general-define-key 
    :keymaps 'override
    "C-<tab>" #'(lambda () (interactive) (switch-to-buffer nil)))

  (defun my-start-app (command) 
    (interactive (list (read-shell-command "$ ")))
    (start-process-shell-command command nil command))

  (defun my-toggle-window-split ()
    (interactive)
    (if (eq (count-windows) 1)
        (progn
          (split-window-right)
          (other-window 1)
          (switch-to-buffer nil)
          (other-window 1))
      (delete-other-windows)))

  (general-create-definer my-leader-def
    :prefix "SPC"
    :prefix-command 'my-leader-prefix-cmd
    :states '(normal visual motion)
    :keymaps 'override)

  (general-define-key 
    :keymaps '(override exwm-mode-map)
    "C-SPC" 'my-leader-prefix-cmd)

  ;; make iterated prefix commands like C-u C-u C-u actually work
  (general-define-key 
    :keymaps 'universal-argument-map
    "SPC u" 'universal-argument-more
    "C-SPC u" 'universal-argument-more)

  (general-create-definer my-local-leader-def
    :prefix ","
    :states '(normal visual motion)
    :keymaps 'override)

  (my-leader-def
    "SPC" 'execute-extended-command
    "u" 'universal-argument
    "'" 'vterm
    "a"  '(:ignore t :which-key "apps")
    "as"  '(:ignore t :which-key "shell")
    "ase" 'eshell
    "ass" 'shell
    "ast" 'ansi-term
    "asv" 'vterm
    "aw" 'woman
    "w"  '(:ignore t :which-key "windows")
    "ww" 'my-toggle-window-split
    "w/" 'split-window-right
    "w-" 'split-window-below
    "w=" 'balance-windows
    "wd" 'delete-window
    "b"  'consult-buffer ;'switch-to-buffer
    "C-b"  'consult-buffer ;'switch-to-buffer
    ;;"c"  '(:ignore t :which-key "cd")
    "c"  '(:ignore t :which-key "buffers")
    "cc" 'ibuffer
    "ck" 'kill-current-buffer
    "cu" 'revert-buffer
    "cd" 'cd
    "cw" 'widen
    "q"  '(:ignore t :which-key "quit")
    "qq" 'save-buffers-kill-emacs
    "f"  '(:ignore t :which-key "files")
    "ff" 'find-file
    "fs" 'save-buffer
    "fa" 'save-some-buffers
    ;;"h"  'help
    "h"  '(:ignore t :which-key "help")
    "hh" 'describe-symbol
    "hm" 'describe-mode
    "hk" 'describe-key
    "hf" 'describe-function
    "hv" 'describe-variable
    "hb" 'describe-bindings
    "j"  '(:ignore t :which-key "jump")
    "ji" 'consult-imenu ;'imenu
    "s"  '(:ignore t :which-key "search")
    "e" 'my-start-app
    "z" 'describe-bindings
    "tv" 'visual-line-mode
    "tw" 'whitespace-mode
    )
  )

(elpaca-wait)

which-key

(use-package which-key
  :config
  (which-key-mode)
  )

evil

I edited

(defun evil-search-message (string forward) “Prefix STRING with the search prompt.” (format “%s%s%s” (isearch-lazy-count-format) (evil-search-prompt forward) string))

;(use-package undo-tree
;  :init
;  (setq undo-tree-auto-save-history nil)
;  :config
;  (global-undo-tree-mode)
;  )
(use-package vundo)

(use-package evil
  :init
  (setq evil-want-keybinding nil
        evil-disable-insert-state-bindings t
        ;; evil-want-minibuffer t
        evil-want-C-u-scroll t
        evil-want-C-i-jump nil
        evil-move-cursor-back nil
        evil-move-beyond-eol t
        evil-undo-system 'undo-redo)
  (setq evil-normal-state-cursor '(box "DarkGoldenrod2")
        evil-insert-state-cursor '((bar . 2) "chartreuse3")
        evil-emacs-state-cursor '(box "SkyBlue2")
        evil-hybrid-state-cursor '((bar . 2) "SkyBlue2")
        evil-replace-state-cursor '((hbar . 2) "chocolate")
        evil-evilified-state-cursor '(box "LightGoldenrod3")
        evil-visual-state-cursor '((hbar . 2) "gray")
        evil-motion-state-cursor '(box "plum3")
        evil-lisp-state-cursor '(box "HotPink1")
        evil-iedit-state-cursor '(box "firebrick1")
        evil-iedit-insert-state-cursor '((bar . 2) "firebrick1")
        )
  :config
  (evil-mode 1)
  (evil-set-initial-state 'term-mode 'emacs)
  (define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line)
  (define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line)
  )
(use-package evil-collection
  :after evil
  ;;:custom
  ;;(evil-collection-setup-minibuffer nil)
  :config
  ; see https://github.com/emacs-evil/evil-collection/pull/397
  ; overshadows bindings in emacs-webkit and xwidget-webkit
  ;(setq evil-collection-mode-list (delete 'simple evil-collection--supported-modes))

  (evil-collection-init)
  )
(use-package evil-matchit
  :after evil
  :config
  (global-evil-matchit-mode 1))
(use-package evil-surround
  :after evil
  :config
  ; https://github.com/emacs-evil/evil-surround/pull/48
  ;(evil-define-key 'visual evil-surround-mode-map "s" 'evil-surround-region)
  ;(evil-define-key 'visual evil-surround-mode-map "S" 'evil-substitute)
  (global-evil-surround-mode 1))
(use-package evil-tex
  :after evil
  )
;;(use-package evil-easymotion
;;  :config
;;  (evilem-default-keybindings "SPC j")
;;  )

TODO smartparens and rainbow-delimiters

(use-package smartparens
  :config
  (sp-local-pair 'org-mode "$" "$")
  (sp-local-pair 'org-mode '"\\[" "\\]")
  (add-hook 'prog-mode-hook #'smartparens-mode)
  (add-hook 'org-mode-hook #'smartparens-mode)
  )
(use-package rainbow-delimiters
  :config
  (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
  )

ivy

What I really want is just for buffer switching to be in a centered posframe over everything? https://oremacs.com/swiper/#key-bindings https://siawyoung.com/blog/code/2020-02-10-vterm-ibuffer

(use-package ivy
  :init
  (setq recentf-max-saved-items 50)
  (setq ivy-use-virtual-buffers t)
  (setq enable-recursive-minibuffers t)
  (setq ivy-count-format "(%d/%d) ")
  (setq ivy-height 20)
  :config
  (ivy-mode 1)
  (general-def
    :keymaps 'ivy-minibuffer-map
    "C-<return>" 'ivy-immediate-done
    "C-d" 'ivy-scroll-up-command
    "C-u" 'ivy-scroll-down-command
    )
  )

(use-package counsel
  :config
  (counsel-mode 1)
  (my-leader-def "sa" 'counsel-ag)
  (my-leader-def "fg" 'counsel-git)
  )

(use-package swiper
  :config
  (general-define-key "C-s" 'swiper)
  (my-leader-def "ss" 'swiper)
  )

(use-package ivy-avy)

(use-package amx)

(use-package ivy-rich
  :init
  (setq ivy-rich-parse-remote-buffer nil)
  ;;(setq ivy-format-function #'ivy-format-function-line)
  :config
  (ivy-rich-mode 1)
  (ivy-rich-project-root-cache-mode 1)
  )

;use-package ivy-posframe
;  :config
;  (put 'ivy-posframe 'face-alias 'default)
;  (setq ivy-posframe-border-width 5)
;  (setq ivy-posframe-display-functions-alist '((t . ivy-posframe-display-at-frame-center)))
;  (setq ivy-posframe-display-functions-alist
;      '((swiper          . ivy-posframe-display-at-point)
;        (complete-symbol . ivy-posframe-display-at-point)
;        (t               . ivy-posframe-display-at-frame-center)))
;  ;(ivy-posframe-mode 1)
;  )

vertico

(use-package vertico
  :elpaca (vertico :files (:defaults "extensions/*"))
  :init
  (vertico-mode)
  (setq vertico-count 16
        vertico-cycle t)

  ;(require 'vertico-directory)
  (general-def
    :keymaps 'vertico-map
    "C-d" 'vertico-scroll-up
    "C-u" 'vertico-scroll-down
    ;"RET" 'vertico-directory-enter
    "DEL" 'vertico-directory-delete-char
    )
  )

(use-package vertico-directory
  :elpaca nil
  :after vertico)

;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
  :elpaca nil
  :init
  (savehist-mode))

(use-package emacs
  :elpaca nil
  :init
  ;; Do not allow the cursor in the minibuffer prompt
  (setq minibuffer-prompt-properties
        '(read-only t cursor-intangible t face minibuffer-prompt))
  (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

  ;; Enable recursive minibuffers
  (setq enable-recursive-minibuffers t))

orderless

(use-package orderless
  :init
  (setq completion-styles '(orderless basic)
        completion-category-defaults nil
        completion-category-overrides '((file (styles . (partial-completion))))))

consult

(use-package consult
  :config
  (consult-customize
   consult-buffer
   :preview-key "M-.")

  ; https://github.com/minad/consult/issues/651
  (defun consult--buffer-sort-mru(xs)
    (append (cdr xs) (list (car xs))))
  (plist-put consult--source-buffer :items
             (lambda() (consult--buffer-query :sort 'mru :as #'buffer-name)))

  (general-define-key "C-s" 'consult-line)
  (my-leader-def "ss" 'consult-line)
  (my-leader-def "sa" 'consult-ripgrep)
  (my-leader-def "fp" 'consult-project-buffer)
  (recentf-mode)

  ; from the consult wiki https://github.com/minad/consult/wiki
  (defvar consult--previous-point nil
    "Location of point before entering minibuffer.
Used to preselect nearest headings and imenu items.")

  (defun consult--set-previous-point ()
    "Save location of point. Used before entering the minibuffer."
    (setq consult--previous-point (point)))

  (advice-add #'consult-org-heading :before #'consult--set-previous-point)
  (advice-add #'consult-outline :before #'consult--set-previous-point)

  (advice-add #'vertico--update :after #'consult-vertico--update-choose)

  (defun consult-vertico--update-choose (&rest _)
    "Pick the nearest candidate rather than the first after updating candidates."
    (when (and consult--previous-point
               (memq current-minibuffer-command
                     '(consult-org-heading consult-outline)))
      (setq vertico--index
            (max 0 ; if none above, choose the first below
                 (1- (or (seq-position
                          vertico--candidates
                          consult--previous-point
                          (lambda (cand point-pos) ; counts on candidate list being sorted
                            (> (cl-case current-minibuffer-command
                                 (consult-outline
                                  (car (consult--get-location cand)))
                                 (consult-org-heading
                                  (get-text-property 0 'consult--candidate cand)))
                               point-pos)))
                         (length vertico--candidates))))))
    (setq consult--previous-point nil))
  )

;(use-package consult-ag
;  :config
;  (my-leader-def "sa" 'consult-ag)
;  )

marginalia

(use-package all-the-icons-completion
  :config
  (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup)
  )

(use-package marginalia
  :init
  (marginalia-mode))

embark

(use-package embark
  :bind
  (("C-." . embark-act))
   ;("C-;" . embark-dwim)        ;; good alternative: M-.
   ;("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'

  :config

  ;; Hide the mode line of the Embark live/completions buffers
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none))))

  (defvar my-org-roam-map
    (let ((map (make-sparse-keymap)))
      ;(define-key map (kbd "t") 'org-roam-buffer-toggle)
      (define-key map (kbd "i") 'org-roam-node-insert)
      (define-key map (kbd "f") 'org-roam-node-find)
      ;(define-key map (kbd "r") 'org-roam-ref-find)
      ;(define-key map (kbd "g") 'org-roam-show-graph)
      ;(define-key map (kbd "c") 'org-roam-capture)
      ;(define-key map (kbd "j") 'org-roam-dailies-capture-today)
      map)
    "Keymap for 'org-roam' v2.")

  ; make available my-org-roam-map to embark-act
  (add-to-list 'embark-keymap-alist '(org-roam-node . my-org-roam-map))
  )

;; Consult users will also want the embark-consult package.
(use-package embark-consult
  :after (embark consult))

avy

(use-package avy
  :config
  (avy-setup-default)
  (setq avy-all-windows nil)
  (setq avy-keys '(?a ?o ?e ?u ?h ?t ?n ?s))
  (setq avy-timeout-seconds 0.2)
  (general-define-key :states 'normal "gc" 'evil-avy-goto-char-timer);;evil-avy-goto-char-2)
  (general-define-key :states '(normal insert) "C-'" 'evil-avy-goto-char-timer);;evil-avy-goto-char-2)
  )

ace

(use-package ace-link
  :config
  (ace-link-setup-default)
  (general-define-key :states 'normal :keymaps 'Info-mode-map "o" 'ace-link-info)
  (general-define-key :states 'normal :keymaps 'help-mode-map "o" 'ace-link-help)
  (general-define-key :states 'normal :keymaps 'help-mode-map "o" 'ace-link-help)
  (my-local-leader-def :keymaps 'org-mode-map "o" 'ace-link-org)
  )

(use-package ace-window
  :config
  (setq aw-keys '(?h ?t ?n ?s))
  (setq aw-scope 'frame)
  (general-define-key :keymaps 'override  "M-<tab>" 'ace-window)
  )

corfu

(use-package corfu
  :init
  (setq tab-always-indent 'complete
        ;corfu-auto t
        ;corfu-auto-delay 0
        corfu-preselect-first nil
        corfu-quit-at-boundary nil
        ;corfu-quit-no-match t
        )
  :config
  (global-corfu-mode)

  (defun corfu-enable-always-in-minibuffer ()
    "Enable Corfu in the minibuffer if Vertico is not active."
    (unless (bound-and-true-p vertico--input)
      ;; (setq-local corfu-auto nil) Enable/disable auto completion
      (corfu-mode 1)))
  (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)
  )

(use-package kind-icon
  :after corfu
  :custom
  (kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
  :config
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))

tempel

modified   tempel.el
@@ -598,7 +598,8 @@ This is meant to be a source in `tempel-template-sources'."
   (let ((completion-at-point-functions (list capf))
         completion-cycle-threshold)
     (tempel--save)
-    (or (completion-at-point) (user-error "%s: No completions" capf))))
+    (completion-at-point)))
+    ;(or (completion-at-point) (user-error "%s: No completions" capf))))

 (defun tempel--completion-table (templates)
   "Return a completion table for a list of TEMPLATES.
(use-package tempel
  :bind
  (:map tempel-map
        ([tab] . tempel-next)
        ([backtab] . tempel-previous))
  :init
  ;;(add-to-list 'org-structure-template-alist '("p" . "src python"))
  (defun my-templates ()
    (cond ((derived-mode-p 'org-mode)
           '((today (format-time-string "%Y-%m-%d"))
             (bl "#+begin_" (p "src" block) " " p n r n "#+end_" (s block))
             (py "#+begin_src jupyter-python" n r n "#+end_src")
             (jl "#+begin_src jupyter-julia" n r n "#+end_src")
             (el "#+begin_src emacs-lisp" n> r> n> "#+end_src")
             (be "\\begin{" (p "align" env) "}" n r n "\\end{" (s env) "}")
             ))
          ((derived-mode-p 'tex-mode)
           '(
             (be "\\begin{" (p "align" env) "}" n r n "\\end{" (s env) "}")
             ))))
  (setq tempel-template-sources '(my-templates))
  )

cape

(use-package cape
  :init
  (setq cape-dabbrev-check-other-buffers 'some)

  :config

  (bind-key  "C-c l" 'cape-tex)
  (defun my-org-emacs-lisp-capf ()
    (when (and (org-in-src-block-p 'inside)
               (string= "emacs-lisp"
                        (org-element-property
                         :language (org-element-at-point))))
      (elisp-completion-at-point)))

  (defun my-org-capf ()
    (setq-local completion-at-point-functions
                '(tempel-expand ;tempel-complete
                  jupyter-org-completion-at-point
                  my-org-emacs-lisp-capf
                  pcomplete-completions-at-point
                  cape-dabbrev
                  cape-file t)))

  (add-hook 'org-mode-hook #'my-org-capf)

  (setq completion-at-point-functions
        '(tempel-expand ;tempel-complete
          pcomplete-completions-at-point
          cape-dabbrev
          cape-file t))

  ;(add-hook 'prog-mode-hook 'tempel-setup-capf)
  ;(add-hook 'text-mode-hook 'tempel-setup-capf)
  )

lsp/eglot

(use-package consult-eglot
  :init
  (my-leader-def "al" 'consult-eglot-symbols)
  )
(use-package lsp-mode
  :init
  ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
  (setq lsp-keymap-prefix nil)
  (defun my-lsp-which-key-setup ()
    (let ((lsp-keymap-prefix "SPC a l"))
      (my-leader-def "al" lsp-command-map)
      (lsp-enable-which-key-integration t)))

  (setq lsp-enable-snippet nil)
  :hook ((latex-mode . lsp)
         ;(lsp-mode . lsp-enable-which-key-integration)
         (lsp-mode . my-lsp-which-key-setup))
  :commands lsp)

(use-package lsp-ui :commands lsp-ui-mode)
(use-package consult-lsp :commands consult-lsp-diagnostics)

;; optionally if you want to use debugger
;;(use-package dap-mode)
;; (use-package dap-LANGUAGE) to load the dap adapter for your language

flyspell

(use-package flyspell
  :elpaca nil
  :init
  (setq ispell-program-name "aspell")
  :config
  (add-hook 'org-mode-hook 'flyspell-mode)
  (add-hook 'TeX-mode-hook 'flyspell-mode)
  (add-hook 'message-mode-hook 'flyspell-mode)
  )
(use-package flyspell-correct
  :config
  (my-leader-def
    "sc" 'flyspell-correct-wrapper
    )
  )

(use-package consult-flyspell
  :config
  (setq consult-flyspell-select-function nil
        consult-flyspell-set-point-after-word t
        consult-flyspell-always-check-buffer nil))

org

org

https://github.com/integral-dw/org-superstar-mode

’(org-cycle-hide-archived-subtrees org-cycle-show-empty-lines org-optimize-window-after-visibility-change)) https://www.mail-archive.com/emacs-orgmode@gnu.org/msg127537.html

(use-package org
  :elpaca (org :host github :repo "akirakyle/org-mode")
  :after evil
  :init
  (setq org-agenda-files (list "~/todo.org")
        org-agenda-span 10
        org-edit-src-content-indentation 0
        org-agenda-window-setup 'current-window
        org-startup-with-inline-images t
        org-src-tab-acts-natively t
        org-adapt-indentation nil
        org-src-window-setup 'other-window
        org-export-with-smart-quotes t
        org-log-done t
        ;;org-export-in-background t
        org-highlight-latex-and-related '(native latex scripts entities)
        org-ellipsis "⤵"
        org-imenu-depth 4
        org-cycle-hook '(org-cycle-hide-archived-subtrees org-cycle-show-empty-lines org-optimize-window-after-visibility-change)
        org-cycle-include-plain-lists nil
        org-latex-prefer-user-labels t
        )

  (add-hook 'org-mode-hook #'visual-line-mode)

  ;; TODO: fix this so org-scheduled today actually applied correctly in org-faces.el
  ;; (- 1 (/ (float diff) (max wdays 0)))
  ;;   (upcoming? (and today? (> deadline today)))
  (setq org-deadline-warning-days 0)
  (setq org-agenda-deadline-faces '((1.01 . org-scheduled-previously)
                                    (1.0 . org-scheduled)
                                    (0.99 . org-sheduled-today)
                                    (0.0 . org-scheduled)))

  (setq org-confirm-babel-evaluate nil)
  ;; display/update images in the buffer after I evaluate
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images 'append)
  ;;(remove-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)

  ;; better to set :eval no-export than (setq org-export-use-babel nil)
  (setq org-babel-default-header-args '((:session . "none")
                                        (:results . "replace")
                                        (:exports . "code")
                                        (:cache . "no")
                                        (:noweb . "no")
                                        (:hlines . "no")
                                        (:tangle . "no")
                                        (:eval . "no-export")
                                        (:comments . "link")))

  (setq org-babel-default-header-args:emacs-lisp '((:lexical . "yes")))

  (setq org-babel-default-header-args:latex '((:results . "file raw")
                                              (:buffer . "no")
                                              (:exports . "both")
                                              (:noweb . "no-export")))
  (setq org-babel-default-header-args:jupyter-python '((:kernel . "python3")
                                                       (:async . "yes")
                                                       (:results . "raw")
                                                       (:exports . "both")
                                                       (:comments . "link")))
  (setq org-babel-default-header-args:jupyter-julia '((:kernel . "julia-1.10")
                                                      (:async . "yes")
                                                      (:results . "raw")
                                                      (:exports . "both")
                                                      (:comments . "link")))

  (defun my-org-ctrl-c-ctrl-c-latex-preview-hook ()
    (let ((element (car (org-element-context))))
      (if (or (eq element 'latex-fragment) (eq element 'latex-environment))
          (org-latex-preview))))

  ;(add-hook 'org-ctrl-c-ctrl-c-final-hook
  (add-hook 'org-ctrl-c-ctrl-c-hook
            'my-org-ctrl-c-ctrl-c-latex-preview-hook)

  :config
  (require 'org-indent) ; Prevents "Invalid face reference: org-indent"
  (evil-define-key 'normal org-mode-map (kbd "RET") 'org-open-at-point)
  (add-to-list 'org-src-lang-modes '("conf" . conf))

  (setq org-preview-latex-default-process 'dvisvgm
        org-preview-latex-image-directory "~/.cache/org-preview-latex/"
        org-format-latex-options
        '(:foreground default :background default :scale 1.5
                      :html-foreground "Black" :html-background "Transparent"
                      :html-scale 1.0
                      :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))
        )

  (add-hook 'org-mode-hook (lambda ()
                             (setq-local time-stamp-start "^#\\+modified:[       ]+\\\\?"
                                         time-stamp-end "$"
                                         time-stamp-format "\[%Y-%m-%d %a\]")
                             (add-hook 'before-save-hook #'time-stamp nil 'local)))

  (defun my-org-format-web-link ()
    (interactive)
    (let ((el (org-element-context)))
      (when (and (eq (org-element-type el) 'link)
                 (let ((type (org-element-property :type el)))
                   (or (string= type "http") (string= type "https"))))
        (let* ((url (org-element-property :raw-link el))
               (title (with-current-buffer (url-retrieve-synchronously url)
                        (dom-text
                         (dom-by-tag
                          (libxml-parse-html-region (point-min) (point-max))
                          'title)))))
          (delete-region (org-element-property :begin el)
                         (org-element-property :end el))
          (insert (org-link-make-string url title))))))

  (my-local-leader-def
    :keymaps 'org-mode-map
    "'" 'org-edit-special
    "c" 'org-capture

    "l" 'org-latex-export-to-pdf
    "h" 'org-latex-export-to-html

    ;; Clock
    ;; These keybindings should match those under the "aoC" prefix (below)
    "Cc" 'org-clock-cancel
    "Cd" 'org-clock-display
    "Ce" 'org-evaluate-time-range
    "Cg" 'org-clock-goto
    "Ci" 'org-clock-in
    "CI" 'org-clock-in-last
    "Cj" 'spacemacs/org-clock-jump-to-current-clock
    "Co" 'org-clock-out
    "CR" 'org-clock-report
    "Cr" 'org-resolve-clocks

    "dd" 'org-deadline
    "ds" 'org-schedule
    "dt" 'org-time-stamp
    "dT" 'org-time-stamp-inactive
    "e" 'org-export-dispatch
    "fi" 'org-feed-goto-inbox
    "fu" 'org-feed-update-all

    "a" 'org-agenda

    "p" 'org-priority

    "Tc" 'org-toggle-checkbox
    "Te" 'org-toggle-pretty-entities
    "Ti" 'org-toggle-inline-images
    "Tl" 'org-toggle-link-display
    "Tt" 'org-show-todo-tree
    "TT" 'org-todo
    "TV" 'space-doc-mode
    "Tx" 'org-latex-preview
    "Ts" 'org-toggle-timestamp-type

    ;; More cycling options (timestamps, headlines, items, properties)
    "L" 'org-shiftright
    "H" 'org-shiftleft
    "J" 'org-shiftdown
    "K" 'org-shiftup

    ;; Change between TODO sets
    "C-S-l" 'org-shiftcontrolright
    "C-S-h" 'org-shiftcontrolleft
    "C-S-j" 'org-shiftcontroldown
    "C-S-k" 'org-shiftcontrolup

    ;; Subtree editing
    "sa" 'org-toggle-archive-tag
    "sA" 'org-archive-subtree
    "sb" 'org-tree-to-indirect-buffer
    "sh" 'org-promote-subtree
    "sj" 'org-move-subtree-down
    "sk" 'org-move-subtree-up
    "sl" 'org-demote-subtree
    "sn" 'org-narrow-to-subtree
    "sN" 'widen
    "sr" 'org-refile
    "ss" 'org-sparse-tree
    "sS" 'org-sort

    ;; tables
    "ta" 'org-table-align
    "tb" 'org-table-blank-field
    "tc" 'org-table-convert
    "tdc" 'org-table-delete-column
    "tdr" 'org-table-kill-row
    "te" 'org-table-eval-formula
    "tE" 'org-table-export
    "th" 'org-table-previous-field
    "tH" 'org-table-move-column-left
    "tic" 'org-table-insert-column
    "tih" 'org-table-insert-hline
    "tiH" 'org-table-hline-and-move
    "tir" 'org-table-insert-row
    "tI" 'org-table-import
    "tj" 'org-table-next-row
    "tJ" 'org-table-move-row-down
    "tK" 'org-table-move-row-up
    "tl" 'org-table-next-field
    "tL" 'org-table-move-column-right
    "tn" 'org-table-create
    "tN" 'org-table-create-with-table.el
    "tr" 'org-table-recalculate
    "ts" 'org-table-sort-lines
    "ttf" 'org-table-toggle-formula-debugger
    "tto" 'org-table-toggle-coordinate-overlays
    "tw" 'org-table-wrap-region

    ;; Source blocks / org-babel
    "bp" 'org-babel-previous-src-block
    "bn" 'org-babel-next-src-block
    "be" 'org-babel-execute-maybe
    "bo" 'org-babel-open-src-block-result
    "bv" 'org-babel-expand-src-block
    "bu" 'org-babel-goto-src-block-head
    "bg" 'org-babel-goto-named-src-block
    "br" 'org-babel-goto-named-result
    "bb" 'org-babel-execute-buffer
    "bs" 'org-babel-execute-subtree
    "bd" 'org-babel-demarcate-block
    "bt" 'org-babel-tangle
    "bf" 'org-babel-tangle-file
    "bc" 'org-babel-check-src-block
    "bj" 'org-babel-insert-header-arg
    "bl" 'org-babel-load-in-session
    "bi" 'org-babel-lob-ingest
    "bI" 'org-babel-view-src-block-info
    "bz" 'org-babel-switch-to-session
    "bZ" 'org-babel-switch-to-session-with-code
    "ba" 'org-babel-sha1-hash
    "bx" 'org-babel-do-key-sequence-in-edit-buffer
    "vk" 'org-babel-remove-result-one-or-many
    "vm" 'org-babel-mark-block

    ;; Multi-purpose keys
    "," 'org-ctrl-c-ctrl-c
    "*" 'org-ctrl-c-star
    "-" 'org-ctrl-c-minus
    "#" 'org-update-statistics-cookies
    "RET"   'org-ctrl-c-ret
    "M-RET" 'org-meta-return
    ;; attachments
    "A" 'org-attach
    ;; insertion
    "ib" 'org-insert-structure-template
    "id" 'org-insert-drawer
    "ie" 'org-set-effort
    "if" 'org-footnote-new
    "ih" 'org-insert-heading
    "iH" 'org-insert-heading-after-current
    "iK" 'spacemacs/insert-keybinding-org
    "il" 'org-insert-link
    "ir" 'org-roam-node-insert
    "in" 'org-add-note
    "ip" 'org-set-property
    "is" 'org-insert-subheading
    "it" 'org-set-tags-command
    "ii" 'my-org-format-web-link
    )

  (my-leader-def
    ;; org-agenda
    "ao#" 'org-agenda-list-stuck-projects
    "ao/" 'org-occur-in-agenda-files
    "aoa" 'org-agenda-list
    "aoc" 'org-capture
    "aoe" 'org-store-agenda-views
    "aofi" 'org-feed-goto-inbox
    "aofu" 'org-feed-update-all
    "aol" 'org-store-link
    "aom" 'org-tags-view
    "aoo" 'org-agenda
    "aos" 'org-search-view
    "aot" 'org-todo-list
    )
  )
(elpaca-wait) ;; avoid elpaca's async loading of builtin org as dep of other pkgs

(use-package org-contrib)

(use-package ox
  :elpaca nil
  :config
  <<website.org:org-publish-project-blk()>>
  )

org-roam

https://org-roam.discourse.group/t/org-roam-major-redesign/1198/181?page=9

(use-package org-roam
  :init
  (my-leader-def "ar" 'org-roam-node-find)
  (my-leader-def "ac" 'org-roam-capture)
  (my-local-leader-def
    :keymaps 'org-mode-map
    "Tr" 'org-roam-buffer-toggle)
  (setq org-roam-directory "~/org")
  ;(setq org-roam-node-display-template
  ;      (concat "${title:*} "
  ;              (propertize "${tags:10}" 'face 'org-tag)))
  (setq org-roam-capture-templates
        '(("d" "default" plain "%?" :target
           (file+head
            "notebook/${slug}.org"
            "#+title: ${title}\n#+date: %u\n#+modified: %u\n")
          :unnarrowed t)))

  (setq org-id-link-to-org-use-id 'create-if-interactive)

  :config
  (org-roam-db-autosync-mode)
  (require 'org-roam-export)

  ;; https://github.com/org-roam/org-roam/wiki/User-contributed-Tricks#overriding-the-slug-function
(cl-defmethod org-roam-node-slug ((node org-roam-node))
  "Return the slug of NODE."
  (let ((title (org-roam-node-title node))
        (slug-trim-chars '(;; Combining Diacritical Marks https://www.unicode.org/charts/PDF/U0300.pdf
                           768 ; U+0300 COMBINING GRAVE ACCENT
                           769 ; U+0301 COMBINING ACUTE ACCENT
                           770 ; U+0302 COMBINING CIRCUMFLEX ACCENT
                           771 ; U+0303 COMBINING TILDE
                           772 ; U+0304 COMBINING MACRON
                           774 ; U+0306 COMBINING BREVE
                           775 ; U+0307 COMBINING DOT ABOVE
                           776 ; U+0308 COMBINING DIAERESIS
                           777 ; U+0309 COMBINING HOOK ABOVE
                           778 ; U+030A COMBINING RING ABOVE
                           779 ; U+030B COMBINING DOUBLE ACUTE ACCENT
                           780 ; U+030C COMBINING CARON
                           795 ; U+031B COMBINING HORN
                           803 ; U+0323 COMBINING DOT BELOW
                           804 ; U+0324 COMBINING DIAERESIS BELOW
                           805 ; U+0325 COMBINING RING BELOW
                           807 ; U+0327 COMBINING CEDILLA
                           813 ; U+032D COMBINING CIRCUMFLEX ACCENT BELOW
                           814 ; U+032E COMBINING BREVE BELOW
                           816 ; U+0330 COMBINING TILDE BELOW
                           817 ; U+0331 COMBINING MACRON BELOW
                           )))
    (cl-flet* ((nonspacing-mark-p (char) (memq char slug-trim-chars))
               (strip-nonspacing-marks (s) (string-glyph-compose
                                            (apply #'string
                                                   (seq-remove #'nonspacing-mark-p
                                                               (string-glyph-decompose s)))))
               (cl-replace (title pair) (replace-regexp-in-string (car pair) (cdr pair) title)))
      (let* ((pairs `(("[^[:alnum:][:digit:]]" . "-") ;; convert anything not alphanumeric
                      ("--*" . "-")                   ;; remove sequential underscores
                      ("^-" . "")                     ;; remove starting underscore
                      ("-$" . "")))                   ;; remove ending underscore
             (slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
        (downcase slug)))))
  )

ox-latex

(use-package ox-latex
  :elpaca nil
  :config
  (add-to-list 'org-latex-minted-langs '(jupyter-python "python"))
  ;;(setq org-latex-image-default-width "\\linewidth")
  ;;(setq org-latex-src-block-backend 'minted)
  (setq org-latex-packages-alist '(("" "physics" t)
                                   ("" "tikz" t)))
                                   ;("" "lmodern" nil)
                                   ;("" "svg" nil)
                                   ;("" "caption" nil)))
  ;;("" "minted" nil)
  ;;("margin=1in,headsep=0.4in,headheight=14pt" "geometry" nil)
  ;;("" "fancyhdr" nil)
  ;;("" "parskip" nil)))
  )

ox-pluto

(use-package ox-pluto
  :elpaca (ox-pluto :host github :repo "tecosaur/ox-pluto")
  )

ox-ipynb

(use-package ox-ipynb
  :elpaca (ox-ipynb :host github :repo "jkitchin/ox-ipynb")
  )

evil-org

(use-package evil-org
  :after org
  :init
  (setq evil-org-key-theme
        '(navigation insert textobjects additional calendar todo))
  :config
  (add-hook 'org-mode-hook 'evil-org-mode)
  (require 'evil-org-agenda)
  (evil-org-agenda-set-keys)
)

htmlize

(use-package htmlize)

bibtex and citar

Perhaps interesting idea to use org-bibtex https://github.com/emacs-citar/citar/issues/397 Alternative to biblio: https://github.com/teeann/scholar-import

(use-package bibtex
  :elpaca nil
  :init
  (setq bibtex-autokey-year-title-separator "-"
        bibtex-autokey-titleword-separator "-"
        bibtex-entry-format t
        bibtex-align-at-equal-sign t
        bibtex-autokey-edit-before-use nil)
  :config
  (setq bibtex-autokey-titleword-ignore
        (remove "[^[:upper:]].*" bibtex-autokey-titleword-ignore))

  (setq bibtex-BibTeX-entry-alist
        (mapcar (lambda (e) (cons (downcase (car e)) (cdr e)))
                bibtex-BibTeX-entry-alist))

  (setq bibtex-biblatex-entry-alist
        (mapcar (lambda (e) (cons (downcase (car e)) (cdr e)))
                bibtex-BibTeX-entry-alist))
  )

(use-package citeproc)

(use-package citar
  ;:bind (("C-c b" . citar-insert-citation)
  ;       :map minibuffer-local-map
  ;       ("M-b" . citar-insert-preset))
  ;(:map org-mode-map :package org ("C-c b" . #'org-cite-insert))
  :after (org)
  :custom
  (org-cite-export-processors '((t csl)))
  (org-cite-insert-processor 'citar)
  (org-cite-follow-processor 'citar)
  (org-cite-activate-processor 'citar)
  (org-cite-global-bibliography '("~/org/references.bib"
                                  "~/org/references-arxiv.bib"
                                  "~/org/references-non-article.bib"))
  (citar-bibliography org-cite-global-bibliography)
  (citar-library-paths '("~/ref-pdfs/"))

  :init
  (my-leader-def "ab" 'citar-open)

  :config
  (defvar citar-indicator-files-icons
    (citar-indicator-create
     :symbol (all-the-icons-faicon
              "file-o"
              :face 'all-the-icons-green
              :v-adjust -0.1)
     :function #'citar-has-files
     :padding "  " ; need this because the default padding is too low for these icons
     :tag "has:files"))

  (defvar citar-indicator-links-icons
    (citar-indicator-create
     :symbol (all-the-icons-octicon
              "link"
              :face 'all-the-icons-orange
              :v-adjust 0.01)
     :function #'citar-has-links
     :padding "  "
     :tag "has:links"))

  (defvar citar-indicator-notes-icons
    (citar-indicator-create
     :symbol (all-the-icons-material
              "speaker_notes"
              :face 'all-the-icons-blue
              :v-adjust -0.3)
     :function #'citar-has-notes
     :padding "  "
     :tag "has:notes"))

  (setq citar-indicators
        (list citar-indicator-files-icons
              citar-indicator-links-icons
              citar-indicator-notes-icons))

  (add-to-list 'savehist-additional-variables 'citar-history)
  ;(setq citar-at-point-function 'embark-act)
  )

(use-package citar-embark
  :after citar embark
  :no-require
  :config (citar-embark-mode))

(use-package citar-org-roam
  :after citar org-roam
  ;;:custom
  ;;(citar-org-roam-note-title-template "")
  :config
  (citar-org-roam-mode)

  (defun citar--shorten-name (name)
    (car (last (split-string name " "))))

  (setq citar-display-transform-functions
        `((sn . (citar--shorten-names))
          (etal . (citar--shorten-names 1 "&"))))

  (setq citar-org-roam-note-title-template "${author:%etal} ${year}")

  (add-to-list 'org-roam-capture-templates
        '("n" "ref note" plain "%?" :target
           (file+head
            "ref-notes/${citar-citekey}.org"
            "#+title: ${note-title}\n#+subtitle: ${citar-title}\n#+date: %u\n#+modified: %u\n#+print_bibliography:\n[cite/n:@${citar-citekey}]\n")
           :unnarrowed t))

  (setq citar-org-roam-capture-template-key "n")

  (defun my-citar-org-roam--create-capture-note (citekey entry)
    (citar-org-roam--create-capture-note citekey entry)
    (org-set-property "DOI" (citar-format--entry "${doi}" entry)))

  (citar-register-notes-source
   'my-citar-org-roam-source 
   (list :name "Org-Roam Notes"
         :category 'org-roam-node
         :items 'citar-org-roam--get-candidates
         :hasitems 'citar-org-roam-has-notes
         :open 'citar-org-roam-open-note
         :create 'my-citar-org-roam--create-capture-note
         :annotate 'citar-org-roam--annotate))
  (setq citar-notes-source 'my-citar-org-roam-source)
  )

(use-package doi2bib
  :elpaca (doi2bib :host github :repo "akirakyle/emacs-doi2bib")
  :after citar
  :init 
  (setq doi2bib-bibtex-file (car citar-bibliography))
  (setq doi2bib-disable-bibtex-prompt t)

  ;;(defun my-add-doi-to-org-roam ()
  ;;  (interactive)
  ;;  (citar-create-note
  ;;   (cdr (assoc "=key=" (call-interactively 'doi2bib-add-bibtex-entry-from-doi)))))
  ;;(my-leader-def "ad" 'my-add-doi-to-org-roam)
  ;;(my-leader-def "ad" 'doi2bib-add-bibtex-entry-from-doi)

  (defun my-citar-add-file-to-library (citekey)
    (interactive (list (citar-select-ref)))
    (let* ((filepath (expand-file-name citekey (car citar-library-paths)))
           (url (read-string "Add file URL: ")))
      (url-copy-file url (concat filepath ".pdf"))))

  (defun my-add-doi ()
    (interactive)
    (let ((bibtex (call-interactively 'doi2bib-add-bibtex-entry-from-doi)))
      (my-citar-add-file-to-library (cdr (assoc "=key=" bibtex)))))

  (my-leader-def "ad" 'my-add-doi)

  )

Cleaning up references

Here’s some code I’ve used to cleanup my bibfiles

(with-current-buffer "references.bib"
  (bibtex-map-entries (lambda (key start end) (bibtex-clean-entry))))

(with-current-buffer "references.bib"
  (setq my-no-doi nil)
  (defun my-bibtex-doi (key start end)
    (let* ((entry (bibtex-parse-entry))
           (key (cdr (assoc "=key=" entry)))
           (doi (cdr (assoc "doi" entry))))
                                        ;(message "%S" key)
      (unless doi
        (add-to-list 'my-no-doi key))))
  (bibtex-map-entries 'my-bibtex-doi))

(with-current-buffer "references.bib"
  (setq my-arxiv nil)
  (defun my-bibtex-arxiv (key start end)
    (let* ((entry (bibtex-parse-entry))
           (key (cdr (assoc "=key=" entry)))
           (doi (cdr (assoc "doi" entry)))
           (publisher (cdr (assoc "publisher" entry))))
           ;(message "%S" publisher)
      (when (string= publisher "{arXiv}")
        (add-to-list 'my-arxiv key))))
  (bibtex-map-entries 'my-bibtex-arxiv))

(with-current-buffer "references.bib"
  (defun my-bibtex-cleaner (key start end)
    (let* ((entry (bibtex-parse-entry))
           (key (cdr (assoc "=key=" entry)))
           (doi (cdr (assoc "doi" entry)))
           (doi (substring doi 1 -1)))
      (if (not doi) (error "no DOI! %S" key)
        (delete-region start end)
        (doi2bib-insert-bibtex-entry-from-doi doi))))
  (bibtex-map-entries 'my-bibtex-cleaner))

(with-current-buffer "references_arxiv.bib"
  (setq my-arxiv nil)
  (defun my-bibtex-arxiv (key start end)
    (let* ((entry (bibtex-parse-entry))
           (key (cdr (assoc "=key=" entry)))
           (doi (cdr (assoc "doi" entry)))
           (publisher (cdr (assoc "publisher" entry))))
           ;(message "%S" publisher)
      (when (string= publisher "{arXiv}")
        (add-to-list 'my-arxiv key))))
  (bibtex-map-entries 'my-bibtex-arxiv))

org-pdftools

(use-package org-pdftools
  :init (setq org-pdftools-use-isearch-link t)
  :hook (org-mode . org-pdftools-setup-link))

geiser

;(use-package geiser
;  :init
;  (setq geiser-active-implementations '(guile)))

jupyter

(use-package jupyter
  :after (org)
  ;:defer t
  :elpaca (jupyter :host github :repo "akirakyle/emacs-jupyter")
  :config
  (org-babel-do-load-languages
   'org-babel-load-languages
   '(
     (emacs-lisp . t)
     (org . t)
     (shell . t)
     (latex . t)
     (julia . t)
     (python . t)
     (jupyter . t) ; must be last
     ))
  )

buffer-env

https://amodernist.com/texts/emacs-guix.html

(use-package buffer-env
  :config
  (eval-when-compile (require 'cl-lib))
  (defun buffer-env-inherit (fn &rest args)
    "Call FN with ARGS using the buffer-local process environment.
Intended as an advice around commands that start a process after
switching buffers."
    (cl-letf (((default-value 'process-environment) process-environment)
              ((default-value 'exec-path) exec-path))
      (apply fn args)))

  (add-hook 'hack-local-variables-hook 'buffer-env-update)
  (advice-add 'shell-command-to-string :around #'buffer-env-inherit)
  (advice-add 'async-shell-command :around #'buffer-env-inherit)
  (advice-add 'org-babel-eval :around #'buffer-env-inherit)
  (advice-add 'jupyter-command :around #'buffer-env-inherit)
  ;; order matters for the following!
  (advice-add 'vterm-mode :around #'buffer-env-inherit)
  (advice-add 'vterm-mode :before #'buffer-env-update)
)

LaTeX

(use-package tex-mode
  :elpaca nil
  :init
  (setq TeX-view-program-selection '((output-pdf "pdf-tools")))
  (setq TeX-view-program-list '(("pdf-tools" "TeX-pdf-tools-sync-view")))
  (add-hook 'TeX-after-compilation-finished-functions
            #'TeX-revert-document-buffer)
  (add-hook 'LaTeX-mode-hook #'visual-line-mode)
  (add-hook 'LaTeX-mode-hook (lambda () (whitespace-mode -1)))
  (setq TeX-command-extra-options "\"-shell-escape\"")
  )

cdlatex

https://github.com/tecosaur/LaTeX-auto-activating-snippets https://karthinks.com/software/latex-input-for-impatient-scholars/ Probably prefer laas to this?

(use-package cdlatex
  :init
  (org-defkey org-cdlatex-mode-map ";" 'cdlatex-math-symbol)
  (setq cdlatex-math-symbol-prefix ?\;)
  (defun my-tempel-expand ()
    (tempel-expand t))
  ; I've edited tempel--interactive not to error so this works
  (add-hook 'cdlatex-tab-hook #'my-tempel-expand)
  (add-hook 'LaTeX-mode-hook #'turn-on-cdlatex)
  (add-hook 'org-mode-hook #'turn-on-org-cdlatex)
  )
diff --git a/cdlatex.el b/cdlatex.el
index 4c85b87..0d657dd 100644
--- a/cdlatex.el
+++ b/cdlatex.el
@@ -443,7 +443,8 @@ indicating the label types for which it should be true."

 (defcustom cdlatex-math-symbol-prefix ?`
   "Prefix key for `cdlatex-math-symbol'.
-This may be a character, a string readable with `read-kbd-macro', or a
+This may be a character, a string readable with `read-kbd-macro'
+(doesn't work because of format specificer in cdlatex-math-symbol) , or a
 Lisp vector."
   :group 'cdlatex-math-support
   :type '(choice

laas auto-activating-snippets

  • laas.el isn’t much code at all, and I really don’t care for the laas-subscript-snippets, and I could probably better tailor laas-basic-snippets to my needs, so consider just copying it here
(use-package laas
  :elpaca (laas :host github :repo "akirakyle/LaTeX-auto-activating-snippets")
  :hook ((LaTeX-mode org-mode) . laas-mode)
  :init
  (setq laas-enable-auto-space nil)
  )

pdf-tools

(use-package pdf-tools
  :mode (("\\.pdf\\'" . pdf-view-mode))
  :config
  (evil-collection-define-key 'normal 'pdf-view-mode-map
    "u" 'pdf-view-scroll-down-or-previous-page
    "d" 'pdf-view-scroll-up-or-next-page
    "J" 'pdf-view-next-page-command
    "K" 'pdf-view-previous-page-command
    "<right>" 'image-forward-hscroll
    "<left>" 'image-backward-hscroll
    (kbd "C-u") 'pdf-view-scroll-down-or-previous-page
    (kbd "C-d") 'pdf-view-scroll-up-or-next-page
    (kbd "C-s") 'pdf-occur
    )
  (setq pdf-view-use-scaling t)
  (setq pdf-view-resize-factor 1.1)
  (setq pdf-cache-image-limit 8)
  (setq image-cache-eviction-delay 1)
  ; https://github.com/politza/pdf-tools/issues/467
  ; https://github.com/politza/pdf-tools/issues/177
  (add-hook 'pdf-view-mode-hook #'pdf-links-minor-mode)
  (add-hook 'pdf-view-mode-hook #'pdf-isearch-minor-mode)

  ; Not quite the same issue I was having but relevant since it still fixes it
  ; https://github.com/politza/pdf-tools/issues/201
  ; This fixes the performance issue switching evil states
  ; I suspect this was due to changing the cursor and was especially bad on large monitors
  ;(evil-set-initial-state 'pdf-view-mode 'normal)
  (add-hook 'pdf-view-mode-hook
            (lambda ()
              (set (make-local-variable 'evil-normal-state-cursor) (list nil))))
  (setq pdf-annot-activate-created-annotations t)
  (setq pdf-annot-default-annotation-properties
        `((t (label . ,user-full-name))
          (text (icon . "Comment")
                (color . "#ff0000"))
          (highlight (color . "yellow"))
          (squiggly (color . "orange"))
          (strike-out(color . "red"))
          (underline (color . "blue"))))
  )

epub

(use-package nov
  :mode (("\\.epub\\'" . nov-mode))
  )

markdown

(use-package markdown-mode)

lua

(use-package lua-mode
  :config
  )

julia

(use-package julia-mode)

json

(use-package json-mode)

haskell+tidal

(use-package haskell-mode)
;(use-package tidal
;  :config
;  (add-hook 'tidal-mode-hook (lambda () (interactive-haskell-mode 0))))

swift

(use-package swift-mode)

ibuffer

(use-package ibuffer
  :elpaca nil
  :config
  (general-def
    :states 'normal
    :keymaps 'ibuffer-mode-map
    "<tab>" 'ibuffer-visit-buffer-other-window-noselect)
  )

dired

(setq delete-by-moving-to-trash t)
(setq trash-directory "~/.Trash")

(setq dired-listing-switches "-alhv")
(setq dired-guess-shell-alist-user
      (list (list "\\.pdf" "open")))
(put 'dired-find-alternate-file 'disabled nil)

(general-def
  :keymaps 'dired-mode-map
  :states 'normal
  "gj" 'dired-next-subdir
  "gk" 'dired-prev-subdir
  )

eshell

(elpaca-wait)
(add-hook 'eshell-mode-hook
          #'(lambda ()
              (define-key eshell-mode-map (kbd "<tab>") 'completion-at-point)))

(evil-define-key 'insert eshell-mode-map 
  (kbd "C-p") 'eshell-previous-input 
  (kbd "C-n") 'eshell-next-input)

comint

(setq shell-default-height 40)
(setq shell-default-position 'full)
(setq shell-default-full-span nil)
(setq shell-default-term-shell "/usr/local/bin/bash")
;;(setq shell-default-shell 'shell)
(push (cons "\\*shell\\*" display-buffer--same-window-action) display-buffer-alist)
;;(setq term-color-black ((t (:foreground "dim gray"))))

(evil-define-key 'normal comint-mode-map (kbd "C-p") 'comint-previous-input
  (kbd "C-n") 'comint-next-input)
(evil-define-key 'insert comint-mode-map (kbd "C-p") 'comint-previous-input
  (kbd "C-n") 'comint-next-input)
(evil-define-key 'normal comint-mode-map (kbd "C-l") 'comint-clear-buffer)
(evil-define-key 'insert comint-mode-map (kbd "C-l") 'comint-clear-buffer)
(evil-define-key 'normal term-raw-map (kbd "C-p") 'term-send-up
  (kbd "C-n") 'term-send-down)
(evil-define-key 'insert term-raw-map (kbd "C-p") 'term-send-up
  (kbd "C-n") 'term-send-down)

(setq term-char-mode-point-at-process-mark nil)

vterm

(use-package vterm)

magit

(use-package magit
  :config
  (my-leader-def
   "g"  '(:ignore t :which-key "git")
   "gs" 'magit-status
   )
  (define-key magit-mode-map (kbd "M-<tab>") nil)
  (define-key magit-section-mode-map (kbd "C-<tab>") nil)
  (define-key magit-section-mode-map (kbd "M-<tab>") nil)
  (evil-collection-define-key 'normal 'magit-section-mode-map
    [C-tab] nil
    [M-tab] nil
    )
  (setq magit-diff-refine-hunk 'all)
  )

mu4e

(use-package mu4e
  :elpaca nil
  :load-path  "/opt/homebrew/share/emacs/site-lisp/mu/mu4e/"
  :init
  (setq mu4e-completing-read-function 'completing-read)

  (setq mu4e-change-filenames-when-moving t
        mu4e-headers-time-format "%I:%M %p"
        mu4e-headers-date-format "%y-%m-%d"
        ;;mu4e-split-view 'vertical
        ;;mu4e-split-view 'single-window
        ;;mu4e-headers-visible-columns 80
        mu4e-get-mail-command "mbsync -a"
        mu4e-headers-fields '((:maildir . 12)
                              (:flags . 4)
                              (:human-date . 9)
                              ;;(:mailing-list . 10)
                              (:from . 24)
                              (:subject))
        mu4e-headers-sort-field ':date
        mu4e-headers-sort-direction 'ascending
        mu4e-view-show-addresses t
        mu4e-compose-format-flowed t
        mu4e-compose-dont-reply-to-self t
        mu4e-headers-results-limit 1000
        message-send-mail-function 'message-smtpmail-send-it ; For message-mode (Gnus)
        send-mail-function 'smtpmail-send-it ; For mail-mode (Rmail)
        ;;smtpmail-stream-type 'starttls
        ;;mu4e-view-prefer-html nil
        )

  ;; customize the reply-quote-string
  (setq message-citation-line-format "On %a, %b %d, %Y at %I:%M %p, %f wrote:\n")
  ;; choose to use the formatted string
  (setq message-citation-line-function 'message-insert-formatted-citation-line)

  :config

  (general-define-key
   :states 'normal
   :keymaps 'mu4e-view-mode-map
   "o" 'ace-link-mu4e
   "O" 'mu4e-view-open-attachment)
;;(define-key mu4e-view-mode-map (kbd "f") 'mu4e-view-go-to-url)

  (my-leader-def
   "am" 'mu4e
   )

  <<email.org:mu4e-blk()>>

  ;;(defun my-mu4e-html2text (msg)
  ;;  "My html2text function; shows short message inline, show
  ;;long messages in some external browser (see `browse-url-generic-program')."
  ;;  (let ((html (or (mu4e-message-field msg :body-html) "")))
  ;;    (if (> (length html) 20000)
  ;;        (progn
  ;;          (mu4e-action-view-in-browser msg)
  ;;          "[Viewing message in external browser]")
  ;;      (mu4e-shr2text msg))))

  (setq mu4e-html2text-command 'mu4e-shr2text); my-mu4e-html2text

  (defun my-mu4e-action-view-in-browser (msg)
  "Show current MSG in browser if it includes an HTML-part.
The variables `browse-url-browser-function',
`browse-url-handlers', and `browse-url-default-handlers'
determine which browser function to use."
  (with-temp-buffer
    (insert-file-contents-literally
     (mu4e-message-field msg :path) nil nil nil t)
    (run-hooks 'gnus-article-decode-hook)
    (when (re-search-forward "<!DOCTYPE[^>]*>" nil t)
      (replace-match ""))
    (when (re-search-forward "<html[^>]*>" nil t)
      (replace-match "<html>"))
    (let ((header (cl-loop for field in '("from" "to" "cc" "date" "subject")
                           when (message-fetch-field field)
                           concat (format "%s: %s\n" (capitalize field) it)))
          (parts (mm-dissect-buffer t t)))
      ;; If singlepart, enforce a list.
      (when (and (bufferp (car parts))
                 (stringp (car (mm-handle-type parts))))
        (setq parts (list parts)))
      ;; Process the list
      (unless (gnus-article-browse-html-parts parts header)
        (mu4e-warn "Message does not contain a \"text/html\" part"))
      (mm-destroy-parts parts))))

  (setq mu4e-view-actions
        '(("capture message" . mu4e-action-capture-message)
          ("view in browser" . my-mu4e-action-view-in-browser)
          ("show this thread" . mu4e-action-show-thread)))

  (add-hook 'mu4e-view-mode-hook (lambda () (visual-line-mode 1)))

  (custom-theme-set-faces
   'user
   '(variable-pitch ((t (:family "DejaVu Sans" :height 120)))))

  (add-hook 'message-mode-hook (lambda () (whitespace-mode -1)))
  (add-hook 'message-mode-hook (lambda () (auto-fill-mode -1)))
  (add-hook 'message-mode-hook (lambda () (visual-line-mode 1)))
  )

pass

Super inconvient bug preventing saving of files https://dev.gnupg.org/T6481

(use-package pass)

xwidget-webkit

;(add-hook 'xwidget-webkit-mode-hook 'posframe-delete-all)

webkit

(use-package webkit
  :straight (webkit :type git :host github :repo "akirakyle/emacs-webkit"
                    :branch "main"
                    :files (:defaults "*.js" "*.css" "*.so")
                    :pre-build ("nix-shell" "--command" "make clean && make"))
  :init
  (setq browse-url-browser-function 'webkit-browse-url)
  ;(setq browse-url-browser-function 'xwidget-webkit-browse-url)
  (setq webkit-browse-url-force-new t)
  (setq webkit-search-prefix "https://google.com/search?q=")
  (setq webkit-ace-chars "aoeuidhtns")
  ;(setq webkit-dark-mode t)
  :config
  (my-leader-def
    "," 'webkit
    )

  (defun webkit--display-progress (progress)
    (setq webkit--progress-formatted
          (if (equal progress 100.0)
              ""
            (format "%s%.0f%%  " (all-the-icons-faicon "spinner") progress)))
    (force-mode-line-update))

  (defun my-mu4e-action-view-in-webkit (msg)
    (add-hook 'webkit-new-hook #'webkit-enable-javascript)
    (webkit-browse-url (concat "file://"
                               (mu4e~write-body-to-html msg)) t)
    (remove-hook 'webkit-new-hook #'webkit-enable-javascript))

  ;(add-to-list 'mu4e-view-actions
  ;             '("open in browser" . mu4e-action-view-in-browser) t)

(defun my-webkit-secure ()
  (interactive)
  (let ((cookie-file "~/.emacs.d/webkit/cookies-centos"))
    (webkit-set-proxy "socks://localhost:8000")
    (delete-file (expand-file-name cookie-file))
    (webkit-set-cookie-file cookie-file)))

(defun my-webkit-secure-start ()
  (interactive)
  (start-process "socks" "*socks*" "ssh" "centos" "ip a")
  (start-process "socks" "*socks*" "ssh" "-CND" "8000" "centos"))

)

(use-package webkit-ace
  :straight nil)

(use-package webkit-dark
  :straight nil)

(use-package evil-collection-webkit
  :straight nil
  :config
  (evil-collection-xwidget-setup)
  )

Desktop

;;(use-package desktop
;;  :init
;;  (setq desktop-restore-frames nil)
;;  )

GCMH

(use-package gcmh
  :init
  (setq gcmh-high-cons-threshold #x10000000)
  :config
  (gcmh-mode 1)
  )

Server

;(server-start)