Skip to content

arttsu/dotemacs

Repository files navigation

Emacs Config

Table of contents

Notes

Dependencies

Install mpv to play media via EMMS

Fedora

sudo dnf install mpv -y

Install ledger

Fedora

sudo dnf install ledger -y

Set up GPTel

  1. Create a new API key.
  2. Add an entry to ~/.authinfo:
    machine api.openai.com login apikey password TOKEN
        

Set up Vterm

Fedora

Install fish
sudo dnf install fish -y
Change shell
chsh

After entering the password, enter the path to fish - /usr/bin/fish.

Log out and back in to make this effective.

Install dependencies for compilation
sudo dnf install cmake libtool -y

All systems

Configure fish to work w/ vterm as described in https://github.com/akermu/emacs-libvterm?tab=readme-ov-file#shell-side-configuration.

Set up Copilot

Install Node.js

Fedora
sudo dnf install nodejs -y

Install Copilot server

M-x copilot-install-server

Login to Copilot

M-x copilot-login

Set up Jinx

Jinx requires libenchant.

On Fedora, install enchant2-devel, pkgconf. Additional languages are available as hunspell-* packages, e.g. hunspell-ru.

Set up Ripgrep

On Fedora, install ripgrep package.

Eglot: Metals

coursier bootstrap \
  --java-opt -XX:+UseG1GC \
  --java-opt -XX:+UseStringDeduplication  \
  --java-opt -Xss4m \
  --java-opt -Xms100m \
  --java-opt -Dmetals.client=emacs \
  org.scalameta:metals_2.13:1.3.1 -o ~/bin/metals -f

Anki

  1. Install Anki (Instructions for Linux)
  2. Add anki-connect addon

Notdeft

Build Xapian Backend

  1. Go to ~/$EMACS_HOME/straight/build/notdeft/xapian
  2. Run make
Fedora

Need to install tclap and xapian-core-devel packages.

Setup

Declare flags

(setq my-use-copilot nil)
(setq my-use-aider nil)

Load local config

(load (expand-file-name "local.el" user-emacs-directory))

OS helpers

(defun my-windows-p ()
  (eq system-type 'windows-nt))

(defun my-mac-p ()
  (eq system-type 'darwin))

(defun my-env-flag (name)
  (let ((value (getenv name)))
    (and value (or (string= value "1") (string= value "true")))))

Add ‘lisp’ dir to load path

(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))

Windows: Add Git to path

(when (my-windows-p)
  (setenv "PATH" (concat my-git-path ";" (getenv "PATH")))
  (push my-git-path exec-path))

Straight

https://github.com/radian-software/straight.el

Pre-bootstrap

(setq package-enable-at-startup nil)

Bootstrap

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name
        "straight/repos/straight.el/bootstrap.el"
        (or (bound-and-true-p straight-base-dir)
            user-emacs-directory)))
      (bootstrap-version 7))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

Post-bootstrap

(setq straight-use-package-by-default t)

MacOS: Exec path from shell

(use-package exec-path-from-shell
  :when (my-mac-p)
  :config
  (exec-path-from-shell-initialize))

Packages

Helpers

Pop mark

(defun my-pop-mark (&optional prefix)
  (interactive "P")
  (cond ((equal prefix nil) (set-mark-command '(4)))
        ((equal prefix '(4)) (avy-pop-mark))
        (t (error "Invalid prefix argument: %s" prefix))))

Insert date or datetime

(defun my-insert-current-date-or-datetime (&optional include-time)
  "Insert the current date (YYYY-MM-DD) or datetime (YYYY-MM-DDTHH-MM-SS) at point.
With a prefix argument, include the time."
  (interactive "P")
  (let ((format (if include-time "%Y-%m-%dT%H-%M-%S" "%Y-%m-%d")))
    (insert (format-time-string format))))

Emacs

(use-package emacs
  :custom
  (inhibit-splash-screen t)
  (initial-major-mode 'text-mode)
  (initial-scratch-message "✅ All systems go! 🚀🪐✨")
  (disabled-command-function nil)
  (visible-bell t)
  (save-interprogram-paste-before-kill t)
  (global-auto-revert-non-file-buffers t)
  (create-lockfiles nil)
  (make-backup-files nil)
  (custom-file (expand-file-name "custom.el" user-emacs-directory))
  (require-final-newline t)
  (indent-tabs-mode nil)
  (tab-always-indent 'complete)
  (read-extended-command-predicate #'command-completion-default-include-p)
  (backward-delete-char-untabify-method 'hungry)
  (split-width-threshold 200)
  (split-height-threshold 60)
  (epa-file-encrypt-to (list my-gpg-key-id))
  (epa-pinentry-mode 'loopback)
  :config
  (add-to-list 'default-frame-alist '(fullscreen . maximized))
  (scroll-bar-mode -1)
  (tool-bar-mode -1)
  (menu-bar-mode -1)
  (fset 'yes-or-no-p 'y-or-n-p)
  (add-hook 'prog-mode-hook 'display-line-numbers-mode)
  (global-auto-revert-mode)
  (global-subword-mode)
  (tab-bar-history-mode)
  (tab-bar-mode)
  (repeat-mode)
  :bind
  (("C-c j x" . scratch-buffer)
   ("C-x C-b" . ibuffer-other-window)
   ("M-g w" . forward-to-word)
   ("M-g W" . backward-to-word)
   ("C-M-; d" . duplicate-dwim)
   ("C-c d h" . erase-buffer)
   ("M-z" . zap-up-to-char)
   ("M-Z" . zap-to-char)
   ("C-x K" . kill-this-buffer)
   ("s-t" . tab-switch)
   ([down-mouse-2] . mouse-set-point)
   ([mouse-2] . delete-window)
   ("<f8>" . my-pop-mark)
   ("C-M-<return>" . tab-switch)
   ("C-c t" . my-insert-current-date-or-datetime)
   :map prog-mode-map
   ("DEL" . backward-delete-char-untabify)
   ("M-g N" . flymake-goto-next-error)
   ("M-g P" . flymake-goto-prev-error)))

My Emacs

lisp/my-emacs.org

(use-package my-emacs
  :straight nil
  :demand
  :after emacs
  :bind
  (("C-c d w" . my/kill-forward-to-word)
   ("C-c d W" . my/kill-backward-to-word)
   ("C-c d <" . my/kill-to-beginning-of-buffer)
   ("C-c d >" . my/kill-to-end-of-buffer)
   ("C-c j h" . my/jump-home)))

envrc

(use-package envrc
  :hook (after-init . envrc-global-mode))

Modus Themes

https://protesilaos.com/emacs/modus-themes

(use-package modus-themes
  :custom
  (modus-themes-italic-constructs t)
  (modus-themes-org-blocks 'gray-background)
  (modus-themes-headings '((0 . (ultrabold 1.7))
                           (1 . (ultrabold 1.7))
                           (2 . (extrabold 1.5))
                           (3 . (extrabold 1.3))
                           (4 . (extrabold 1.1))
                           (t . (extrabold))))
  (modus-themes-variable-pitch-ui t)
  :config
  (modus-themes-load-theme 'modus-vivendi))

Font

(set-face-attribute 'default nil :font my-font :height my-font-height)
(set-frame-font my-font nil t)

(when (my-windows-p)
  (set-fontset-font t 'unicode "Segoe UI Emoji" nil 'append))

Dired

Dired interactive functions

Dired: Rename files to their modification time timestamp

(defun my-dired-rename-to-timestamp ()
  (interactive)
  (let ((files (dired-get-marked-files)))
    (dolist (file files)
      (let* ((attributes (file-attributes file))
             (mod-time (file-attribute-modification-time attributes))
             (timestamp (format-time-string "%Y%m%d%H%M%S" mod-time))
             (new-name (concat timestamp (file-name-extension file t)))
             (new-path (concat (file-name-directory file) new-name)))
        (dired-rename-file file new-path nil)))))

Configure Dired

(use-package dired
  :straight nil
  :custom
  (dired-dwim-target t)
  (insert-directory-program (cond ((my-windows-p) insert-directory-program)
                                  ((my-mac-p) "gls")
                                  (t "ls")))
  (dired-listing-switches (cond ((my-windows-p) dired-listing-switches)
                                (t "-alh --group-directories-first")))
  :bind
  (("<f7>" . dired-jump)
   :map dired-mode-map
   ("o" . crux-open-with)
   ("<tab>" . dired-find-file-other-window)
   ("C-c D t" . my-dired-rename-to-timestamp)))

Project

(use-package project
  :config
  (add-to-list 'project-switch-commands '(project-dired "Dired" "<return>") t))

My project

lisp/my-project.org

(use-package my-project
  :straight nil
  :after project
  :demand
  :bind
  (("C-x p P" . my-project-open-new-frame)
   ("C-x p v" . my-project-vterm)))

Super Save

https://github.com/bbatsov/super-save

(use-package super-save
  :custom
  (super-save-all-buffers t)
  (super-save-auto-save-when-idle t)
  (super-save-delete-trailing-whitespace 'except-current-line)
  (super-save-silent t)
  (super-save-exclude '(".sbt" "project/" ".gpg"))
  (auto-save-default nil)
  :config
  (super-save-mode))

EMMS

https://www.gnu.org/software/emms/manual/#Introduction

(use-package emms
  :unless (my-windows-p)
  :custom
  (emms-player-list '(emms-player-mpv))
  (emms-player-mpv-update-metadata t)
  (emms-streams-file (expand-file-name "streams.emms" user-emacs-directory))
  :config
  (emms-all)
  :bind
  (("C-c r r" . emms-streams)
   ("C-c r p" . emms-pause)
   ("C-c r s" . emms-stop)))

Ace Window

https://github.com/abo-abo/ace-window

(use-package ace-window
  :custom
  (aw-keys '(?a ?s ?d ?f ?g ?h ?k ?l))
  (aw-scope 'frame)
  :bind
  (("M-o" . ace-window)))

Vertico

https://github.com/minad/vertico

(use-package vertico
  :demand
  :config
  (vertico-mode)
  (vertico-multiform-mode)
  (add-to-list 'vertico-multiform-categories
               '(jinx grid (vertico-grid-annotate . 20)))
  (add-to-list 'vertico-multiform-commands
               '(consult-ripgrep buffer indexed))
  :bind
  (:map vertico-map
        ("C-;" . vertico-quick-insert)))

Savehist

(use-package savehist
  :config
  (savehist-mode))

Orderless

https://github.com/oantolin/orderless

(use-package orderless
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles partial-completion)))))

Consult

https://github.com/minad/consult

(use-package consult
  :config
  ;; Don't live preview buffers to avoid triggering package loading.
  ;; See https://github.com/minad/consult#live-previews
  (consult-customize consult-buffer :preview-key "M-.")
  :bind
  (("C-x b" . consult-buffer)
   ("C-x 4 b" . consult-buffer-other-window)
   ("C-x 5 b" . consult-buffer-other-frame)
   ("C-x p b" . consult-project-buffer)
   ("M-g M-g" . consult-goto-line)
   ("M-g o" . consult-outline)
   ("M-s r" . consult-ripgrep)
   ("M-s l" . consult-line)
   ("M-s k" . consult-keep-lines)
   ("M-s f" . consult-focus-lines)))

My Consult

lisp/my-consult.org

(use-package my-consult
  :straight nil
  :after (consult org))

Corfu

https://github.com/minad/corfu

(use-package corfu
  :demand
  :custom
  (corfu-cycle t)
  (corfu-auto t)
  (corfu-auto-prefix 2)
  (corfu-quit-at-boundary 'separator)
  (corfu-quit-no-match t)
  :config
  (global-corfu-mode)
  (corfu-history-mode)
  :bind
  (:map corfu-map
        ("C-SPC" . corfu-insert-separator)
        ("C-;" . corfu-quick-insert)))

Company

(use-package company
  :init
  (setq company-minimum-prefix-length 2)
  (setq company-idle-delay 0.2)
  (setq company-selection-wrap-around t)
  (setq company-dabbrev-downcase nil)
  (setq company-show-numbers t)
  :config
  (global-company-mode))

Smartparens

https://github.com/Fuco1/smartparens

(use-package smartparens
  :hook
  (prog-mode . smartparens-mode)
  :config
  (require 'smartparens-config)
  :bind
  (:map smartparens-mode-map
        ("C-<right>" . sp-forward-slurp-sexp)
        ("C-<left>" . sp-backward-slurp-sexp)
        ("M-<right>" . sp-forward-barf-sexp)
        ("M-<left>" . sp-backward-barf-sexp)
        ("M-a" . sp-beginning-of-sexp)
        ("M-e" . sp-end-of-sexp)
        ("C-M-u" . sp-up-sexp)
        ("C-M-S-u" . sp-backward-up-sexp)
        ("C-M-d" . sp-down-sexp)
        ("C-M-S-d" . sp-backward-down-sexp)
        ("C-c p u" . sp-unwrap-sexp)
        ("C-c p (" . sp-wrap-round)
        ("C-c p [" . sp-wrap-square)
        ("C-c p {" . sp-wrap-curly)
        ("C-c p r" . sp-rewrap-sexp)))

Yasnippet

https://github.com/joaotavora/yasnippet

(use-package yasnippet
  :custom
  (yas-snippet-dirs (list (expand-file-name "snippets" user-emacs-directory)))
  :config
  (yas-global-mode))

Avy

https://github.com/abo-abo/avy

(use-package avy
  :custom
  (avy-single-candidate-jump t)
  :bind
  (("C-;" . avy-goto-char-timer)
   ("M-;" . avy-pop-mark)
   ("M-g g" . avy-goto-line)
   ("M-g G" . avy-goto-end-of-line)
   ("M-g h" . avy-org-goto-heading-timer)
   ("M-g s" . avy-goto-word-1)
   ("C-M-; c" . avy-copy-line)
   ("C-M-; C" . avy-copy-region)
   ("C-M-; m" . avy-move-line)
   ("C-M-; M" . avy-move-region)
   ("C-M-; k" . avy-kill-whole-line)
   ("C-M-; K" . avy-kill-region)
   ("C-M-; s" . avy-kill-ring-save-whole-line)
   ("C-M-; S" . avy-kill-ring-save-region)
   :map isearch-mode-map
   ("C-;" . avy-isearch)))

My Avy-Embark

lisp/my-avy-embark.org

(use-package my-avy-embark
  :straight nil
  :after avy
  :config
  (setf (alist-get ?. avy-dispatch-alist) 'my-avy-embark)
  (setf (alist-get ?\; avy-dispatch-alist) 'my-avy-embark-dwim))

Link hint

https://github.com/noctuid/link-hint.el

(use-package link-hint
  :bind
  (("C-c f" . link-hint-open-link)
   ("C-c y" . link-hint-copy-link)))

Crux

https://github.com/bbatsov/crux

(use-package crux
  :bind
  (("C-o" . crux-smart-open-line)
   ("C-S-o" . crux-smart-open-line-above)
   ("C-^" . crux-top-join-line)
   ("C-M-; D" . crux-duplicate-and-comment-current-line-or-region)))

Whole Line or Region

https://github.com/purcell/whole-line-or-region

(use-package whole-line-or-region
  :demand
  :config
  (whole-line-or-region-global-mode)
  :bind
  (("M-/" . whole-line-or-region-comment-dwim)))

Multiple Cursors

https://github.com/magnars/multiple-cursors.el

(use-package multiple-cursors
  :bind
  (("C-+" . mc/mark-next-like-this)
   ("C-c k l" . mc/edit-lines)
   ("C-c k m" . mc/mark-all-dwim)
   ("C-S-<mouse-1>" . mc/add-cursor-on-click)
   ("C-<return>" . set-rectangular-region-anchor)))

Expand Region

https://github.com/magnars/expand-region.el

(use-package expand-region
  :bind
  (("C-=" . er/expand-region)))

Go to Char

https://github.com/doitian/iy-go-to-char

(use-package iy-go-to-char
  :bind
  (("M-g f" . iy-go-to-char)
   ("M-g F" . iy-go-to-char-backward)
   ("M-g t" . iy-go-up-to-char)
   ("M-g T" . iy-go-up-to-char-backward)
   ("M-g ;" . iy-go-to-or-up-to-continue)
   ("M-g ," . iy-go-to-or-up-to-continue-backward)))

Magit

https://magit.vc/

(use-package magit
  :bind
  (("C-c g" . magit-file-dispatch)))

Org mode

https://orgmode.org/

Org files

(defconst my-open-org-dir "~/org-open")

(defconst my-local-gtd-dir (concat my-local-org-dir "/gtd"))
(defconst my-open-gtd-dir (concat my-open-org-dir "/gtd"))

(defun my-gtd-path (name)
  (expand-file-name (concat my-local-gtd-dir name ".org")))

(defconst my-gtd-inbox (my-gtd-path "/inbox"))

(defconst my-local-gtd-projects-dir (expand-file-name "projects" my-local-gtd-dir))
(defconst my-local-gtd-areas-dir (expand-file-name "areas" my-local-gtd-dir))
(defconst my-open-gtd-projects-dir (expand-file-name "projects" my-open-gtd-dir))
(defconst my-open-gtd-areas-dir (expand-file-name "areas" my-open-gtd-dir))

(defconst my-local-gtd-files `(,my-local-gtd-dir ,my-local-gtd-projects-dir ,my-local-gtd-areas-dir))
(defconst my-open-gtd-files `(,my-open-gtd-dir ,my-open-gtd-projects-dir ,my-open-gtd-areas-dir))
(defconst my-all-gtd-files (append my-local-gtd-files my-open-gtd-files))

(defconst my-local-notes (expand-file-name "notes" my-local-org-dir))
(defconst my-open-notes (expand-file-name "notes" my-open-org-dir))

Setup helpers

To run on the mode hook

(defun my-org-setup ()
  (setq-local fill-column 120)
  (auto-fill-mode 1))

Helpers

(defun my-org-files-in-dir (dir)
  (directory-files dir t "\\.org$"))

Remove priority to the default one when completing a todo

(defun my-org-remove-priority-when-done ()
  (when (string= org-state "DONE")
    (ignore-errors (org-entry-put (point) "PRIORITY" nil))))

Extract created/closed timestamp

(defun my-org-extract-closed-timestamp ()
  (save-excursion
    (save-restriction
      (org-narrow-to-subtree)
      (goto-char (point-min))
      (if (re-search-forward "CLOSED: " nil t)
          (buffer-substring-no-properties (point) (line-end-position))
        "[1900-01-01 Mon 00:00]"))))

(defun my-org-extract-created-timestamp ()
  (save-excursion
    (save-restriction
      (org-narrow-to-subtree)
      (goto-char (point-min))
      (if (re-search-forward "# CREATED: " nil t)
          (buffer-substring-no-properties (point) (line-end-position))
        "[1900-01-01 Mon 00:00]"))))

Interactive Helpers

Sort TODOs

(defun my-org-sort-todos ()
  (interactive)
  (unless (org-at-heading-p)
    (error "Not at a heading"))
  (org-sort-entries nil ?f 'my-org-extract-created-timestamp)
  (org-sort-entries nil ?f 'my-org-extract-closed-timestamp)
  (org-sort-entries nil ?p)
  (org-sort-entries nil ?o)
  (org-cycle)
  (org-cycle))

(defun my-org-sort-todos-after-refile ()
  (org-up-heading-safe)
  (let ((sort-todos (org-entry-get (point) "SORT_TODOS")))
    (when (and sort-todos
               (string= sort-todos "yes"))
      (my-org-sort-todos))))

Jump to the last item of a subtree

(defun my-org-end-of-subtree ()
  "Jump to the last item of the current subtree."
  (interactive)
  (org-end-of-subtree)
  (org-back-to-heading))

Add an update

(defun my-org-add-update ()
  "Add an update entry with a timestamp to the current Org heading."
  (interactive)
  (org-end-of-subtree)
  (end-of-line)
  (newline-and-indent)
  (insert (format "# Upd. %s" (format-time-string "<%Y-%m-%d %H:%M>")))
  (newline-and-indent))

Insert a heading w/ a timestamp

(defun my-org-insert-timestamped-heading ()
  (interactive)
  (org-insert-heading-respect-content)
  (forward-line)
  (insert "# CREATED: ")
  (org-insert-timestamp (current-time) t t)
  (insert "\n")
  (forward-line -2)
  (end-of-line))

Duplicate a subtree

(defun my-org-duplicate-subtree ()
  (interactive)
  (when (org-at-heading-p)
    (beginning-of-line)
    (org-copy-subtree)
    (org-paste-subtree)
    (org-delete-property "ID")))

Refile a note

(defun my-org-refile-note ()
  (interactive)
  (let ((original-targets org-refile-targets))
    (unwind-protect
        (progn
          (setq org-refile-targets `((,(append (my-org-files-in-dir my-local-notes) (my-org-files-in-dir my-open-notes)) :level 2)))
          (org-refile))
      (setq org-refile-targets original-targets))))

Capturing

(defun my-org-capture-template-path (name)
  (expand-file-name (concat "capture-templates/" name ".txt") user-emacs-directory))

(defconst my-gtd-inbox-target `(file+headline ,my-gtd-inbox "Inbox items"))

(defconst my-gtd-capture-templates
  `(("i" "Inbox")
    ("ii" "note" entry ,my-gtd-inbox-target (file ,(my-org-capture-template-path "gtd-note")))
    ("iI" "todo" entry ,my-gtd-inbox-target (file ,(my-org-capture-template-path "gtd-todo")))
    ("il" "note link" entry ,my-gtd-inbox-target (file ,(my-org-capture-template-path "gtd-note-link")))
    ("iL" "todo link" entry ,my-gtd-inbox-target (file ,(my-org-capture-template-path "gtd-todo-link")))))

(defun my-gtd-capture-note (&optional prefix)
  (interactive "P")
  (cond ((equal prefix nil) (org-capture nil "ii"))
        ((equal prefix '(4)) (org-capture nil "il"))
        (t (error "Invalid prefix argument: %s" prefix))))

(defun my-gtd-capture-todo (&optional prefix)
  (interactive "P")
  (cond ((equal prefix nil) (org-capture nil "iI"))
        ((equal prefix '(4)) (org-capture nil "iL"))
        (t (error "Invalid prefix argument: %s" prefix))))

Agendas

“Day” agenda

(defun my-org-day-agenda-skip-todo-if ()
  (let ((subtree-end (save-excursion (org-end-of-subtree t)))
        (scheduled (org-get-scheduled-time (point)))
        (deadline (org-get-deadline-time (point)))
        (priority (org-get-priority (thing-at-point 'line t)))
        (tags (org-get-tags))
        (category (org-get-category)))
    (if (or scheduled
            deadline
            (or (string= category "SOMEDAY") (string= category "OPENINBOX"))
            (< priority 1000)
            (and (or (member "PROJECT" tags) (member "AREA" tags))
                 (< priority 3000)))
        subtree-end)))

(defun my-org-day-agenda-skip-project-if ()
  (let ((subtree-end (save-excursion (org-end-of-subtree t)))
        (priority (org-get-priority (thing-at-point 'line t))))
    (if (< priority 1000)
        subtree-end)))

(defun my-org-day-agenda-not-high-prio-someday-p ()
  (let ((subtree-end (save-excursion (org-end-of-subtree t)))
        (scheduled (org-get-scheduled-time (point)))
        (deadline (org-get-deadline-time (point)))
        (priority (org-get-priority (thing-at-point 'line t)))
        (tags (org-get-tags))
        (category (org-get-category)))
    (if (or scheduled
            deadline
            (not (string= category "SOMEDAY"))
            (< priority 3000))
        subtree-end)))

(defconst my-org-day-agenda
  `("d" "Day" ((agenda "" ((org-agenda-span 1)
                           (org-agenda-skip-scheduled-if-done t)
                           (org-agenda-skip-deadline-if-done t)
                           (org-agenda-skip-timestamp-if-done t)))
               (todo "TODO" ((org-agenda-overriding-header "Ad-hoc tasks and high-prio project tasks")
                             (org-agenda-skip-function 'my-org-day-agenda-skip-todo-if)
                             (org-agenda-files ',my-local-gtd-files)))
               (tags "+PROJECT" ((org-agenda-overriding-header "Projects")
                                 (org-tags-match-list-sublevels nil)
                                 (org-agenda-sorting-strategy '(priority-down))
                                 (org-agenda-skip-function 'my-org-day-agenda-skip-project-if)
                                 (org-agenda-files '(,my-local-gtd-projects-dir))))
               (todo "TODO" ((org-agenda-overriding-header "Open ad-hoc tasks and high-prio project tasks")
                             (org-agenda-skip-function 'my-org-day-agenda-skip-todo-if)
                             (org-agenda-files ',my-open-gtd-files)))
               (tags "+PROJECT" ((org-agenda-overriding-header "Open projects")
                                 (org-tags-match-list-sublevels nil)
                                 (org-agenda-sorting-strategy '(priority-down))
                                 (org-agenda-skip-function 'my-org-day-agenda-skip-project-if)
                                 (org-agenda-files '(,my-open-gtd-projects-dir))))
               (todo "TODO" ((org-agenda-overriding-header "Someday")
                             (org-agenda-skip-function 'my-org-day-agenda-not-high-prio-someday-p)
                             (org-agenda-skip-files ',my-local-gtd-files))))))

Configure

(use-package org
  :custom
  (org-startup-indented t)
  (org-startup-with-inline-images t)
  (org-confirm-babel-evaluate nil)
  (org-use-sub-superscripts '{})
  (org-src-window-setup 'split-window-below)
  (org-fold-catch-invisible-edits 'show-and-error)
  (org-special-ctrl-a/e t)
  (org-hide-emphasis-markers t)
  (org-pretty-entities t)
  (org-use-speed-commands t)
  (org-attach-id-dir (concat my-local-org-dir "/attachments/"))
  (org-attach-use-inheritance nil)
  (org-startup-folded 'showall)
  (org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)
  (org-log-done 'time)
  (org-capture-templates my-gtd-capture-templates)
  (org-agenda-files `(,my-local-gtd-dir
                      ,(expand-file-name "projects" my-local-gtd-dir)
                      ,(expand-file-name "areas" my-local-gtd-dir)
                      ,my-open-gtd-dir
                      ,(expand-file-name "projects" my-open-gtd-dir)
                      ,(expand-file-name "areas" my-open-gtd-dir)))
  (org-refile-targets '((org-agenda-files :level . 2)))
  (org-priority-lowest 69)
  (org-priority-default 68)
  (org-agenda-custom-commands `(,my-org-day-agenda))
  (org-habit-graph-column 80)
  (org-habit-show-done-always-green t)
  :config
  (require 'org-attach)
  (require 'org-id)
  (require 'org-habit)
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((shell . t)))
  (add-to-list 'org-modules 'org-id)
  (add-hook 'org-mode-hook 'my-org-setup)
  (add-hook 'org-after-todo-state-change-hook 'my-org-remove-priority-when-done)
  (add-hook 'org-after-refile-insert-hook 'my-org-sort-todos-after-refile)
  :bind
  (("C-c c" . org-capture)
   ("C-c l" . org-store-link)
   ("C-c a" . org-agenda)
   ("C-c S" . my-org-sort-todos)
   ("M-g e" . my-org-end-of-subtree)
   ("C-c i" . my-gtd-capture-note)
   ("C-c I" . my-gtd-capture-todo)
   ("C-c o u" . my-org-add-update)
   ("C-c o l" . my-org-insert-timestamped-heading)
   ("C-c o D" . my-org-duplicate-subtree)
   ("C-c o w" . my-org-refile-note)
   :map org-mode-map
   ("C-c P i" . org-id-get-create)))

Org Modern

https://github.com/minad/org-modern

Setup helpers

Make checked checkboxes green

Org Modern makes checkboxes very small and it’s hard to distinguish checked from unchecked. This makes checked ones green to help with that.

(defface my-org-checked-checkbox-face
  '((t (:inherit org-done)))
  "Face for a checked Org mode checkbox.")

(defun my-org-set-checked-checkbox-face ()
  (font-lock-add-keywords
   'org-mode
   `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 1 'my-org-checked-checkbox-face prepend))
   'append))

Configure

(use-package org-modern
  :after org
  :custom
  (org-auto-align-tags nil)
  (org-tags-column 0)
  (org-agenda-tags-column 0)
  (org-modern-priority-faces '((?A :background "IndianRed" :foreground "white")
                               (?B :background "Goldenrod" :foreground "white")
                               (?C :background "DarkOliveGreen" :foreground "white")
                               (?D :background "SteelBlue" :foreground "white")
                               (?E :background "DarkOrchid" :foreground "white")))
  :custom-face
  (org-modern-tag ((t (:foreground "white" :background "#9575cd" :slant italic))))
  (org-checkbox ((t (:height 1.3))))
  :config
  (global-org-modern-mode)
  (my-org-set-checked-checkbox-face))

Auto-tangle

https://github.com/yilkalargaw/org-auto-tangle

(use-package org-auto-tangle
  :hook (org-mode . org-auto-tangle-mode))

TOC

https://github.com/snosov1/toc-org

(use-package toc-org
  :hook (org-mode . toc-org-mode))

Restclient

https://github.com/alf/ob-restclient.el

(use-package ob-restclient
  :after org)

ox-slack

https://github.com/titaniumbones/ox-slack

(use-package ox-slack
  :after org)

Org super links

https://github.com/toshism/org-super-links

(use-package org-super-links
  :straight (org-super-links :type git :host github :repo "toshism/org-super-links" :branch "develop")
  :bind (("C-c s s" . org-super-links-link)
         ("C-c s l" . org-super-links-store-link)
         ("C-c s C-l" . org-super-links-insert-link)))

GPTel

https://github.com/karthink/gptel

(use-package gptel
  :custom
  (gptel-model 'gpt-4o)
  (gptel-default-mode 'org-mode)
  :config
  (add-hook 'gptel-mode-hook 'toggle-truncate-lines)
  (require 'my-gptel)
  :bind
  (("C-c SPC" . gptel)
   :map gptel-mode-map
   ("C-c k" . gptel-abort)))

My GPTel

lisp/my-gptel.org

(use-package my-gptel
  :straight nil
  :mode ("\\.gpt\\'" . my-gptel-mode)
  :bind
  (:map gptel-mode-map
        ("C-c d h" . my-gptel-clear-buffer)
        ("C-c C-c" . my-gptel-send)))

Ledger

https://github.com/ledger/ledger-mode

(use-package ledger-mode
  :unless (my-windows-p)
  :custom
  (ledger-default-date-format "%Y-%m-%d"))

My Ledger

lisp/my-ledger.org

(use-package my-ledger
  :straight nil
  :after ledger-mode)

Vterm

https://github.com/vterm/vterm

(use-package vterm
  :unless (my-windows-p)
  :custom
  (vterm-module-cmake-args "-DUSE_SYSTEM_LIBVTERM=no")
  (vterm-shell my-fish-path)
  (vterm-max-scrollback 50000)
  (vterm-clear-scrollback-when-clearing t)
  :bind
  (("C-x v" . vterm)
   ("C-x 4 v" . vterm-other-window)))

Shell

(use-package shell
  :custom
  (shell-kill-buffer-on-exit t))

Copilot

https://github.com/zerolfx/copilot.el

(use-package copilot
  :when my-use-copilot
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :custom
  (copilot-idle-delay 0.3)
  :custom-face (copilot-overlay-face ((t (:foreground "DarkOrchid" :slant italic))))
  :config
  (add-to-list 'warning-suppress-log-types '(copilot copilot-no-mode-indent))
  :hook (prog-mode . copilot-mode))

My Copilot

lisp/my-copilot.org

(use-package my-copilot
  :straight nil
  :after copilot)

Jinx

https://github.com/minad/jinx

(use-package jinx
  :unless (my-windows-p)
  :custom (jinx-languages "en_US de_DE ru")
  :hook (emacs-startup . global-jinx-mode)
  :bind
  (("M-$" . jinx-correct)
   ("C-M-$" . jinx-languages)))

Ripgrep

https://github.com/dajva/rg.el

(use-package rg
  :unless (my-windows-p)
  :bind
  (("M-s R" . rg-project)))

Tree Sitter

(use-package tree-sitter
  :unless (my-windows-p)
  :custom
  (treesit-font-lock-level 4))

Eglot

(use-package eglot
  :unless (my-windows-p)
  :hook (scala-ts-mode . eglot-ensure)
  :config
  (add-to-list 'eglot-server-programs '((scala-ts-mode) . ("metals")))
  :bind
  (:map eglot-mode-map
        ("C-c e a" . eglot-code-actions)
        ("C-c e i" . eglot-code-action-organize-imports)
        ("C-c e f" . eglot-format-buffer)
        ("C-c e r" . eglot-rename)
        ([M-down-mouse-1] . mouse-set-point)
        ([M-mouse-1] . xref-find-definitions)
        ([M-mouse-3] . xref-go-back)))

LSP

(use-package lsp-mode
  :custom
  (lsp-keymap-prefix "<f5>")
  (lsp-pylsp-plugins-black-enabled t)
  :hook
  (scala-ts-mode . lsp)
  (python-mode . lsp)
  (python-ts-mode . lsp)
  :commands lsp
  :bind
  (:map lsp-mode-map
        ([M-down-mouse-1] . mouse-set-point)
        ([M-mouse-1] . lsp-find-definition)
        ([M-mouse-3] . xref-go-back)
        ("<f5> I" . lsp-metals-build-import)))

(use-package lsp-metals)

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

(setq lsp-completion-provider :none)

(defun corfu-lsp-setup ()
  (setq-local completion-styles '(orderless)
              completion-category-defaults nil))

(add-hook 'lsp-mode-hook #'corfu-lsp-setup)

Consult-LSP

(use-package consult-lsp
  :bind
  (:map lsp-mode-map
        ("<f5> d" . consult-lsp-diagnostics)
        ("<f5> s" . consult-lsp-file-symbols)
        ("<f5> S" . consult-lsp-symbols)))

Flycheck

(use-package flycheck
  :init
  (setq flycheck-global-modes '(not org-mode))
  :config
  (global-flycheck-mode))

Scala TS mode

https://github.com/KaranAhlawat/scala-ts-mode

(use-package scala-ts-mode
  :unless (my-windows-p)
  :interpreter "scala")

Jarchive

(use-package jarchive
  :unless (my-windows-p)
  :after eglot
  :config
  (jarchive-setup))

Kubel

https://github.com/abrochard/kubel

(use-package kubel
  :unless (my-windows-p)
  :config
  (with-eval-after-load 'vterm
    (add-to-list 'vterm-tramp-shells '("kubectl" "/bin/bash")))
  :bind
  (("C-c K" . kubel)
   :map kubel-mode-map
   ("n" . next-line)
   ("p" . previous-line)
   ("N" . kubel-set-namespace)
   ("v" . kubel-exec-vterm-pod)
   ("D" . kubel-exec-pod)
   ("P" . kubel-port-forward-pod)))

Markdown

(use-package markdown-mode
  :interpreter "markdown")

Anki editor

https://github.com/louietan/anki-editor

(define-derived-mode anki-mode org-mode "Anki")

(add-to-list 'auto-mode-alist '("\\.anki\\'" . anki-mode))

(use-package anki-editor
  :unless (my-windows-p)
  :hook (anki-mode . anki-editor-mode)
  :bind
  (:map anki-mode-map
        ("C-<return>" . anki-editor-insert-note)
        ("C-c p p" . anki-editor-push-notes)
        ("C-c p r" . anki-editor-retry-failure-notes)))

PlantUML

(use-package plantuml-mode)

Clojure mode

(use-package clojure-mode)

CIDER

(use-package cider)

Clerk

(defun clerk-show ()
  (interactive)
  (when-let
      ((filename
        (buffer-file-name)))
    (save-buffer)
    (cider-interactive-eval
     (concat "(nextjournal.clerk/show! \"" filename "\")"))))

(define-key clojure-mode-map (kbd "<M-return>") 'clerk-show)

OpenAI tools

(use-package my-openai-tools
  :straight nil)

Terraform

(use-package terraform-mode)

GraphQL

(use-package graphql-mode)

decide-mode

(use-package decide)

Embark

(use-package embark
  :bind
  (("C-." . embark-act)
   ("M-." . embark-dwim)))

Emabrk-Consult

(use-package embark-consult
  :after (embark consult))

Org-roam

https://www.orgroam.com/

(defconst my-roam-dailies-file-template
  (let ((base "%<%Y-%m-%d>.org"))
    (if my-roam-encrypt-dailies? (concat base ".gpg") base)))

(use-package org-roam
  :custom
  (org-roam-directory "~/roam")
  (org-roam-database-connector 'sqlite-builtin)
  (org-roam-db-gc-threshold most-positive-fixnum)
  :config
  (add-to-list 'display-buffer-alist
               '("\\*org-roam\\*"
                 (display-buffer-in-direction)
                 (direction . right)
                 (window-width . 0.33)
                 (window-height . fit-window-to-buffer)))
  (org-roam-db-autosync-mode)
  (require 'org-roam-dailies)
  (setq org-roam-dailies-capture-templates `(("d" "default" entry "* %?" :target
                                              (file+head ,my-roam-dailies-file-template "#+title: %<%Y-%m-%d>
"))))
  :bind
  (("C-c n f" . org-roam-node-find)
   ("C-c n i" . org-roam-node-insert)
   ("C-c n d t" . org-roam-dailies-capture-today)
   ("C-c n d y" . org-roam-dailies-capture-yesterday)
   ("C-c n d T" . org-roam-dailies-goto-today)
   ("C-c n d Y" . org-roam-dailies-goto-yesterday)
   :map org-mode-map
   ("C-c n t a" . org-roam-tag-add)
   ("C-c n t r" . org-roam-tag-remove)))

Org-roam UI

https://github.com/org-roam/org-roam-ui

(use-package org-roam-ui)

Notdeft

https://github.com/hasu/notdeft

(use-package notdeft
  :straight (notdeft :type git :host github :repo "hasu/notdeft" :files ("*.el" "xapian"))
  :custom
  (notdeft-directory "~/roam")
  (notdeft-directories '("~/roam"))
  (notdeft-xapian-program (expand-file-name "straight/build/notdeft/xapian/notdeft-xapian" user-emacs-directory))
  :config
  (notdeft-install)
  :bind
  (("C-c n n" . notdeft)))

dash

https://github.com/magnars/dash.el

(use-package dash)

emacs-pet

(use-package pet
  :config
  (add-hook 'python-base-mode-hook 'pet-mode -10)
  (require 'envrc)
  (add-hook 'change-major-mode-after-body-hook 'envrc-mode))

just

https://github.com/leon-barrett/just-mode.el

(use-package just-mode)

elfeed

https://github.com/skeeto/elfeed

(use-package elfeed
  :custom
  (elfeed-feeds my-elfeed-feeds))

aider

https://github.com/tninja/aider.el

(use-package aider
  :when my-use-aider
  :straight (:host github :repo "tninja/aider.el" :files ("*.el"))
  :config
  ;; For latest claude sonnet model
  (setq aider-args '("--model" "o3-mini"))
  (global-set-key (kbd "C-c b") 'aider-transient-menu))

easysession

https://github.com/jamescherti/easysession.el

Don’t autosave ‘main’ session

(defun my-easysession-is-not-main ()
  "Is current session some other than 'main'?"
  (not (string= "main" (easysession-get-current-session-name))))

Save only visible buffers

(defun my-easysession-visible-buffer-list ()
  "Return a list of all visible buffers in the current session.
This includes buffers visible in windows or tab-bar tabs."
  (let ((visible-buffers '()))
    (dolist (buffer (buffer-list))
      (when (or
             ;; Windows
             (get-buffer-window buffer 'visible)
             ;; Tab-bar windows
             (and (bound-and-true-p tab-bar-mode)
                  (fboundp 'tab-bar-get-buffer-tab)
                  (tab-bar-get-buffer-tab buffer t nil)))
        (push buffer visible-buffers)))
    visible-buffers))

New session setup

(defun my-empty-easysession ()
  "Set up a minimal environment when easysession creates a new session."
  (when (and (boundp 'tab-bar-mode) tab-bar-mode)
    (tab-bar-close-other-tabs)
    (tab-bar-rename-tab ""))
  (delete-other-windows)
  (scratch-buffer))

Configure

(use-package easysession
  :commands (easysession-switch-to
             easysession-save-as
             easysession-save-mode
             easysession-load-including-geometry)

  :custom
  (easysession-mode-line-misc-info t)  ; Display the session in the modeline
  (easysession-save-interval (* 5 60))  ; Save every 5 minutes
  (easysession-buffer-list-function 'my-easysession-visible-buffer-list)
  (easysession-save-mode-predicate 'my-easysession-is-not-main)
  :init
  (add-hook 'emacs-startup-hook #'easysession-load-including-geometry 102)
  (add-hook 'emacs-startup-hook #'easysession-save-mode 103)
  (add-hook 'easysession-new-session-hook #'my-empty-easysession)
  :bind
  (("<f12> <f12>" . easysession-switch-to)
   ("<f12> s" . easysession-save)
   ("<f12> k" . easysession-delete)))

Local variables

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published