Files
nixos/home/emacs.org
2025-09-16 15:02:56 -04:00

15 KiB
Raw Blame History

Emacs litterate config file

I am using straight as the backend for use package and have thusly set it in [./early-init.el]

Use-Package

Install use-package and enable ':ensure t' globally.

  (straight-use-package 'use-package)
  (setq use-package-always-ensure t)
  (use-package straight
    :custom
    (straight-use-package-by-default t))

As a lifetime vim user I need to evil keys set up early

Overrides

  (setq custom-file (locate-user-emacs-file "custom-vars.el"))
  (load custom-file 'noerror 'nomessage)
  (setq global-auto-revert-non-file-buffers 't)

Evil Mode

Undo-Tree

evil mode requires undo-tree so I have it set to compress the undo files and enable undo-tree mode globally

        (use-package undo-tree :config
          (global-undo-tree-mode)
          (setq undo-tree-auto-save-history t)
          (defadvice undo-tree-make-history-save-filename
    	  (after undo-tree activate)
  	  (setq ad-return-value (concat ad-return-value ".gz"))))

goto-chg

It also requires goto-chg

  (use-package goto-chg)

Evil Mode

Now I hook in Evil mode

  (use-package evil :config
    (evil-mode 1)
    (setq evil-search-module 'evil-search)
    (setq evil-shift-width 2)
    (setq evil-split-window-below 't)
    (setq evil-vsplit-window-right 't)
    (setq show-paren-mode 't)
    (setq evil-undo-system 'undo-tree))
  (evil-set-leader '(normal visual motion) (kbd "SPC"))
  (evil-define-key 'normal 'global
    (kbd "<leader>f f") 'file-file
    (kbd "<leader>f s") 'save-buffer
    (kbd "<leader>f r") 'recentf-open-files
    (kbd "<leader>e e") 'eval-buffer)

Evil Collection

  (use-package evil-collection :after evil
    :ensure t
    :config
    (evil-collection-init))
  (use-package evil-org :after org
    :ensure t
    :hook (org-mode . (lambda () evil-org-mode))
    :config
    (require 'evil-org-agenda)
    (evil-org-agenda-set-keys)
    (setf evil-org-key-theme '(navigation insert textobjects additional))
    (setf org-special-ctrl-a/e t))

UI

  (use-package treemacs :config
    (evil-define-key 'normal 'global (kbd "<leader> f e") 'treemacs))

Enable which key mode

  (which-key-mode)

Theming

Fonts / icons

Icons must be installed 'all-the-icons-install

  (use-package all-the-icons
    :if (display-graphic-p))
  (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode))

UI System

  (require 'recentf)
  (recentf-mode 1)
  (setq history-length 50)
  (savehist-mode 1)
  (setq recentf-max-menu-items 25)
  (save-place-mode 1)
  (menu-bar-mode -1)
  (tool-bar-mode -1)
  (scroll-bar-mode -1)
  (global-display-line-numbers-mode 1)
  (hl-line-mode 1)
  (blink-cursor-mode 1)

Color Scheme -> load-theme here

  (use-package doom-themes
  :ensure t
  :config
  ;; Global settings (defaults)
  (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
        doom-themes-enable-italic t) ; if nil, italics is universally disabled
  (load-theme 'doom-tokyo-night t)
  (doom-themes-visual-bell-config)
  (doom-themes-neotree-config)
  (setq doom-themes-treemacs-theme "doom-tokyo-night") ; use "doom-colors" for less minimal icon theme
  (doom-themes-treemacs-config)
  ;; Corrects (and improves) org-mode's native fontification.
  (doom-themes-org-config))

Utilities

Completion

counsel
  (use-package counsel :config (counsel-mode))
  (use-package swiper)
  (use-package ivy :config
    (ivy-mode)
    (setq ivy-use-virtual-buffers 't)
    (setq enable-recursive-minibuffers 't)
    (global-set-key "\C-s" 'swiper-isearch)
    (global-set-key (kbd "C-c C-r") 'ivy-resume)
    (global-set-key (kbd "M-x") 'counsel-M-x)
    (global-set-key (kbd "C-x C-f") 'counsel-find-file)
    (global-set-key (kbd "<f1> f") 'counsel-describe-function)
    (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
    (global-set-key (kbd "<f1> o") 'counsel-describe-symbol)
    (global-set-key (kbd "<f1> l") 'counsel-find-library)
    (global-set-key (kbd "<f1> i") 'counsel-info-lookup-symbol)
    (global-set-key (kbd "<f1> u") 'counsel-unicode-char)
    (global-set-key (kbd "C-c g") 'counsel-git)
    (global-set-key (kbd "C-c j") 'counsel-git-grep)
    (global-set-key (kbd "C-c k") 'counsel-ag)
    (global-set-key (kbd "C-x l") 'counsel-locate)
    (global-set-key (kbd "C-S-o") 'counsel-rhythmbox)
    (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history))
  (use-package all-the-icons-ivy-rich
    :ensure t
    :init (all-the-icons-ivy-rich-mode 1))

  (use-package ivy-rich
    :ensure t
    :init (ivy-rich-mode 1))
helpful
  (use-package helpful
    :config
    (global-set-key (kbd "C-h f") #'helpful-callable)
    (global-set-key (kbd "C-h v") #'helpful-variable)
    (global-set-key (kbd "C-h k") #'helpful-key)
    (global-set-key (kbd "C-h x") #'helpful-command)
    (global-set-key (kbd "C-c C-S-d") #'helpful-at-point))

Org Mode

Org Roam

Presents a good example of use-package's capabilities.

  (use-package org-roam :ensure t :after org :custom (org-roam-directory "~/org/roam") :bind
    (("C-c n l" . org-roam-buffer-toggle)
     ("C-c n f" . org-roam-node-find)
     ("C-c n i" . org-roam-node-insert)
     :map org-mode-map
     ("C-M-i" . completion-at-point))
    :init (setq org-roam-v2-ack t)
    :config
     (org-roam-setup))
  (setq org-roam-node-display-template
      (concat "${title:*} "
              (propertize "${tags:10}" 'face 'org-tag)))
  (setq org-roam-database-connector 'sqlite-builtin)
  (setq org-roam-capture-templates '(("d" "default" plain "%?"
     :target (file+head "${slug}.org"
                        "#+title: ${title}\n")
     :unnarrowed t)))
    (org-roam-capture-templates
     '(("d" "default" plain
  	"%?"
  	:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
  	:unnarrowed t)
       ("l" "programming language" plain
  	"* Characteristics\n\n- Family: %?\n- Inspired by: \n\n*Reference:\n\n"
  	:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
  	:unnarrowed t)
       ("b" "book notes" plain
  	"\n* Source\n\nAuthor: %^{Author}\nTitle: ${title}\nYear: %^{Year}\n\n* Summary\n\n%?"
  	:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
  	:unnarrowed t)
       ("p" "project" plain "* Goals\n\n%?\n\n* Tasks\n\n** TODO Add initial tasks\n\n* Dates\n\n"
  	:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: Project")
  	:unnarrowed t))
Capture Templates

Org Agenda

  (setq org-columns-default-format "%50ITEM(Task) %10CLOCKSUM %16TIMESTAMP_IA")

Capture Templates

Agenda Related

[https://d12frosted.io/posts/2020-06-23-task-management-with-roam-vol1.html]

(setq org-capture-templates
       '(("t" "todo" entry (file org-default-notes-file)
	  "* TODO %?\n%u\n%a\n" :clock-in t :clock-resume t)
	 ("m" "Meeting" entry (file org-default-notes-file)
	  "* MEETING with %? :MEETING:\n%t" :clock-in t :clock-resume t)
	 ("d" "Diary" entry (file+datetree "~/org/diary.org")
	  "* %?\n%U\n" :clock-in t :clock-resume t)
	 ("i" "Idea" entry (file org-default-notes-file)
	  "* %? :IDEA: \n%t" :clock-in t :clock-resume t)
	 ("n" "Next Task" entry (file+headline org-default-notes-file "Tasks")
	  "** NEXT %? \nDEADLINE: %t") ))
          (setq org-agenda-prefix-format
              '((agenda . " %i %-12(vulpea-agenda-category)%?-12t% s")
                (todo . " %i %-12(vulpea-agenda-category) ")
                (tags . " %i %-12(vulpea-agenda-category) ")
                (search . " %i %-12(vulpea-agenda-category) ")))

        (defun vulpea-agenda-category ()
          "Get category of item at point for agenda.

        Category is defined by one of the following items:

        - CATEGORY property
        - TITLE keyword
        - TITLE property
        - filename without directory and extension

        Usage example:

          (setq org-agenda-prefix-format
                '((agenda . \" %(vulpea-agenda-category) %?-12t %12s\")))

        Refer to `org-agenda-prefix-format' for more information."
          (let* ((file-name (when buffer-file-name
                              (file-name-sans-extension
                               (file-name-nondirectory buffer-file-name))))
                 (title (vulpea-buffer-prop-get "title"))
                 (category (org-get-category)))
            (or (if (and
                     title
                     (string-equal category file-name))
                    title
                  category)
                "")))
        (defun vulpea-buffer-prop-get (name)
        "Get a buffer property called NAME as a string."
        (org-with-point-at 1
          (when (re-search-forward (concat "^#\\+" name ": \\(.*\\)")
                                   (point-max) t)
            (buffer-substring-no-properties
             (match-beginning 1)
             (match-end 1)))))
        (setq org-agenda-prefix-format
            '((agenda . " %i %(vulpea-agenda-category 12)%?-12t% s")
              (todo . " %i %(vulpea-agenda-category 12) ")
              (tags . " %i %(vulpea-agenda-category 12) ")
              (search . " %i %(vulpea-agenda-category 12) ")))

      (defun vulpea-agenda-category (&optional len)
        "Get category of item at point for agenda.

      Category is defined by one of the following items:

      - CATEGORY property
      - TITLE keyword
      - TITLE property
      - filename without directory and extension

      When LEN is a number, resulting string is padded right with
      spaces and then truncated with ... on the right if result is
      longer than LEN.

      Usage example:

        (setq org-agenda-prefix-format
              '((agenda . \" %(vulpea-agenda-category) %?-12t %12s\")))

      Refer to `org-agenda-prefix-format' for more information."
        (let* ((file-name (when buffer-file-name
                            (file-name-sans-extension
                             (file-name-nondirectory buffer-file-name))))
               (title (vulpea-buffer-prop-get "title"))
               (category (org-get-category))
               (result
                (or (if (and
                         title
                         (string-equal category file-name))
                        title
                      category)
                    "")))
          (if (numberp len)
              (s-truncate len (s-pad-right len " " result))
            result)))
      (defun vulpea-ensure-filetag ()
      "Add respective file tag if it's missing in the current note."
      (interactive)
      (let ((tags (vulpea-buffer-tags-get))
            (tag (vulpea--title-as-tag)))
        (when (and (seq-contains-p tags "people")
                   (not (seq-contains-p tags tag)))
          (vulpea-buffer-tags-add tag))))

    (defun vulpea--title-as-tag ()
      "Return title of the current note as tag."
      (vulpea--title-to-tag (vulpea-buffer-title-get)))

    (defun vulpea--title-to-tag (title)
      "Convert TITLE to tag."
      (concat "@" (s-replace " " "" title)))
    (defun vulpea-tags-add ()
    "Add a tag to current note."
    (interactive)
    ;; since https://github.com/org-roam/org-roam/pull/1515
    ;; `org-roam-tag-add' returns added tag, we could avoid reading tags
    ;; in `vulpea-ensure-filetag', but this way it can be used in
    ;; different contexts while having simple implementation.
    (when (call-interactively #'org-roam-tag-add)
      (vulpea-ensure-filetag)))

    (defun org-roam-node-insert-wrapper (fn)
    "Insert a link to the note using FN.

  If inserted node has PEOPLE tag on it, tag the current outline
  accordingly."
    (interactive)
    (when-let*
        ((node (funcall fn))
         (title (org-roam-node-title node))
         (tags (org-roam-node-tags node)))
      (when (seq-contains-p tags "people")
        (save-excursion
          (ignore-errors
            (org-back-to-heading)
            (org-set-tags
             (seq-uniq
              (cons
               (vulpea--title-to-tag title)
               (org-get-tags nil t)))))))))

  (advice-add
   #'org-roam-node-insert
   :around
   #'org-roam-node-insert-wrapper)

(defun my-vulpea-insert-handle (note)
  "Hook to be called on NOTE after `vulpea-insert'."
  (when-let* ((title (vulpea-note-title note))
              (tags (vulpea-note-tags note)))
    (when (seq-contains-p tags "people")
      (save-excursion
        (ignore-errors
          (org-back-to-heading)
          (when (eq 'todo (org-element-property
                           :todo-type
                           (org-element-at-point)))
            (org-set-tags
             (seq-uniq
              (cons
               (vulpea--title-to-tag title)
               (org-get-tags nil t))))))))))

(defun vulpea--title-to-tag (title)
  "Convert TITLE to tag."
  (concat "@" (s-replace " " "" title)))

(add-hook 'vulpea-insert-handle-functions
          #'my-vulpea-insert-handle)

EXWM

#+begin_src emacs-lisp (require 'exwm) ;; Set the initial workspace number. (setq exwm-workspace-number 4) ;; Make class name the buffer name. (add-hook 'exwm-update-class-hook (lambda () (exwm-workspace-rename-buffer exwm-class-name))) ;; Global keybindings. (setq exwm-input-global-keys `(([?\s-r] . exwm-reset) ;; s-r: Reset (to line-mode). ([?\s-w] . exwm-workspace-switch) ;; s-w: Switch workspace. ([?\s-&] . (lambda (cmd) ;; s-&: Launch application. (interactive (list (read-shell-command "$ "))) (start-process-shell-command cmd nil cmd))) ;; s-N: Switch to certain workspace. ,@(mapcar (lambda (i) `(,(kbd (format "s-%d" i)) . (lambda () (interactive) (exwm-workspace-switch-create ,i)))) (number-sequence 0 9)))) ;; Enable EXWM ;; let's get encryption established (setenv "GPG_AGENT_INFO" nil) ;; use emacs pinentry (setq auth-source-debug t)

(setq epg-gpg-program "gpg2") ;; not necessary (require 'epa-file) (epa-file-enable) (setq epa-pinentry-mode 'loopback) (setq epg-pinentry-mode 'loopback) (pinentry-start)

(require 'org-crypt) (org-crypt-use-before-save-magic) (require 'exwm-randr) (require 'exwm-systemtray) (setq exwm-randr-workspace-output-plist '(o "eDP-1")) (add-hook 'exwm-randr-screen-change-hook (lambda () (start-process-shell-command "xrandr" nil "xrandr output eDP-1 scale .5 filter nearest"))) (exwm-randr-enable) (exwm-systemtray-enable)